diff --git a/.cursor/rules/morpheus.mdc b/.cursor/rules/morpheus.mdc new file mode 100644 index 00000000..0c920b6b --- /dev/null +++ b/.cursor/rules/morpheus.mdc @@ -0,0 +1,52 @@ +--- +description: Always-on rules for AI assistants working in this Morpheus Lumerin Node repo. Loaded automatically by Cursor. +alwaysApply: true +--- + +# Morpheus Lumerin Node — agent rules + +This repository has nuance that generic web knowledge gets wrong. **Before answering any Morpheus question or writing any Morpheus code, consult the canonical `/docs` site and the [`AGENTS.md`](../../AGENTS.md) at the repo root.** + +## Canonical sources + +- Documentation site: `/docs/` (Mintlify; preview with `mint dev` in that folder) +- API schema: [`proxy-router/docs/swagger.yaml`](../../proxy-router/docs/swagger.yaml) +- Networks and contract addresses: [`docs/get-started/networks-and-tokens.mdx`](../../docs/get-started/networks-and-tokens.mdx) +- TEE attestation reference: [`docs/providers/full/tee-reference.mdx`](../../docs/providers/full/tee-reference.mdx) and [`proxy-router/docs/tee-backend-verification.md`](../../proxy-router/docs/tee-backend-verification.md) + +## Anti-hallucination rules + +0. **Never confuse the proxy-router HTTP API (this repo) with the hosted Morpheus Inference API.** The proxy-router API is documented at `proxy-router/docs/swagger.yaml`. The hosted Morpheus Inference API at [apidocs.mor.org](https://apidocs.mor.org) (`https://api.mor.org/api/v1`) is a **separate product** for users who don't run a node — see [`docs/inference-api/overview.mdx`](../../docs/inference-api/overview.mdx). +1. **Never invent contract addresses, chain IDs, or token addresses.** Use [`docs/get-started/networks-and-tokens.mdx`](../../docs/get-started/networks-and-tokens.mdx) (BASE Mainnet `8453`, Sepolia `84532`). +2. **Never invent live values** (active model count, bid prices, latency). Link to `https://active.mor.org`. +3. **Never claim "Morpheus runs the inference."** Independent providers run inference; Morpheus is a marketplace coordinated by the Diamond contract on BASE. +4. **Disambiguate the local `tinyllama` demo from real Morpheus models.** Cite [`docs/ai/local-vs-blockchain-models.mdx`](../../docs/ai/local-vs-blockchain-models.mdx). +5. **Opening a session escrows MOR; it does not spend MOR.** Unused MOR returns on close. Cite [`docs/ai/session-states-open-close-recover.mdx`](../../docs/ai/session-states-open-close-recover.mdx). +6. **There is no `recover` RPC.** Closing the session is the recovery path. +7. **For TEE questions, separate Phase 1 (consumer → P-Node) from Phase 2 (P-Node → backend).** A v6+ consumer transparently benefits from a v7+ provider's Phase 2 with no client-side upgrade. +8. **The proxy-router `:8082` admin/API port must not be exposed publicly.** Only `:3333` is public, and only on providers. +9. **MorpheusUI mnemonic recovery only works for tier-1 (index 0) addresses.** For derived addresses, recommend importing the private key directly. + +## When unsure + +If the user's question doesn't match a documented behavior: + +1. Search `/docs` first. +2. Search `proxy-router/docs/swagger.yaml` for endpoint shape. +3. Search the codebase under `proxy-router/`. +4. **Dynamic-query the broader Morpheus docs hub** at [gitbook.mor.org](https://gitbook.mor.org). It supports `GET https://gitbook.mor.org/.md?ask=` returning a natural-language answer with sources — useful for ecosystem questions outside this repo. +5. If you still don't have a confident answer, **say so** and link to the closest matching docs page rather than guessing. + +## When writing code + +- All proxy-router HTTP requests use **HTTP Basic Auth** ([`docs/reference/api-auth.mdx`](../../docs/reference/api-auth.mdx)). +- For prompts to remote Morpheus models, include the `session_id: 0x...` header. +- For the bundled local `tinyllama` model, omit `session_id`. +- Do not hard-code contract addresses; read them from environment / config. + +## When editing documentation + +- Pages are MDX with frontmatter: `title`, `description`, `audience`, `product`, `last_verified`, and `source_url` for mirrored content. +- Update navigation in [`docs/docs.json`](../../docs/docs.json) if you add a page. +- Bump `last_verified` when content is reconfirmed against current behavior. +- Mirrored ecosystem pages must include attribution and a `source_url`. diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d621befa..5eccc152 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -41,7 +41,13 @@ on: - dev - cicd/* - paths: [".github/**", "ui-desktop/**", "ui-core/**", "proxy-router/**", "cli/**"] + paths: + - ".github/**" + - "!.github/workflows/docs.yml" + - "ui-desktop/**" + - "ui-core/**" + - "proxy-router/**" + - "cli/**" # pull_request: # types: [opened, reopened, synchronize] @@ -2651,7 +2657,7 @@ jobs: --env .env --platform tdx --persistence --upgradeability ``` - See the [TEE Quick-Start Guide](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/blob/main/docs/02.4-proxy-router-secretvm-quickstart.md) for full setup instructions. + See the [TEE Quick-Start Guide](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/blob/main/docs/providers/full/secretvm-quickstart.mdx) for full setup instructions. --- diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 00000000..565ad35f --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,165 @@ +name: Docs + +# Validate Mintlify docs on PRs and pushes. Deploy to S3 + CloudFront (OIDC) on +# test/main after validation passes. Does not trigger the main CI-CD pipeline. + +on: + pull_request: + paths: + - "docs/**" + - "proxy-router/docs/swagger.yaml" + - ".github/workflows/docs.yml" + push: + branches: + - main + - dev + - test + paths: + - "docs/**" + - "proxy-router/docs/swagger.yaml" + - ".github/workflows/docs.yml" + workflow_dispatch: + +concurrency: + group: docs-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: read + pull-requests: write + +jobs: + mintlify-validate: + name: Mintlify validate + broken-link check + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: "20" + cache: npm + cache-dependency-path: docs/package-lock.json + + - name: Install docs dependencies + working-directory: docs + run: npm ci + + - name: Validate Mintlify config + working-directory: docs + run: | + npx mint --version + npx mint broken-links || echo "::warning::mint broken-links reported issues" + + - name: List MDX files + run: find docs -name "*.mdx" | wc -l + + openapi-lint: + name: OpenAPI spec lint + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: "20" + + - name: Install Redocly CLI + run: npm install -g @redocly/cli@latest + + - name: Lint swagger.yaml + run: | + redocly lint proxy-router/docs/swagger.yaml || \ + echo "::warning::OpenAPI spec has lint issues (non-blocking)" + + last-verified-staleness: + name: Check last_verified staleness + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Find pages with last_verified older than the latest release tag + run: | + set -euo pipefail + LATEST_TAG=$(git tag --list 'v*' --sort=-v:refname | grep -v -- '-test' | head -n 1 || true) + LATEST_TAG=${LATEST_TAG:-v0.0.0} + echo "Latest release tag: $LATEST_TAG" + + STALE_FILES=() + while IFS= read -r f; do + VERIFIED=$(awk '/^---$/{n++; next} n==1 && /^last_verified:/ {print}' "$f" \ + | sed -E 's/^last_verified:[[:space:]]*"?([^"]*)"?$/\1/' || true) + if [ -z "$VERIFIED" ]; then + continue + fi + if [ "$VERIFIED" \< "$LATEST_TAG" ]; then + STALE_FILES+=("$f (last_verified=$VERIFIED < $LATEST_TAG)") + fi + done < <(find docs -name "*.mdx") + + if [ "${#STALE_FILES[@]}" -gt 0 ]; then + echo "::warning::Pages with last_verified older than $LATEST_TAG:" + for s in "${STALE_FILES[@]}"; do + echo "::warning:: $s" + done + else + echo "All pages report last_verified >= $LATEST_TAG." + fi + + deploy: + name: Build and deploy docs + needs: + - mintlify-validate + - openapi-lint + - last-verified-staleness + if: github.event_name == 'push' && (github.ref_name == 'test' || github.ref_name == 'main') + runs-on: ubuntu-latest + environment: ${{ github.ref_name }} + permissions: + contents: read + id-token: write + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: "20" + cache: npm + cache-dependency-path: docs/package-lock.json + + - name: Install docs dependencies + working-directory: docs + run: npm ci + + - name: Build static site + working-directory: docs + env: + SITE_URL: ${{ vars.NODEDOCS_SITE_URL }} + run: npm run build:site -- ../.site + + - name: Configure AWS credentials (OIDC) + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: ${{ vars.NODEDOCS_IAM_ROLE_ARN }} + aws-region: us-east-2 + + - name: Sync to S3 + run: | + aws s3 sync .site/ "s3://${{ vars.NODEDOCS_S3_BUCKET }}/" \ + --delete \ + --exclude "serve.js" \ + --exclude "Start Docs.command" \ + --exclude "Start Docs.bat" + + - name: Invalidate CloudFront + run: | + aws cloudfront create-invalidation \ + --distribution-id "${{ vars.NODEDOCS_CLOUDFRONT_DISTRIBUTION_ID }}" \ + --paths "/*" diff --git a/.gitignore b/.gitignore index 59c3ef85..e8c6fe15 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,5 @@ ***/.env ***/.$*drawio.bkp ***/.$*drawio.dtmp -*.internal.* \ No newline at end of file +*.internal.* +.site/ \ No newline at end of file diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..a3f02824 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,110 @@ +# AGENTS.md — guidance for AI agents and coding assistants + +If you are an LLM (Claude, GPT, Gemini, Copilot, Cursor, etc.) reading this repository to answer questions about Morpheus, **read this file first**, then read the linked pages under `/docs`. The Morpheus Lumerin Node has nuance that generic web knowledge gets wrong; this file (and the `/docs/ai/` directory) exists to keep you out of the most common hallucination traps. + +## Canonical knowledge base + +The single source of truth for documentation is **`/docs/`**, a Mintlify site. All linked pages below resolve from the same site. Old `00-overview.md` / `02-*.md` style links redirect via [`docs/docs.json`](docs/docs.json). + +### Read these AI-knowledge pages before answering user questions + +- [`docs/ai/myths.mdx`](docs/ai/myths.mdx) — corrections of the most common wrong assumptions. +- [`docs/ai/where-is-my-mor.mdx`](docs/ai/where-is-my-mor.mdx) — diagnostic for "missing" MOR. +- [`docs/ai/session-states-open-close-recover.mdx`](docs/ai/session-states-open-close-recover.mdx) — deterministic state machine for sessions. +- [`docs/ai/why-locked-in-contract.mdx`](docs/ai/why-locked-in-contract.mdx) — why MOR appears locked. +- [`docs/ai/local-vs-blockchain-models.mdx`](docs/ai/local-vs-blockchain-models.mdx) — distinguish the bundled `tinyllama` from real Morpheus models. +- [`docs/ai/llm-prompt-cheatsheet.mdx`](docs/ai/llm-prompt-cheatsheet.mdx) — concise rules for answering Morpheus questions. + +### Concept references (cite from these) + +- [`docs/concepts/architecture.mdx`](docs/concepts/architecture.mdx) +- [`docs/concepts/sessions-stake-close-recover.mdx`](docs/concepts/sessions-stake-close-recover.mdx) +- [`docs/concepts/local-vs-onchain-models.mdx`](docs/concepts/local-vs-onchain-models.mdx) +- [`docs/concepts/tee-overview.mdx`](docs/concepts/tee-overview.mdx) +- [`docs/concepts/tokens-and-fees.mdx`](docs/concepts/tokens-and-fees.mdx) +- [`docs/get-started/networks-and-tokens.mdx`](docs/get-started/networks-and-tokens.mdx) — canonical contract addresses + chain IDs. +- [`docs/reference/glossary.mdx`](docs/reference/glossary.mdx) + +### How-tos by role + +| Role | Start here | +|------|-----------| +| API user (no node, hosted OpenAI-compatible) | [`docs/inference-api/overview.mdx`](docs/inference-api/overview.mdx) | +| Consumer | [`docs/consumers/quickstart.mdx`](docs/consumers/quickstart.mdx) | +| Prosumer (agents) | [`docs/prosumers/overview.mdx`](docs/prosumers/overview.mdx) | +| Provider — Full P-Node | [`docs/providers/full/quickstart.mdx`](docs/providers/full/quickstart.mdx) | +| Provider — TEE / SecretVM | [`docs/providers/full/secretvm-quickstart.mdx`](docs/providers/full/secretvm-quickstart.mdx) | +| Provider — Resale | [`docs/providers/resale/overview.mdx`](docs/providers/resale/overview.mdx) | +| Developer (proxy-router API) | [`docs/reference/api-overview.mdx`](docs/reference/api-overview.mdx) | + +### API and config schemas + +- API: [`proxy-router/docs/swagger.yaml`](proxy-router/docs/swagger.yaml). The Mintlify site auto-generates the API Reference tab from this file. +- Models config schema: [`proxy-router/internal/config/models-config-schema.json`](proxy-router/internal/config/models-config-schema.json). +- Rating config schema: [`proxy-router/internal/rating/rating-config-schema.json`](proxy-router/internal/rating/rating-config-schema.json). + +## Hard rules — never break these + +0. **Never confuse the proxy-router HTTP API with the hosted Morpheus Inference API.** The proxy-router API is documented locally at `http://localhost:8082/swagger/index.html` and in [`proxy-router/docs/swagger.yaml`](proxy-router/docs/swagger.yaml). The hosted Morpheus Inference API is a **different product** at [apidocs.mor.org](https://apidocs.mor.org) (base URL `https://api.mor.org/api/v1`) — described in [`docs/inference-api/overview.mdx`](docs/inference-api/overview.mdx). +1. **Never invent contract addresses, chain IDs, or token addresses.** Use only what's in [`docs/get-started/networks-and-tokens.mdx`](docs/get-started/networks-and-tokens.mdx) or release notes. +2. **Never invent live values** (active model count, current bid prices, network status). Link out to `https://active.mor.org` instead. +3. **Never claim Morpheus runs the inference itself.** Independent providers do; Morpheus is a marketplace coordinated by the Diamond contract on BASE. +4. **Always disambiguate the local `tinyllama` demo from real Morpheus models.** They are not comparable. +5. **Never describe "open a session" as "spending MOR."** The MOR is escrowed; unused stake returns on close. +6. **Never tell users to call a `recover` RPC.** It does not exist. Closing the session is the recovery path. +7. **For TEE questions, distinguish Phase 1 (consumer → P-Node) from Phase 2 (P-Node → backend).** Phase 2 runs *inside* the v7+ provider's P-Node — a v6+ consumer benefits transparently with no client-side upgrade. +8. **The proxy-router's `:8082` admin port should not be public** — only `:3333` (TCP) is public, and only on provider nodes. +9. **MorpheusUI mnemonic-recover only works for tier-1 (index 0) addresses.** Don't suggest it for derived addresses; suggest private-key import instead. +10. **When uncertain, cite a docs page or say so.** Don't guess. + +## Common-question quick lookup + +| User says | Cite | +|-----------|------| +| "How do I use Morpheus without running a node?" | [`docs/inference-api/overview.mdx`](docs/inference-api/overview.mdx) (the hosted Inference API) or [app.mor.org](https://app.mor.org) | +| "Where is my MOR?" | [`docs/ai/where-is-my-mor.mdx`](docs/ai/where-is-my-mor.mdx) | +| "Why is MOR locked in the contract?" | [`docs/ai/why-locked-in-contract.mdx`](docs/ai/why-locked-in-contract.mdx) | +| "What does open/close/recover mean?" | [`docs/ai/session-states-open-close-recover.mdx`](docs/ai/session-states-open-close-recover.mdx) | +| "Is the local model real Morpheus?" | [`docs/ai/local-vs-blockchain-models.mdx`](docs/ai/local-vs-blockchain-models.mdx) | +| "How do I install as a consumer?" | [`docs/consumers/quickstart.mdx`](docs/consumers/quickstart.mdx) | +| "How do I become a provider?" | [`docs/get-started/quickstart-provider.mdx`](docs/get-started/quickstart-provider.mdx) | +| "How do I run TEE?" | [`docs/providers/full/secretvm-quickstart.mdx`](docs/providers/full/secretvm-quickstart.mdx) | +| "What contract address?" | [`docs/get-started/networks-and-tokens.mdx`](docs/get-started/networks-and-tokens.mdx) | +| "Where can I see live status?" | https://active.mor.org | + +## When unsure / out-of-corpus questions + +If the user's question doesn't match anything on this site or in the repo: + +1. Search [`/docs`](docs/) first. +2. Search [`proxy-router/docs/swagger.yaml`](proxy-router/docs/swagger.yaml) for endpoint shape. +3. Search the codebase under `proxy-router/`. +4. **Dynamic query the broader Morpheus docs hub.** [gitbook.mor.org](https://gitbook.mor.org) supports an `?ask=` HTTP query that returns a natural-language answer plus sources. Example: + ``` + GET https://gitbook.mor.org/morpheus-inference-marketplace.md?ask= + ``` + Cite the returned URLs back to the user so they can verify. +5. If you still don't have a confident answer, **say so** and link to the closest matching page rather than guessing. + +## When asked to write code that talks to the proxy-router + +- Use the API documented in `proxy-router/docs/swagger.yaml`. +- Auth is **HTTP Basic Auth** — see [`docs/reference/api-auth.mdx`](docs/reference/api-auth.mdx). +- Set the `session_id` header on `/v1/*` calls when targeting a remote (Morpheus) model. Omit it for the local model. +- Don't hard-code contract addresses — read them from the proxy-router's environment. + +## When asked to modify the docs + +- The site lives under `/docs` and is built with [Mintlify](https://mintlify.com). +- Pages are MDX with frontmatter (`title`, `description`, `audience`, `product`, `last_verified`, optional `source_url` for mirrored content). +- Navigation is in [`docs/docs.json`](docs/docs.json). Add new pages there. +- Run `mint dev` from `/docs` to preview locally. + +## Repository sub-projects + +- `proxy-router/` — Go service: the consumer/provider router. Hosts the HTTP API. +- `MorpheusUI/` — Electron consumer GUI. +- `cli/` — Go CLI client. +- `smart-contracts/` — Solidity contracts (Diamond marketplace). +- `agents/` — agent reference implementations. +- `docs/` — Mintlify documentation site (this is the doc system). diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 00000000..892c809c --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1,5 @@ +.mintlify/ +node_modules/ +.DS_Store +*.log +.site/ diff --git a/docs/00-overview.md b/docs/00-overview.md deleted file mode 100644 index 1d30fa64..00000000 --- a/docs/00-overview.md +++ /dev/null @@ -1,79 +0,0 @@ -# Overview of the Morpheus-Lumerin Environment - -![Architecture-Overview](images/overview.png) - -This document is intended to provide a high level overview of the major architectural components between model compute-providers and consumers in the Morpheus-Lumerin environment. - -The ultimate goal is to show how configuration of the compute-provider environment and the consumer nodes can enable prompts and inference from the consumer to the hosted models by the provider. The key enablers being the BASE blockchain, Morpheus token for staking and bidding (transactions to pay for use) and the Lumerin proxy-router to anonymously route traffic based on smart contract governance. - -In other words, referring to the overview model...how do we get to conversation **6** where prompts and inference are happening? - -Numbers below reference the circled elements in the diagram above. - -## 0. Existing Foundation Elements -- [Readme](../readme.md) - for more details -- BASE Layer 2 blockchain -- Morpheus Token (MOR) for staking and bidding -- Lumerin Smart Contract for governance and routing - -## 1. Provider AI Model -- [01-model-setup.md](01-model-setup.md) - for more details -- Existing, Hosted AI model that is available for inference -- In the real world, this is assumed to be a high-horsepower server or server farm tuned for large language models and available via standard OpenAI API interface on a privately accessed endpoint (IP address:port or DNS name:port) eg: `http://mycoolaimodel.serverfarm.io:8080` -- In the packaged software releases, llama.cpp (llama-server) example can be automatically downloaded (`./mor-launch local`) to run on the same machine as the other components to show how the components work together. It is not a real-world model and is not tuned for performance. - -## 2. Provider Proxy-Router -- [02-provider-setup.md](02-provider-setup.md) - for more details -- [02.1-proxy-router-docker.md](02.1-proxy-router-docker.md) - for more details on running the proxy-router in a docker container -- The proxy-router is the core "router" that talks to and listens to the blockchain, routes prompts and inference between the providers hosted models via bids and the consumers that purchase and use the model -- In a real-world scenario, this proxy-router would be a separate, small server or even docker container that is not part of the AI Model Server Instance (it can be, but it's nice to separate the architecture either for anonymity or performance) -- Installation on the provider side is as simple as setting up the environment variables and running the proxy-router software. - - There is a sample `.env.example` file located within the ./proxy-router folder that shoudld be copied to `.env` and edited with the appropriate values. - - Please see [proxy-router .ENV Variables](proxy-router.all.env) for more information on the key values needed in the .env file -- The `models-config.json` file is particularly important as it directs the proxy-router to the provider's model(s) and the endpoint(s) for the model(s) - - This file should be copied from the `./proxy-router/models-config.example.json` to `./proxy-router/models-config.json` and edited with the appropriate values - - Please see [proxy-router models-config.json](proxy-router.models-config.json.md) for more information on the key values needed in the models-config.json file -- The proxy-router needs to be on both the provider and consumer environment and have access to a BASE Ethereum node (default) public ethernet nodes or via web sockets (WSS) for listening to and posting elements on the blockchain - -## 2.5 API Authentication -- As of main release version 2.0.0 (and starting with dev & test 1.6.1) and greater, API access will require authentication as well as network access to function -- The reason for this change is twofold: - 1. To prevent unauthorized access to the API and the wallet in case of network or firewall mis-configuration - 1. To enable interaction with AI Agents - agents access from the local machine should have "goverened" access to the API -- For details in setting up the API authentication, please see [02.5 API Auth](02.5-api-auth.md) -- Key changes and features to note: - * There will be a `.cookie` file created in the proxy-router folder that will contain the username and password for the API access - * The proxy-router will require the .cookie file to be present and the username and password to be correct in order to start - * There is a `proxy.conf` file that will contain the details of username and permissions for the proxy-router API - -## 3. Provider - setup Provider, Model and Bid on the blockchain -- [03-provider-offer.md](03-provider-offer.md) - for more details -- Once the proxy-router is setup, and the provider's wallet has the proper amount of ETH and MOR, use the Swagger API Interface (http://yourlocalproxy:8082/swagger/index.html as example) to do the following: - 1. Authorize the diamond contract to spend on your wallet's behalf - 1. Register your provider (the proxy-router) on the blockchain (http://mycoolproxy.serverfarm.io:3333) - 1. Register your model on the blockchain - 1. Create a bid for your model on the blockchain - -## 4. Consumer Node Setup -- [04-consumer-setup.md](04-consumer-setup.md) - for more details -- [04a-consumer-setup-source.md](04a-consumer-setup-source.md) - for more details on setting up from gtihub source -- The consumer node is the "client" that will be purchasing bids from the blockchain, sending prompts via the proxy-router and receiving inference back from the provider's model' -- The components are very similar to the Provider side of things with the exception that the consumer node will typically not be hosting a model, but will be sending prompts to the proxy-router and receiving inference back -- In this case, the easiest way to install is to use the packaged releases for your platform on Github and follow the instructions in the README.md file -- These packages include 3 different pieces of software - - llama.cpp (llama-server) - a simple example model that can be automatically downloaded (`./mor-launch local`) and run on the same machine as the proxy-router and MorpheusUI to show how the components work together and run local (free) inference - - proxy-router - the same software as the provider side, but with different environment variables and a different role - - MorpheusUI - Electron GUI that enables the user to interact with the models (via the API) to browse offered bids, purchase and send prompts -- The consumer node will need to have the proxy-router running and the MorpheusUI running to interact with the models and bids on the blockchain - -## 5. Purchase Bid -- [05-bid-purchase.md](05-bid-purchase.md) - for more details -- Once the MorpheusUI is up and running, the consumer can browse the available bids on the blockchain -- Select a bid and stake the intended MOR amount (minimum should be shown) - -## 6. Prompt & Inference -- [06-model-interaction.md](06-model-interaction.md) - for more details -- Once the bid is purchased, the consumer can send prompts to the proxy-router via the MorpheusUI - -## Proxy-Router and Possible LLM Server Configurations - Reference Architecture -![Reference Architecture](images/system-architecture.png) \ No newline at end of file diff --git a/docs/01-model-setup.md b/docs/01-model-setup.md deleted file mode 100644 index 794e067d..00000000 --- a/docs/01-model-setup.md +++ /dev/null @@ -1,5 +0,0 @@ -## TODO - -- The intent of this document is to outline how to run llama.cpp on your local machine and could include details on AWS / EC2 Build recommendations for compute-providers -- The end state should be presentation of a proxy-router accessible private endpoint that the proxy-router can talk to to serve its models ------------- \ No newline at end of file diff --git a/docs/02-provider-setup.md b/docs/02-provider-setup.md deleted file mode 100644 index e9e625d3..00000000 --- a/docs/02-provider-setup.md +++ /dev/null @@ -1,69 +0,0 @@ - -# Provider Hosting (Local LLM to offer, Proxy-Router running as background/service): - -## Assumptions: -* Your AI model has been configured, started and made available to the proxy-router server via a private endpoint (IP:PORT or DNS:PORT) eg: `http://mycoolaimodel.domain.com:8080` - * Optional - * You can use the provided `llama.cpp` and `tinyllama` model to test locally - * If your local model is listening on a different port locally, you will need to modify the `models-config.json` file to match the correct port -* You have an existing funded wallet with MOR and ETH and also have the `private key` for the wallet (this will be needed for the .env file configuration) -* You have created an Alchemy or Infura free account and have a private API key for BASE (wss://base-mainnet.g.alchemy.com/v2/) -* Your proxy-router must have a **publicly accessible endpoint** for the provider (ip:port or fqdn:port no protocol) eg: `mycoolmornode.domain.com:3333` - this will be used when creating the provider on the blockchain - -## Installation & Configuration Steps: -1. Obtain the software: - 1. Package: Download latest release for your operating system: https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/releases - * Mainnet releases will be prefixed with `main-*` - * Testnet releases will be prefixed with `test-*` - 2. Source Code: - * Clone the repository: `git clone -b branch https://github.com/MorpheusAIs/Morpheus-Lumerin-Node.git` - * Mainnet Branch = `main` - * Testnet Branch = `test` - * Development Branch = `dev`(not recommended unless directed by the development team) - -1. Extract the zip to a local folder (examples) - * Windows: `(%USERPROFILE%)/Downloads/morpheus)` - * Linux & MacOS: `~/Downloads/morpheus` - * On MacOS you may need to execute `xattr -c proxy-router` in a command window to remove the quarantine flag on MacOS - -1. Environment configuration - * In most cases, the default .env file will work for the proxy-router...In some cases you will want to modify the .env file with advanced capability (log entries, private keys, private endpoints, etc) - * Please see [proxy-router.all.env](proxy-router.all.env) for more information on the key values available in the .env file - 1. Choose OS environment you are working with: - * Linux/Mac: `env.example` or `env.example.win` for Windows - * Change the name of the desired file to `.env` - * Edit values within the file (Wallet_Private_Key, for example) as desired - 2. Choose the **blockchain** you'd like to work on...**BASE MAINNET is the default** - * To operate on the BASE Sepolia TESTNET, - * Edit the .env file and - * Uncomment the `TESTNET VALUES` and comment the `MAINNET VALUES` lines & save the file - -1. **(OPTIONAL) - External Provider or Pass through** - * In some cases you will want to leverage external or existing AI Providers in the network via their own, private API - * Dependencies: - * `model-config.json` file in the proxy-router directory - * proxy-router .env file for proxy-router must also be edited to adjust `MODELS_CONFIG_PATH=/models-config.json` - * Once your provider is up and running, deploy a new model and model bid via the API interface (you will need the `model_ID` for the configuration) - * Edit the model-config.json to the following json format - * The JSON ID will be the ModelID that you created above, modelName, apiTYpe, apiURL and apiKey are from the external provider and specific to their offered models - * Full explanation of models-config.json can be found here [models-config.json.md](models-config.json.md) - * Once the model-config.json file is updated, the morpheus node will need to be restarted to pick up the new configuration (not all models (eg: image generation can be utilized via the MorpheusUI, but API integration is possible) - -1. **(OPTIONAL) - Weights and Preferred Providers** - * In some cases you will want to adjust the weights of the providers or set a preferred provider for the models you'd like to use - * Edit the `rating-config.json` file located in the proxy-router directory to adjust the weights and preferred providers for the models you'd like to use - * Weights must add up to 1 - * Full explanation of rating-config.json can be found here [rating-config.json.md](rating-config.json.md) - * Add preferred providerIDs to the `providerAllowlist` array for the providers you'd like to use - * **If this array is left blank**, all providers are available - -## Start the Proxy Router -1. On your server, launch the proxy-router with the modified .env file shown above - * Windows: Double click the `proxy-router.exe` (You will need to tell Windows Defender this is ok to run) - * Linux & MacOS: Open a terminal and navigate to the folder and run `./proxy-router`from the morpheus/proxy-router folder -1. This will start the proxy-router and begin monitoring the blockchain for events - -## Validating Steps: -1. Once the proxy-router is running, you can navigate to the Swagger API Interface (http://localhost:8082/swagger/index.html as example) to validate that the proxy-router is running and listening for blockchain events -1. You can also check the logs in the `./data` directory for any errors or issues that may have occurred during startup -1. Once validated, you can move on and create your provider, model and bid on the blockchain [03-provider-offer.md](03-provider-offer.md) diff --git a/docs/02.1-proxy-router-docker.md b/docs/02.1-proxy-router-docker.md deleted file mode 100644 index a9d7e617..00000000 --- a/docs/02.1-proxy-router-docker.md +++ /dev/null @@ -1,155 +0,0 @@ - -# Proxy-Router Docker Setup: - -**This document describes setting up the proxy-router component of the Morpheus AI Network in a Docker container ONLY and accessing it via the Swagger API Interface...no GUI or Wallet components are included in this setup** - -## Overview: -* The Proxy-Router is a critical component of the Morpheus AI Network. It is responsible for monitoring the blockchain for events and managing the AI models and providers that are available to the network. -* The Proxy-Router is a standalone application that can be run on any server that has access to the blockchain and the AI models. -* This document walks through using Docker to build and run the proxy-router image on your server. - -## Pre-Requisites: -* Your AI model has been configured, started and made available to the proxy-router server via a private endpoint (IP:PORT or DNS:PORT) eg: `http://mycoolaimodel.domain.com:8080` -* You have an existing funded wallet with MOR and ETH and also have the `private key` for the wallet (this will be needed for the .env file configuration) -* Your proxy-router must have a **publicly accessible endpoint** for the provider (ip:port or fqdn:port no protocol) eg: `mycoolmornode.domain.com:3333` - this will be used when creating the provider on the blockchain - -## Published Docker Image: -* We have added a published Docker image to the GitHub Container Registry (ghcr.io) for the proxy-router component -* The image is built from the main branch of the repository and is updated with each new release -* The image is available at: [Morpheus Node Package](https://github.com/orgs/MorpheusAIs/packages?repo_name=Morpheus-Lumerin-Node) source for the different builds - -### Docker Pre-Requisites -* Docker is installed and current on your server -* Volume mapping for the data directory is required for the proxy-router to persist data across container restarts -* Key configuration files are located in mounted volumes on the host server: - * proxy-router.env - env variables configured per [proxy-router.all.env](proxy-router.all.env) - * .cookie - this is created initially when proxy-router starts up - * proxy.conf - controls agent/user access to the api - * models-config.json - model configuration file - * rating-config.json - rating configuration file -* Note the use of `-v` for external volume (should be avaialbe on the host) and `-e` for environment variables -* Ports can be changed for the PROXY_ADDRESS and WEB_ADDRESS as needed ... make sure that the `-p` ports are mapped correctly to the container ports - -### Docker Run with .env file -* The .env file contains all the environment variables needed to run the proxy-router -* Minimal config of the .env file that is required to run the proxy-router and includes the file paths for the key configuration files -```bash -# Minimal .env file contents with external volume references -AUTH_CONFIG_FILE_PATH=/app/data/proxy.conf -COOKIE_FILE_PATH=/app/data/.cookie -RATING_CONFIG_PATH=/app/data/rating-config.json -PROXY_STORAGE_PATH=/app/data/data -MODELS_CONFIG_PATH=/app/data/models-config.json -ETH_NODE_CHAIN_ID= -BLOCKSCOUT_API_URL= -DIAMOND_CONTRACT_ADDRESS= -MOR_TOKEN_ADDRESS= -WALLET_PRIVATE_KEY= -PROXY_ADDRESS=0.0.0.0:3333 -WEB_ADDRESS=0.0.0.0:8082 -WEB_PUBLIC_URL=http://localhost:8082 -``` -* Once the .env file has been created, execute the following command to run the proxy-router Docker container -* Adjust the image tag to the version you want to run -```bash -# Minimal Docker Run Command using a .env file -docker run -d \ - --env-file proxy-router.env \ - -v /path/to/local/data:/app/data \ - -p 3333:3333 \ - -p 8082:8082 \ - ghcr.io/morpheusais/morpheus-lumerin-node:latest -``` - -### Minimum Docker Run Command (command line variables): -```bash -# Minimal Docker Run Command and mandatory variables (no .env file necessary) -docker run -d \ - -e AUTH_CONFIG_FILE_PATH=/app/data/proxy.conf \ - -e COOKIE_FILE_PATH=/app/data/.cookie \ - -e RATING_CONFIG_PATH=/app/data/rating-config.json \ - -e PROXY_STORAGE_PATH=/app/data/data \ - -e MODELS_CONFIG_PATH=/app/data/models-config.json \ - -e ETH_NODE_CHAIN_ID= \ - -e BLOCKSCOUT_API_URL= \ - -e DIAMOND_CONTRACT_ADDRESS= \ - -e MOR_TOKEN_ADDRESS= \ - -e WALLET_PRIVATE_KEY= \ - -e PROXY_ADDRESS=0.0.0.0:3333 \ - -e WEB_ADDRESS=0.0.0.0:8082 \ - -e WEB_PUBLIC_URL=http://localhost:8082 \ - -v /path/to/local/data:/app/data \ - -p 3333:3333 \ - -p 8082:8082 \ - ghcr.io/morpheusais/morpheus-lumerin-node:latest - ``` - -## Manual Docker Build & Run: -* Optionally, you can build and run your own Docker image using the provided Dockerfile and docker_build.sh script -* This is useful if you want to customize the image or if you want to build the image on a server that does not have access to the internet - -### Manual Build and Run Pre-Requisites -* Docker and Git are installed and current on your server -* The three key configuration files are located in the same directory as the proxy-router code: - * .env - * models-config.json - * rating-config.json - -### Installation & Configuration Steps: -1. Clone the source code from the repository: - * `git clone -b main https://github.com/MorpheusAIs/Morpheus-Lumerin-Node.git` -1. Change to the proxy-router directory: - * `cd Morpheus-Lumerin-Node\proxy-router` -1. Configure the 3 key files for your environment: - 1. Environment file configuration - 1. Copy the example file to .env: - * Linux/Mac: `cp .env.example .env` - * Windows: `copy .env.example.win .env` - 1. Edit values within the .env as desired - * Add your private key to`WALLET_PRIVATE_KEY=` - * Modify the following values to ensure that those files remain "outside of the running container" for persistence and are mounted by the docker-compose.yml file's `volume` directive - * `AUTH_CONFIG_FILE_PATH=/app/data/proxy.conf` - * `COOKIE_FILE_PATH=/app/data/.cookie` - * `MODELS_CONFIG_PATH=/app/data/models-config.json` - * `RATING_CONFIG_PATH=/app/data/rating-config.json` - * `PROXY_STORAGE_PATH=/app/data/` - 1. Choose the **blockchain** you'd like to work on...**BASE MAINNET is the default** - * To operate on the BASE Sepolia TESTNET, - * Uncomment the `TESTNET VALUES` and comment the `MAINNET VALUES` lines & save the file - 1. Models Configuration file - 1. Copy the example file to models-config.json: - * Linux/Mac: `cp models-config.json.example models-config.json` - * Windows: `copy models-config.json.example models-config.json` - 1. Edit the models-config.json file to include the models you'd like to use. - 1. Details here: [models-config.json.md](models-config.json.md) - 1. Once your provider is up and running, deploy a new model and model bid via the API interface (you will need to update the `modelId` for the configuration) - 1. Rating Configuration file - 1. Copy the example file to rating-config.json: - * Linux/Mac: `cp rating-config.json.example rating-config.json` - * Windows: `copy rating-config.json.example rating-config.json` - 1. Edit the rating-config.json file to include the weights and preferred providers you'd like to use. - 1. Details here: [rating-config.json.md](rating-config.json.md) - -### Build the proxy-router Docker Image: -1. Build the Docker image using the provided `docker_build.sh` script - * `./docker_build.sh --build` - * This script pulls the current Git tag and version, builds the docker image with all the port and defaults defined in the docker-compose.yml file - -### Running the proxy-router Docker Container: -1. Run the Docker container using the provided `docker_build.sh` script - * `./docker_build.sh --run` - * This script runs the docker container with the port and volume mappings defined in the docker-compose.yml file - * The proxy-router will start and begin listening for blockchain events - -### Validating Steps: -1. Once the proxy-router is running, you can navigate to the Swagger API Interface (http://localhost:8082/swagger/index.html as example) to validate that the proxy-router is running and listening for blockchain events -1. Once validated, you can move on and create your provider, model and bid on the blockchain [03-provider-offer.md](03-provider-offer.md) - -### NOTES: -* We have created docker-compose.yml, Dockerfile and docker_build.sh scripts to ease configuration and deployment of the proxy-router in a containerized environment -* Use these files as guides for applying to your system needs and configurations, private key, eth_node, ports, endpoints, volumes, .env, models-config.json and rating-config.json will need to be adjusted to your specific needs -* In most cases, the default .env file will work for the proxy-router...In some cases you will want to modify the .env file with advanced capability (log entries, private keys, private endpoints, etc) -* Please see the following for more information on these key config files: - * [proxy-router.all.env](proxy-router.all.env) - * [models-config.json.md](models-config.json.md) - * [rating-config.json.md](rating-config.json.md) diff --git a/docs/02.2-proxy-router-akash.md b/docs/02.2-proxy-router-akash.md deleted file mode 100644 index 8b21bef1..00000000 --- a/docs/02.2-proxy-router-akash.md +++ /dev/null @@ -1,59 +0,0 @@ -# Deploying Morpheus Proxy-Router on Akash - -This guide covers deploying the proxy-router component of the Morpheus AI Network on Akash Network. The deployment provides API access via Swagger interface without GUI or wallet components. - -## Prerequisites - -* Running AI model accessible via private endpoint (e.g., `http://model.domain.com:8080`) -* Funded wallet with MOR and ETH tokens -* Wallet private key for blockchain interactions -* Akash account with deployment experience -* Note: The final endpoint URL will be available after provider selection and deployment - -## Configuration - -The proxy-router uses environment variables for configuration instead of volume mounts for improved reliability on Akash: - -* `COOKIE_CONTENT`: API authentication (format: `username:password`) -* `MODELS_CONFIG_CONTENT`: JSON configuration for model endpoints -* `WALLET_PRIVATE_KEY`: For blockchain interactions -* Network-specific variables (chain ID, contract addresses, etc.) - -## Deployment Steps - -1. **Prepare SDL Template** - * Download and customize [Akash SDL Template](./02.2-proxy-router-akash.yml) - * Minimum version: `v2.3.0` - * Configure: - - Wallet private key - - API credentials - - Model configurations - * Save securely (contains sensitive data) - -2. **Deploy Container** - * Use Akash Dashboard: `DEPLOY` → `Custom Container` - * Upload customized SDL - * Select provider and deploy - * Verify deployment status and logs - -3. **Configure Endpoints** - * Update `WEB_PUBLIC_URL` with provider URL and port - * Note both API port (8082) and proxy-router port (3333) - * Format: `http://provider.domain:port` - -4. **Register Provider** - * Access Swagger UI: `http://provider.domain:port/swagger/index.html` - * Authenticate using configured credentials - * Update provider endpoint via `POST /blockchain/providers`: - ```json - { - "endpoint": "provider.domain:proxy_port", - "stake": "123000000000" - } - ``` - * Verify registration via `GET /blockchain/providers` - -## Example Logs - -![akash_good_start](./images/akash_good_start.png) - diff --git a/docs/02.3-proxy-router-tee.md b/docs/02.3-proxy-router-tee.md deleted file mode 100644 index becec0c5..00000000 --- a/docs/02.3-proxy-router-tee.md +++ /dev/null @@ -1,477 +0,0 @@ -# Proxy-Router TEE (Trusted Execution Environment) Setup & Verification - -This document covers two perspectives: -1. **Provider**: How to deploy a TEE-hardened P-Node on a Confidential VM -2. **Consumer**: How to verify that a provider's image is genuine and untampered - ---- - -## What is the TEE Image? - -The `-tee` Docker image (`ghcr.io/morpheusais/morpheus-lumerin-node-tee`) is a hardened version of the standard proxy-router image with all non-secret configuration **baked in at build time**. This means: - -* Blockchain config (contract addresses, chain ID, blockscout URL) is frozen at build time and cannot be changed at runtime -* Chat context storage is disabled (`PROXY_STORE_CHAT_CONTEXT=false`) -* Logging is set to production mode (JSON, no color, minimal verbosity) -* Environment is locked to `production` - -**Two network variants** are produced by CI/CD: - -| Branch | Image tag | Network | Chain ID | -|--------|-----------|---------|----------| -| `main` | `...-tee:vX.Y.Z` / `...-tee:latest` | BASE Mainnet | 8453 | -| `test` | `...-tee:vX.Y.Z-test` / `...-tee:latest-test` | BASE Sepolia (testnet) | 84532 | - -Both variants share identical hardened settings (logging, timeouts, proxy config). The only difference is which blockchain network's contract addresses and chain ID are baked in. The attestation manifest's `baked_env.network` field identifies which variant an image is ("mainnet" or "testnet"). - -Only **5 variables** are configurable at runtime — these are the secrets that differ per provider: - -| Variable | Description | -|---|---| -| `WALLET_PRIVATE_KEY` | Provider's wallet private key | -| `ETH_NODE_ADDRESS` | RPC endpoint for BASE Mainnet (e.g., Alchemy, Infura) | -| `MODELS_CONFIG_CONTENT` | JSON model configuration (model IDs, backend URLs, slots) | -| `WEB_PUBLIC_URL` | Public-facing URL for the API (default: `http://localhost:8082`) | -| `COOKIE_CONTENT` | API authentication credentials (default: `admin:admin`) | - -Because the configuration is frozen in the image, when it runs inside a TEE (Intel TDX or AMD SEV-SNP), the hardware can measure and attest that the software layer has not been modified. - ---- - -## Part 1: Provider — Setting Up a TEE P-Node - -### Prerequisites - -* A funded wallet with MOR and ETH on the target network and access to the private key -* An RPC endpoint for the target network (e.g., `wss://base-mainnet.g.alchemy.com/v2/` for mainnet, or a Base Sepolia RPC for testnet) -* Your AI model backend accessible via a private endpoint (e.g., `http://my-model:8080/v1/chat/completions`) -* A model configuration JSON (see [models-config.json.md](models-config.json.md) for format) -* Access to a Confidential VM provider that supports Intel TDX or AMD SEV-SNP (e.g., [SecretVM](https://secretai.scrtlabs.com/secret-vms/create)) - -> **Mainnet vs. Testnet:** Use the mainnet TEE image (`:latest` or versioned tag without `-test`) for production provider deployments. Use the testnet image (`:latest-test` or tag ending in `-test`) for testing on Base Sepolia. The instructions below use mainnet examples; substitute the testnet image tag and a Sepolia RPC endpoint if testing. - -### Step 1: Prepare the Docker Compose File - -Each CI/CD build produces a **deployed compose file** that references the TEE image by its immutable SHA-256 digest (not a mutable tag). This is critical for attestation — the RTMR3 measurement is computed from the exact compose content. - -Download `docker-compose.tee.deployed.yml` from the [GitHub Release](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/releases) for your target version — it has the correct digest already filled in. Alternatively, use the template at [`proxy-router/docker-compose.tee.yml`](../proxy-router/docker-compose.tee.yml) and replace the image tag with the digest yourself. - -The deployed compose looks like this (the digest will differ per version). It includes a Traefik reverse proxy sidecar that serves the API over HTTPS (port 443) using SecretVM's auto-generated TLS certificates: - -```yaml -services: - proxy-router: - image: ghcr.io/morpheusais/morpheus-lumerin-node-tee@sha256: - restart: unless-stopped - ports: - - 3333:3333 - volumes: - - proxy_data:/app/data - environment: - - WALLET_PRIVATE_KEY=${WALLET_PRIVATE_KEY} - - ETH_NODE_ADDRESS=${ETH_NODE_ADDRESS} - - MODELS_CONFIG_CONTENT=${MODELS_CONFIG_CONTENT} - - WEB_PUBLIC_URL=${WEB_PUBLIC_URL:-https://localhost} - - COOKIE_CONTENT=${COOKIE_CONTENT:-admin:admin} - env_file: - - usr/.env - networks: - - traefik - labels: - - traefik.enable=true - - traefik.http.routers.proxy-router.rule=PathPrefix(`/`) - - traefik.http.routers.proxy-router.entrypoints=websecure - - traefik.http.routers.proxy-router.tls=true - - traefik.http.services.proxy-router.loadbalancer.server.port=8082 - traefik: - image: traefik:v2.10 - command: - - --api.insecure=false - - --providers.docker=true - - --providers.docker.exposedbydefault=false - - --entrypoints.websecure.address=:443 - - --entrypoints.websecure.http.tls.options=default@file - - --providers.file.directory=/etc/traefik/dynamic - - --providers.file.watch=true - ports: - - 443:443 - volumes: - - /var/run/docker.sock:/var/run/docker.sock:ro - - /mnt/secure/cert:/certs:ro - networks: - - traefik - configs: - - source: tls_config - target: /etc/traefik/dynamic/tls.yml - env_file: - - usr/.env -volumes: - proxy_data: null -networks: - traefik: - driver: bridge -configs: - tls_config: - content: |- - tls: - certificates: - - certFile: /certs/secret_vm_fullchain.pem - keyFile: /certs/secret_vm_private.pem - stores: - default: - defaultCertificate: - certFile: /certs/secret_vm_fullchain.pem - keyFile: /certs/secret_vm_private.pem -``` - -The **only line that changes between versions** is the proxy-router image digest on line 3 (`@sha256:`). The Traefik sidecar, TLS config, and network setup remain constant. - -**Why digest instead of tag?** Tags are mutable — someone could push a different image to the same tag. A digest (`@sha256:...`) is an immutable content hash. Using the digest in the compose file guarantees that the RTMR3 measurement is cryptographically bound to one specific image binary. - -> **Important: Exact byte content matters.** The compose file must end with exactly one newline after `proxy_data: null` (standard POSIX line ending, no trailing blank line). RTMR3 is computed from the exact byte content of the compose file — a single extra or missing byte produces a completely different hash. The SecretVM portal normalizes trailing whitespace (strips extra blank lines down to a single newline), so pasting as-is is safe. - -Published images and digests are listed at: -https://github.com/orgs/MorpheusAIs/packages?repo_name=Morpheus-Lumerin-Node - -### Step 2: Prepare Your Secrets - -Your TEE platform will provide a mechanism to inject encrypted secrets that are only accessible inside the enclave. - -You need to set these 5 values: - -``` -WALLET_PRIVATE_KEY= -ETH_NODE_ADDRESS=wss://base-mainnet.g.alchemy.com/v2/ -MODELS_CONFIG_CONTENT= -WEB_PUBLIC_URL=https://your-public-domain.com:8082 -COOKIE_CONTENT=admin: -``` - -**Preparing `MODELS_CONFIG_CONTENT`**: This must be a single-line JSON string. Example: - -``` -MODELS_CONFIG_CONTENT={"models":[{"modelId":"0x626bcb19...","modelName":"hermes-4-14b","apiType":"openai","apiUrl":"http://your-model:8080/v1/chat/completions","concurrentSlots":6,"capacityPolicy":"simple"}]} -``` - -See [models-config.json.md](models-config.json.md) for the full schema. - -### Step 3: Deploy on SecretVM (or Other TEE Platform) - -For **SecretVM** you can either use the web portal (https://secretai.scrtlabs.com/secret-vms/create) or **secretvm-cli**: - -#### Option A: Using the SecretAI Developers Portal - -1. Navigate to the SecretVM creation page -2. Paste the contents of `docker-compose.tee.yml` into the compose configuration -3. Enter your 5 secret values in the encrypted secrets section -4. Under **Advanced features**, configure: - -| Setting | Recommended | Impact on RTMR3 | -|---------|-------------|-----------------| -| **Additional Files** | Leave empty | Uploading a `.tar` archive adds a third hash to the RTMR3 chain, changing the expected value. Secrets are passed via env vars, not files. | -| **Platform** | Intel TDX | Must match the rootfs variant pinned in CI/CD (`rootfs-prod-tdx`). Selecting AMD SEV uses a different rootfs ISO with a different measurement. | -| **Hide Runtime Info** | Off (for verification) | Does not affect RTMR3, but disabling it blocks the `/docker-compose` endpoint used for debugging. | -| **Enable Persistence** | On (recommended) | Does not affect RTMR3. | -| **Enable Upgrades** | On (recommended) | Does not affect RTMR3. | -| **Enable zkVerify** | Optional | Does not affect RTMR3. Increases startup time. | -| **Generate App Certificate** | Optional | Does not affect RTMR3 (cert goes into `reportdata`). | - -5. Deploy the VM - -#### Option B: Using the SecretVM CLI - -1. Install the CLI. -```bash -sudo npm install --global secretvm-cli -``` -2. Authenticate with your SecretAI devportal account: -```bash -secretvm-cli auth login -``` -3. Use the CLI to create your VM, passing in your Docker Compose file and the required runtime secrets: -```bash -secretvm-cli -k vm create \ - --name \ - --type small \ - --persistence \ - --upgradeability \ - --docker-compose proxy-router/docker-compose.tee.yml \ - --env \ - --platform tdx # or sev -``` - -4. You can check the provisioning status of your new VM directly from the terminal: -```bash -secretvm-cli -k vm list -``` - -`Note`: For complete installation instructions, global options, and the most up-to-date command reference, please consult the official [SecretVM CLI documentation](https://docs.scrt.network/secret-network-documentation/secretvm-confidential-virtual-machines/secretvm-cli). - -For other TEE platforms, consult their documentation for deploying Docker Compose workloads with encrypted secret injection. The image and compose file are platform-agnostic — any environment that supports `linux/amd64` Docker containers inside a TEE will work. - -### Step 4: Verify the Node is Running - -Once deployed, check the health endpoint: - -```bash -curl https:///healthcheck -``` - -Expected response: -```json -{ - "status": "healthy", - "version": "", - "uptime": "1m30s" -} -``` - -Then proceed with the standard provider setup: register your provider, create your model (with the `tee` tag), and create a bid. See [03-provider-offer.md](03-provider-offer.md) for those steps. - -### Step 5: Verify Attestation (SecretVM) - -After deployment, SecretVM provides an attestation endpoint at port `29343`. You can verify your own deployment: - -1. **Quick verification** at https://secretai.scrtlabs.com/attestation — paste your compose file and the VM URL -2. **Programmatic verification** — see Part 2 below - ---- - -## Part 2: Consumer — Verifying a TEE Provider Image - -As a consumer, you can independently verify that a provider is running a genuine, untampered TEE image before interacting with it. This verification will eventually be built into the C-Node automatically for models tagged `tee`, but you can do it manually today. - -### Install cosign - -```bash -# macOS -brew install cosign - -# Linux (Debian/Ubuntu) -sudo apt install cosign - -# Or download from: https://github.com/sigstore/cosign/releases -``` - -### Step 1: Verify the Image Signature - -This confirms the image was built by the official MorpheusAIs GitHub Actions CI/CD pipeline — not a fork, not a manual push, not a modified build. - -```bash -cosign verify \ - --certificate-oidc-issuer https://token.actions.githubusercontent.com \ - --certificate-identity-regexp 'MorpheusAIs/Morpheus-Lumerin-Node' \ - ghcr.io/morpheusais/morpheus-lumerin-node-tee: -``` - -A successful output will show: -``` -Verification for ghcr.io/morpheusais/morpheus-lumerin-node-tee: -- -The following checks were performed on each of these signatures: - - The cosign claims were validated - - Existence of the claims in the transparency log was verified offline - - The code-signing certificate was verified using trusted certificate authority certificates -``` - -The output JSON includes the exact GitHub commit, branch, and workflow that produced the image. - -If verification **fails**, the image should not be trusted. - -### Step 2: Inspect the TEE Attestation Manifest - -The attestation manifest is a signed JSON document attached to the image that records exactly what configuration was baked into the TEE image. - -```bash -cosign verify-attestation \ - --certificate-oidc-issuer https://token.actions.githubusercontent.com \ - --certificate-identity-regexp 'MorpheusAIs/Morpheus-Lumerin-Node' \ - --type https://morpheusais.github.io/tee-attestation/v1 \ - ghcr.io/morpheusais/morpheus-lumerin-node-tee: \ - 2>/dev/null | jq -r '.payload' | base64 -d | jq '.predicate' -``` - -This returns a JSON object. Key fields to check: - -| Field | What to Look For | -|---|---| -| `tee_image` | Full image reference with `@sha256:` digest — immutable | -| `tee_image_digest` | The immutable `sha256:...` digest of this exact image | -| `compose_sha256` | Hash of the deployed compose file (digest-pinned) | -| `compose_image_reference` | The exact `image@sha256:` reference inside the compose file | -| `measurements.intel_tdx.rtmr3` | Expected RTMR3 value — compare against the live hardware attestation quote | -| `measurements.intel_tdx.secretvm_release` | Which SecretVM release the RTMR3 was computed against | -| `build.commit` | The Git commit that produced this image — you can inspect the source | -| `build.run_url` | Direct link to the GitHub Actions run that built it | -| `baked_env.network` | `"mainnet"` or `"testnet"` — identifies which network's contracts are baked in | -| `baked_env.PROXY_STORE_CHAT_CONTEXT` | Should be `"false"` — confirms chat logging is disabled | -| `baked_env.ENVIRONMENT` | Should be `"production"` | -| `baked_env.ETH_NODE_CHAIN_ID` | `"8453"` (BASE Mainnet) or `"84532"` (BASE Sepolia testnet) — must match the network | -| `baked_env.DIAMOND_CONTRACT_ADDRESS` | The diamond proxy contract for the target network | -| `baked_env.MOR_TOKEN_ADDRESS` | The MOR token contract for the target network | -| `runtime_secrets_only` | Lists the 5 variables that can differ per provider — everything else is frozen | - -### Step 3: View All Supply-Chain Artifacts - -To see the full tree of artifacts attached to an image: - -```bash -cosign tree ghcr.io/morpheusais/morpheus-lumerin-node-tee: -``` - -This shows: -* **Signatures** (`.sig`) — proves who built it -* **Attestations** (`.att`) — the TEE manifest with config hashes and build provenance -* **SBOMs** (`.sbom`) — full inventory of Go dependencies in the binary - -### Step 4: Verify the Running Provider (SecretVM Attestation) - -If the provider is running on SecretVM, you can verify the hardware attestation: - -1. Go to https://secretai.scrtlabs.com/attestation -2. Paste the `docker-compose.tee.yml` contents (ensure exact byte content — no extra trailing blank lines; see note in Step 1) -3. Enter the provider's VM URL or paste their attestation quote -4. Click **Verify** - -The verification checks three layers: -* **Hardware layer** — the CPU is a genuine Intel TDX or AMD SEV-SNP TEE -* **VM layer** — the firmware, kernel, and initramfs match a known SecretVM release -* **Software layer (RTMR3)** — the rootfs and Docker Compose match what was deployed - -The expected RTMR3 value is published in the signed attestation manifest (Step 2 above) at `measurements.intel_tdx.rtmr3`. Compare it against the RTMR3 reported by the hardware attestation quote to confirm the provider is running the exact image+compose combination that was built by CI/CD. - -If all three layers pass, the provider is running exactly the software that was published by the official CI/CD — inside genuine TEE hardware — with no ability to modify the configuration at runtime. - -### Step 5: Verify RTMR3 Independently (Optional) - -You can recompute RTMR3 yourself using the script in the repository: - -```bash -# Check the pinned version and rootfs variant used by CI/CD -cat .github/tee/secretvm.env -# → SECRETVM_RELEASE=v0.0.25 -# → SECRETVM_ROOTFS_VARIANT=rootfs-prod-tdx - -# Download the same rootfs used by CI/CD -curl -L -o rootfs-prod-tdx.iso \ - "$(grep SECRETVM_ROOTFS_TDX_URL .github/tee/secretvm.env | cut -d= -f2-)" - -# Compute RTMR3 from the deployed compose + rootfs -python3 proxy-router/scripts/compute-rtmr3.py docker-compose.tee.deployed.yml rootfs-prod-tdx.iso -``` - -The output should match `measurements.intel_tdx.rtmr3` from the attestation manifest. - -> **Note:** The rootfs version and variant are pinned in [`.github/tee/secretvm.env`](../.github/tee/secretvm.env). If your RTMR3 doesn't match, check that you're using the same rootfs version as the CI/CD build. See the "Upgrading SecretVM Artifacts" section below. - ---- - -## What This Guarantees (and What It Doesn't) - -TEE trust is a **two-hop chain**, with each hop attested separately. The on-chain `tee` tag on a model triggers both hops: - -``` -C-Node (v6.0.0+) ─────Phase 1─────▶ P-Node -tee image (v7.0.0+) ─────Phase 2─────▶ Backend LLM (SecretVM) -``` - -* **Phase 1** is what the **consumer's proxy-router** runs against the provider's P-Node. It has shipped since v6.0.0. -* **Phase 2** is what the **provider's P-Node** (v7.0.0+) runs against its own backend LLM. The consumer never sees Phase 2 directly — it sees Phase 2 *indirectly*, because the v7+ `-tee` image it just attested in Phase 1 is the code that enforces Phase 2. -* A v6.0.0+ consumer paired with a v7.0.0+ provider gets the full chain transparently — **no consumer-side upgrade is needed** to benefit from Phase 2. - -### Phase 1 — Consumer attests the P-Node (v6.0.0+) - -When a v6.0.0+ C-Node opens a session (and on every subsequent prompt) for a `tee`-tagged model, the consumer's proxy-router proves the following about the provider's P-Node: - -* The proxy-router binary is the exact binary built by the official CI/CD from a known commit (verified via cosign signature on the `-tee` image). -* Chat context storage is disabled and cannot be re-enabled (baked in at image build; enforced by RTMR3). -* Logging is in production mode and cannot be increased to capture prompts (baked in; enforced by RTMR3). -* The blockchain configuration (contracts, chain ID, blockscout URL) is immutable — frozen at build time for the target network (mainnet or testnet). -* The image has not been tampered with between build and deployment (RTMR3 replay of the published deployed compose against the live TDX quote). -* The TLS certificate terminating the connection is pinned into the quote's `reportData[0:32]`, so no TLS-terminating proxy or CDN can sit between the consumer and the P-Node. -* The check runs at session open and is re-checked on every prompt via a ~50 ms fast path (quote hash + TLS fingerprint compare); full re-verification kicks in on drift. - -### Phase 2 — P-Node attests its own backend LLM (v7.0.0+) - -Phase 2 runs **entirely inside the provider's P-Node**. The consumer does not participate. For each `tee`-tagged model, your v7+ P-Node proves the following about the backend LLM it forwards inference to: - -* The backend's CPU TDX quote is independently verified at startup (full `AttestBackend`) and re-checked on **every inference prompt** via the fast path (`FastVerifyBackend` — see [tee-backend-verification.md](../proxy-router/docs/tee-backend-verification.md)). Any quote or TLS drift triggers full re-attestation or a hard fail. -* The backend's TLS certificate fingerprint is pinned into the CPU quote's `reportData[0:32]`, and the P-Node's onward HTTP client rejects any certificate that doesn't match — no MITM can slip between the P-Node and the backend. -* The backend's GPU attestation nonce is bound to the CPU quote via `reportData[32:64]`, and GPU evidence is independently verified by **NVIDIA NRAS** (Remote Attestation Service) for genuine hardware. -* The backend's `docker-compose.yaml` is recovered from `:29343/docker-compose` and **RTMR3 is replayed** against the live TDX quote, proving the exact set of models loaded (e.g., `MODELS='deepseek-r1:70b ...'`) — swapping, adding, or removing any model changes the hash and fails verification. -* MRTD + RTMR0-2 are looked up in the published SecretVM TDX artifact registry to confirm firmware, VM config, kernel, and initramfs all match a known SecretVM build. -* Per-model attestation state is exposed on the P-Node's `GET /v1/models/attestation` endpoint for monitoring and forensics. - -If Phase 2 fails, the P-Node refuses the session open or the individual prompt locally. The consumer observes this as a standard provider-side failure and can fail over to another provider. - -### CI/CD automated verification - -* On every push to `test` (or `cicd/*` branches), the pipeline automatically deploys the new TEE image to a test SecretVM instance and verifies the live RTMR3 attestation matches the CI-computed value. This catches measurement mismatches before they reach providers. - -### Remaining gaps (future work) - -* AMD SEV-SNP measurements are not yet computed in CI/CD. Only Intel TDX RTMR3 is published in the P-Node attestation manifest today. -* Phase 2 backend verification assumes the LLM runs inside a separate SecretVM with the SecretAI attestation endpoints exposed on port `29343`. A future variant will co-locate proxy-router and LLM in a single TDX VM so one RTMR3 covers both hops. -* Backend GPU attestation currently targets NVIDIA NRAS v4 API. Other GPU vendors / alternative attestation services are not yet plumbed in. - ---- - -## Upgrading SecretVM Artifacts - -When SCRT Labs publishes a new SecretVM release (e.g., `v0.0.25` → `v0.0.26`), the rootfs changes and all RTMR3 values must be recomputed. The CI/CD pipeline is fully variablized so that updating requires only editing a single config file. - -### When to Upgrade - -SCRT Labs publishes releases at [github.com/scrtlabs/secret-vm-build/releases](https://github.com/scrtlabs/secret-vm-build/releases). There is no push notification; check the releases page periodically or watch the repository for new releases. You can also query the GitHub API: - -```bash -curl -s https://api.github.com/repos/scrtlabs/secret-vm-build/releases \ - | jq '[.[] | {tag: .tag_name, prerelease: .prerelease, date: .published_at}] | .[0:5]' -``` - -> **Note:** SCRT Labs sometimes marks newer releases as **pre-release** on GitHub while already deploying them to the SecretVM portal (e.g., `v0.0.25` is a pre-release on GitHub but the portal runs "artifacts v0.0.25, environment prod"). The `/releases/latest` API endpoint only returns non-prerelease versions, so always check the full releases list. - -### How to Upgrade - -All SecretVM-specific configuration is in [`.github/tee/secretvm.env`](../.github/tee/secretvm.env). To update: - -1. **Edit `secretvm.env`** — change these three values: - ```bash - SECRETVM_RELEASE=v0.0.26 # ← new version - SECRETVM_ROOTFS_TDX_URL=https://github.com/scrtlabs/secret-vm-build/releases/download/v0.0.26/rootfs-prod-v0.0.26-tdx.iso - SECRETVM_ROOTFS_TDX_SHA256= # ← clear; will be captured on first build - ``` - The `SECRETVM_ROOTFS_VARIANT` stays `rootfs-prod-tdx` unless the naming convention changes. - -2. **Push and let CI/CD run.** The pipeline will: - - Download the new rootfs (and cache it) - - If `SECRETVM_ROOTFS_TDX_SHA256` is empty, compute and report the actual SHA-256 in the step summary - - Compute the new RTMR3 and embed it in the signed attestation manifest - -3. **Pin the rootfs SHA-256.** After the first successful build, copy the reported SHA-256 from the GitHub Actions step summary back into `secretvm.env`: - ```bash - SECRETVM_ROOTFS_TDX_SHA256= - ``` - This pins the exact rootfs for all subsequent builds. - -4. **Rebuild providers.** Providers running older SecretVM versions will have mismatched RTMR3 values. They should redeploy on the current SecretVM release to match the latest attestation manifest. - -### Important: Always Use the `prod` Rootfs Variant - -SecretVM runs "environment prod" even for developer portal deployments. Using the `dev` rootfs variant produces a wrong RTMR3. Always use `rootfs-prod-*` in the config. - ---- - -## Reference - -| Resource | Link | -|---|---| -| TEE images on GHCR | https://github.com/orgs/MorpheusAIs/packages?repo_name=Morpheus-Lumerin-Node | -| RTMR3 computation script | [`proxy-router/scripts/compute-rtmr3.py`](../proxy-router/scripts/compute-rtmr3.py) | -| SecretVM artifact config | [`.github/tee/secretvm.env`](../.github/tee/secretvm.env) | -| Sigstore cosign | https://github.com/sigstore/cosign | -| SCRT Labs reproduce-mr | https://github.com/scrtlabs/reproduce-mr | -| SecretVM documentation | https://docs.scrt.network/secret-network-documentation/secretvm-confidential-virtual-machines | -| SecretVM CLI docs | https://docs.scrt.network/secret-network-documentation/secretvm-confidential-virtual-machines/secretvm-cli | -| SecretVM attestation portal | https://secretai.scrtlabs.com/attestation | -| Model configuration format | [models-config.json.md](models-config.json.md) | -| Provider offer setup | [03-provider-offer.md](03-provider-offer.md) | -| Standard Docker setup | [02.1-proxy-router-docker.md](02.1-proxy-router-docker.md) | diff --git a/docs/02.4-proxy-router-secretvm-quickstart.md b/docs/02.4-proxy-router-secretvm-quickstart.md deleted file mode 100644 index 08bdb5e4..00000000 --- a/docs/02.4-proxy-router-secretvm-quickstart.md +++ /dev/null @@ -1,322 +0,0 @@ -# TEE Provider Quick-Start: Deploying on SecretVM - -This guide walks you through deploying a Morpheus TEE-hardened provider node on [SecretVM](https://secretai.scrtlabs.com) (SCRT Labs' confidential VM platform). By the end, you'll have a provider running inside a hardware-secured Intel TDX enclave that consumers can cryptographically verify before sending prompts. - -For deeper technical details (cosign verification, RTMR3 recomputation, attestation manifest inspection), see the [full TEE reference guide](02.3-proxy-router-tee.md). - ---- - -## What You'll Need - -Before you start, make sure you have: - -- [ ] A **funded wallet** with MOR and ETH on Base Mainnet (or Base Sepolia for testnet) -- [ ] The wallet's **private key** (this stays encrypted inside the TEE — it never leaves the enclave) -- [ ] An **RPC endpoint** for Base Mainnet (e.g., `wss://base-mainnet.g.alchemy.com/v2/`) or Base Sepolia for testnet -- [ ] Your **AI model backend** accessible via a private URL (e.g., `http://my-model:8080/v1/chat/completions`) -- [ ] A **SecretVM account** at https://secretai.scrtlabs.com — sign up and get your API key -- [ ] **secretvm-cli** installed (optional but recommended): `sudo npm install --global secretvm-cli` - ---- - -## Step 1: Get the Docker Compose File - -Each CI/CD build produces a **deployed compose file** that pins the TEE image by its immutable SHA-256 digest. This is what SecretVM uses to compute the RTMR3 measurement that proves your node is running untampered software. - -Download `docker-compose.tee.deployed.yml` from the [latest GitHub Release](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/releases) — it's ready to use with the correct digest already filled in. You can also use the template at [`proxy-router/docker-compose.tee.yml`](../proxy-router/docker-compose.tee.yml) in the repo and replace the image tag with the digest yourself. - -The compose file includes a Traefik TLS reverse proxy sidecar that uses SecretVM's auto-generated certificates to serve the API over HTTPS on port 443: - -```yaml -services: - proxy-router: - image: ghcr.io/morpheusais/morpheus-lumerin-node-tee@sha256: - restart: unless-stopped - ports: - - 3333:3333 - volumes: - - proxy_data:/app/data - environment: - - WALLET_PRIVATE_KEY=${WALLET_PRIVATE_KEY} - - ETH_NODE_ADDRESS=${ETH_NODE_ADDRESS} - - MODELS_CONFIG_CONTENT=${MODELS_CONFIG_CONTENT} - - WEB_PUBLIC_URL=${WEB_PUBLIC_URL:-https://localhost} - - COOKIE_CONTENT=${COOKIE_CONTENT:-admin:admin} - env_file: - - usr/.env - networks: - - traefik - labels: - - traefik.enable=true - - traefik.http.routers.proxy-router.rule=PathPrefix(`/`) - - traefik.http.routers.proxy-router.entrypoints=websecure - - traefik.http.routers.proxy-router.tls=true - - traefik.http.services.proxy-router.loadbalancer.server.port=8082 - traefik: - image: traefik:v2.10 - command: - - --api.insecure=false - - --providers.docker=true - - --providers.docker.exposedbydefault=false - - --entrypoints.websecure.address=:443 - - --entrypoints.websecure.http.tls.options=default@file - - --providers.file.directory=/etc/traefik/dynamic - - --providers.file.watch=true - ports: - - 443:443 - volumes: - - /var/run/docker.sock:/var/run/docker.sock:ro - - /mnt/secure/cert:/certs:ro - networks: - - traefik - configs: - - source: tls_config - target: /etc/traefik/dynamic/tls.yml - env_file: - - usr/.env -volumes: - proxy_data: null -networks: - traefik: - driver: bridge -configs: - tls_config: - content: |- - tls: - certificates: - - certFile: /certs/secret_vm_fullchain.pem - keyFile: /certs/secret_vm_private.pem - stores: - default: - defaultCertificate: - certFile: /certs/secret_vm_fullchain.pem - keyFile: /certs/secret_vm_private.pem -``` - -**The only thing you change between versions is the image digest on line 3** (`@sha256:`). Everything else — Traefik config, TLS certificates, networks — stays the same. The Traefik sidecar (`traefik:v2.10`) is not pinned by digest because it's not part of the TEE measurement. - -> **Use the digest-pinned version.** Tags like `:latest` are mutable — the digest (`@sha256:...`) is not. Using the digest ensures the RTMR3 attestation measurement will match the CI/CD-computed golden value. - ---- - -## Step 2: Prepare Your Secrets - -Create a `.env` file with your 5 provider-specific secrets. These are the **only** values you control — everything else (contract addresses, chain ID, logging config) is baked into the image and cannot be changed. - -```bash -WALLET_PRIVATE_KEY= -ETH_NODE_ADDRESS=wss://base-mainnet.g.alchemy.com/v2/ -MODELS_CONFIG_CONTENT={"models":[{"modelId":"0x","modelName":"your-model-name","apiType":"openai","apiUrl":"http://your-model:8080/v1/chat/completions","concurrentSlots":6,"capacityPolicy":"simple"}]} -WEB_PUBLIC_URL=https://your-public-domain.com -COOKIE_CONTENT=admin: -``` - -`MODELS_CONFIG_CONTENT` must be a single-line JSON string. See [models-config.json.md](models-config.json.md) for the full schema. - ---- - -## Step 3: Deploy on SecretVM - -You have two options: the web portal or the CLI. - -### Option A: Web Portal - -1. Go to https://secretai.scrtlabs.com/secret-vms/create -2. **Docker Compose**: paste the contents of your compose file -3. **Encrypted Secrets**: enter your 5 environment variables from Step 2 -4. **Advanced Features**: - -| Setting | Recommended | Notes | -|---------|-------------|-------| -| **Platform** | Intel TDX | Required for attestation to match CI/CD golden values | -| **Additional Files** | Leave empty | Adding files changes the RTMR3 measurement | -| **Enable Persistence** | On | Preserves data across reboots | -| **Enable Upgrades** | On | Allows updating without reprovisioning | -| **Hide Runtime Info** | Off | Keeps the `/docker-compose` debug endpoint accessible | - -5. Click **Deploy** - -### Option B: CLI (recommended) - -```bash -# Authenticate -secretvm-cli auth login - -# Deploy -secretvm-cli -k vm create \ - --name morpheus-provider \ - --type small \ - --persistence \ - --upgradeability \ - --docker-compose proxy-router/docker-compose.tee.yml \ - --env path/to/your/.env \ - --platform tdx - -# Check status -secretvm-cli -k vm list -``` - -Full CLI reference: [SecretVM CLI docs](https://docs.scrt.network/secret-network-documentation/secretvm-confidential-virtual-machines/secretvm-cli) - ---- - -## Step 4: Verify Your Node is Running - -Once the VM is provisioned (usually 2-3 minutes), check the health endpoint: - -```bash -curl https:///healthcheck -``` - -The API is served over HTTPS on port 443 via the Traefik TLS sidecar (no port number needed in the URL). - -You should see: - -```json -{ - "status": "healthy", - "version": "v7.0.0", - "uptime": "1m30s" -} -``` - -And verify the attestation endpoint is responding (this is on a separate port, directly from SecretVM): - -```bash -curl -k https://:29343/cpu | head -c 100 -``` - -This should return a long hex string — that's your hardware-signed TDX attestation quote. - ---- - -## Step 5: Register as a TEE Provider - -Now register your provider, model, and bid on-chain — the same process as a standard provider, with one critical addition: **tag your model with `tee`**. - -1. Start the Swagger UI at `https:///swagger/index.html` -2. Follow the standard provider setup in [03-provider-offer.md](03-provider-offer.md): - - Approve the Diamond contract to spend MOR on your behalf - - Create your provider with your public endpoint (`your-secretvm-url:3333`) - - Create your model — **include the `tee` tag** so consumers know this is a TEE provider - - Create a bid for your model - -The `tee` tag is what triggers consumer-side attestation verification. Without it, consumers treat you as a standard provider. - ---- - -## Step 6: Verify Your Attestation - -Confirm that your deployment will pass consumer verification: - -### Quick Check (SecretVM Portal) - -1. Go to https://secretai.scrtlabs.com/attestation -2. Paste your compose file contents -3. Enter your VM URL -4. Click **Verify** - -All three layers should pass: -- **Hardware** — genuine Intel TDX enclave -- **VM** — known SecretVM firmware/kernel -- **Software (RTMR3)** — your image + compose matches what CI/CD built - -### Programmatic Check (cosign) - -```bash -# Verify the image signature (proves it was built by the official CI/CD) -cosign verify \ - --certificate-oidc-issuer https://token.actions.githubusercontent.com \ - --certificate-identity-regexp 'MorpheusAIs/Morpheus-Lumerin-Node' \ - ghcr.io/morpheusais/morpheus-lumerin-node-tee: - -# Inspect the attestation manifest (see what's baked in) -cosign verify-attestation \ - --certificate-oidc-issuer https://token.actions.githubusercontent.com \ - --certificate-identity-regexp 'MorpheusAIs/Morpheus-Lumerin-Node' \ - --type https://morpheusais.github.io/tee-attestation/v1 \ - ghcr.io/morpheusais/morpheus-lumerin-node-tee: \ - 2>/dev/null | jq -r '.payload' | base64 -d | jq '.predicate' -``` - ---- - -## What Consumers See, and What Your P-Node Does - -TEE verification is a **two-hop trust chain**. The consumer only talks to your P-Node; your P-Node is what reaches out to the backend LLM. Each hop is attested independently, and the on-chain `tee` tag is what turns both hops on. - -``` -C-Node (v6.0.0+) ─verifies──▶ P-Node (your -tee image, v7.0.0+) ─verifies──▶ Backend LLM (SecretVM) - Phase 1 Phase 2 -``` - -### Hop 1 — Consumer (v6.0.0+) verifies your P-Node (Phase 1) - -When a consumer's C-Node opens a session with your `tee`-tagged model, the consumer's proxy-router automatically performs these checks against **your P-Node** at session open and on every prompt: - -1. **Fetches your P-Node's attestation quote** from `:29343/cpu` -2. **Verifies the quote** via the SecretAI Portal — confirms genuine Intel TDX hardware -3. **Checks TLS binding** — compares the SHA-256 fingerprint of your P-Node's TLS certificate against `reportData[0:32]` in the quote, proving the quote belongs to your server (not replayed from elsewhere) -4. **Compares RTMR3** against the CI/CD-signed golden values published in the `-tee` image's cosign attestation manifest — confirms you're running the exact official `-tee` image -5. **Fast-path re-check on every prompt** — a ~50 ms hash + TLS-fingerprint compare against the cached snapshot; any drift triggers full re-verification - -If any check fails, the consumer refuses to open the session or forward the prompt. This is fully handled inside the consumer's proxy-router (v6.0.0+) — the end user doesn't do anything manually. - -> **Forward compatibility:** a v6.0.0+ C-Node only needs to understand Phase 1 — Phase 2 is entirely your P-Node's job. This means **any v6+ consumer works with any v7+ provider**, gaining the Phase 2 guarantees automatically through the trust chain without a client-side upgrade. - -### Hop 2 — Your P-Node (v7.0.0+) verifies its own backend LLM (Phase 2) - -At startup and on every inference prompt, **your P-Node** (not the consumer) performs these checks against the backend LLM referenced by each `tee`-tagged model's `apiUrl`: - -1. **Fetches the backend's CPU quote** from `:29343/cpu` and verifies it via the SecretAI Portal -2. **TLS pinning** — compares the backend's TLS cert fingerprint against `reportData[0:32]` of its quote, and refuses any onward inference connection whose certificate doesn't match (no MITM can slip between the P-Node and the backend) -3. **Workload RTMR3 replay** — pulls the backend's `docker-compose.yaml` via `:29343/docker-compose`, recomputes the SHA-384 extend chain using the rootfs data from the SecretVM TDX artifact registry, and compares against the RTMR3 reported in the backend's TDX quote — proving the exact set of models loaded (e.g., `MODELS='deepseek-r1:70b ...'`) -4. **GPU attestation + CPU-GPU binding** — fetches GPU evidence from `:29343/gpu`, verifies `reportData[32:64]` of the CPU quote equals the GPU nonce (so the GPU evidence can't be replayed from another box), and submits the GPU evidence to **NVIDIA NRAS** for independent hardware validation -5. **Per-prompt fast verify** — before every forwarded prompt, re-fetches `:29343/cpu` and compares the quote hash + TLS fingerprint against the cached snapshot; any change triggers full re-attestation, any TLS-cert change is a hard fail - -Results are also exposed on your P-Node's health endpoint at `GET /v1/models/attestation`, which reports per-model attestation state (`verified` / `pending` / `failed`), last-success timestamp, and workload verification result. This is useful both for your own monitoring and for any operator who wants to sanity-check the live state. Full developer reference: [proxy-router/docs/tee-backend-verification.md](../proxy-router/docs/tee-backend-verification.md). - -If Phase 2 fails for a `tee`-tagged model, your P-Node will not forward inference to that backend — the session open (or individual prompt) is refused locally. The consumer sees this as a normal provider-side failure. - ---- - -## Troubleshooting - -| Symptom | Likely Cause | Fix | -|---------|-------------|-----| -| Healthcheck returns nothing | VM still provisioning | Wait 2-3 min, check `secretvm-cli vm list` | -| Attestation quote empty | Port 29343 not exposed | SecretVM exposes this automatically — check your VM status | -| RTMR3 mismatch | Wrong compose content or rootfs version | Ensure you're using the exact deployed compose from CI/CD artifacts (byte-for-byte) | -| TLS binding fails | Using a proxy/CDN that terminates TLS | The consumer must connect directly to the SecretVM — no TLS-terminating intermediaries on port 29343 | -| `tee` model not getting sessions | Consumers on older (pre-TEE) versions | Consumers need v6.0.0+ to perform Phase 1 (P-Node) attestation. v6+ consumers transparently gain Phase 2 guarantees by trusting a v7+ provider — no client-side upgrade is needed for Phase 2. | -| Phase 2 failing silently on the consumer | Consumer isn't meant to run Phase 2 | Phase 2 (backend LLM attestation) is done **inside your P-Node**, not the consumer. Check your P-Node's `GET /v1/models/attestation` endpoint for per-model status. | - ---- - -## Updating Your Node - -When a new TEE image is released: - -1. Download the new deployed compose (with updated digest) from GitHub Actions artifacts -2. Update your SecretVM: - -```bash -secretvm-cli -k vm edit \ - --docker-compose path/to/new/docker-compose.tee.yml -``` - -3. The VM reboots with the new image. Verify with `/healthcheck` and the attestation portal. - ---- - -## Further Reading - -| Resource | Link | -|----------|------| -| Full TEE reference (cosign, RTMR3, attestation manifest) | [02.3-proxy-router-tee.md](02.3-proxy-router-tee.md) | -| Model configuration format | [models-config.json.md](models-config.json.md) | -| Provider/model/bid registration | [03-provider-offer.md](03-provider-offer.md) | -| Standard Docker setup (non-TEE) | [02.1-proxy-router-docker.md](02.1-proxy-router-docker.md) | -| SecretVM documentation | [docs.scrt.network](https://docs.scrt.network/secret-network-documentation/secretvm-confidential-virtual-machines) | -| SecretVM CLI | [CLI docs](https://docs.scrt.network/secret-network-documentation/secretvm-confidential-virtual-machines/secretvm-cli) | -| TEE images on GHCR | [GitHub Packages](https://github.com/orgs/MorpheusAIs/packages?repo_name=Morpheus-Lumerin-Node) | diff --git a/docs/02.5-api-auth.md b/docs/02.5-api-auth.md deleted file mode 100644 index b0ec6866..00000000 --- a/docs/02.5-api-auth.md +++ /dev/null @@ -1,155 +0,0 @@ -## Overview - -On startup, the proxy router checks whether a `.cookie` file exists. If not, it creates one. The `.cookie` file contains the administrator’s username and password. Additionally, the router creates (or updates) a configuration file—by default named `proxy.conf`—in the same directory. - -### Default Paths - -- **Cookie File Path**: Configurable via `COOKIE_FILE_PATH`. If not provided, defaults to the same folder where the proxy router binary is located. -- **Proxy Config File**: By default, named `proxy.conf` in the same folder as the proxy router. You can override this path with `AUTH_CONFIG_FILE_PATH`. - ---- - -## Cookie File - -When the cookie file does not exist, the proxy router automatically generates it. -An example `.cookie` file might look like this: - -``` -admin:JJLRNze08ZN3vlNdgwgbrh6c4dRw9gQT -``` - -Where: -- `admin` is the administrator’s username. -- `JJLRNze08ZN3vlNdgwgbrh6c4dRw9gQT` is a randomly generated password. - ---- - -## Proxy Configuration File - -By default, the router creates or updates a file named `proxy.conf` in the same folder. If you set the environment variable `AUTH_CONFIG_FILE_PATH`, it uses that location instead. This file stores user credentials (`rpcauth`) and permission whitelists (`rpcwhitelist`). - -### Example Configuration - -``` -rpcauth=admin:e13576ba0e96bd69f71317c75a06c6f8$cc56ee41055c65b184a34aa5e953d2d069626ce061dd56e22337d2e73804c35c -rpcwhitelist=admin:* -rpcwhitelistdefault=0 -``` - -- **`rpcauth=:$`** - Stores a username with a salted, hashed password. -- **`rpcwhitelist=:`** - Lists the allowed methods for that user. The wildcard (`*`) means “all methods permitted.” -- **`rpcwhitelistdefault=0`** - If set to `0`, only the explicitly whitelisted methods are allowed. If set to `1`, methods are allowed by default unless restricted. - -#### Adding Another User - -When you add a new user (e.g., `agent`), the file might look like: - -``` -rpcauth=admin:e13576ba0e96bd69f71317c75a06c6f8$cc56ee41055c65b184a34aa5e953d2d069626ce061dd56e22337d2e73804c35c -rpcauth=agent:ad7a18621d37167502f29712ffc5f324$c056e5f7aa94f6e48c88c81973dc280d16436c1f7bc3c8bded090ae8ea8fc121 -rpcwhitelist=agent:get_balance -rpcwhitelist=admin:* -rpcwhitelistdefault=0 -``` - -Here, `agent` can only call `get_balance`. The `admin` user retains full access (`*`). - ---- - -## HTTP Endpoints for Managing Users - -Two endpoints are provided to manage users in the config file. Both endpoints require **Basic Authentication** in the HTTP `Authorization` header. - -### 1. Add or Update a User - -**Endpoint**: `POST /auth/users` -**Security**: `BasicAuth` (administrator credentials) -**Produces**: `application/json` - -#### Example Request - -``` -POST /auth/users -Authorization: Basic YWRtaW46SkpMUk56ZTA4Wk4zdmxOZGd3Z2JyaDZjNGRSdzlnUVQ= -Content-Type: application/json - -{ - "username": "agent", - "password": "agentPassword", - "methods": ["get_balance"] -} -``` - -### 2. Remove a User - -**Endpoint**: `DELETE /auth/users` -**Security**: `BasicAuth` (administrator credentials) -**Produces**: `application/json` - -#### Example Request - -``` -DELETE /auth/users -Authorization: Basic YWRtaW46SkpMUk56ZTA4Wk4zdmxOZGd3Z2JyaDZjNGRSdzlnUVQ= -Content-Type: application/json - -{ - "username": "agent" -} -``` - ---- - -## Authentication - -All endpoints require a valid `Authorization` header with **Basic Auth** credentials: - -``` -Authorization: Basic YWRtaW46SkpMUk56ZTA4Wk4zdmxOZGd3Z2JyaDZjNGRSdzlnUVQ= -``` - -In this example, `YWRtaW46SkpMUk56ZTA4Wk4zdmxOZGd3Z2JyaDZjNGRSdzlnUVQ=` is the Base64-encoded form of `admin:JJLRNze08ZN3vlNdgwgbrh6c4dRw9gQT`. - ---- - -## List of Possible Permissions - -Below is a set of recognized RPC methods that can be whitelisted for specific users: - -``` -get_balance -get_transactions -get_allowance -get_latest_block -approve -send_eth -send_mor -get_providers -create_provider -delete_provider -get_models -create_model -delete_model -create_bid -get_bids -delete_bids -get_sessions -session_provider_claim -open_session -close_session -get_budget -get_supply -system_config -add_user -remove_user -initiate_session -chat -get_local_models -get_chat_history -edit_chat_history -``` - -Use these method names in `rpcwhitelist` entries (e.g., `rpcwhitelist=agent:get_balance,get_transactions`) or set `rpcwhitelistdefault=1` to allow them by default unless restricted. \ No newline at end of file diff --git a/docs/03-provider-offer.md b/docs/03-provider-offer.md deleted file mode 100644 index c1a9df8a..00000000 --- a/docs/03-provider-offer.md +++ /dev/null @@ -1,70 +0,0 @@ - -# Creating Provider, Model and Bid on the Blockchain: -**Contract Minimums** As of 11/22/2024: -* "providerMinStake": `200000000000000000`, (0.2 MOR) -* "modelMinStake": `100000000000000000`, (0.1 MOR) -* "marketplaceBidFee": `300000000000000000`, (0.3 MOR) -* "bidPricePerSeconMin `10000000000`, (0.00000001 MOR) - -**Needed information (samples):** -* Provider/Owner: `0x9E26Fea97F7d644BAf62d0e20e4d4b8F836C166c` # Your ERC-20 Wallet with MOR & ETH -* Endpoint: `server.domain.com:3333` # Internet **publicly accessible** server/node access point -* Model ID: `0xe1e6e3e77148d140065ef2cd4fba7f4ae59c90e1639184b6df5c84` # Random 32byte/hex that you generate -* ipfcCID: `0xc2d3a5e4f9b7c1a2c8f0b1d5e6c78492fa7bcd34e9a3b9c9e18f25d3be47a1f6` # 32byte/hex from CID of the model file in the ipfs network -* Model Name: `CapybaraHermes-v2.5-Mistral-7b` # Human Readable name for the model -* Bid Cost: `10000000000` (0.00000001 MOR) # What will the model cost per second to use - -## Steps -1. To complete these steps, you will need to be running the proxy-router and also have access to the API Port (default=8082)for the Swagger API Interface - 1. http://localhost:8082/swagger/index.html - -1. Authorize Diamond Contract to spend on the Provider's behalf - 1. http://localhost:8082/swagger/index.html#/transactions/post_blockchain_approve - 1. Spender Address = Diamond Contract - 1. Authorized Amount = remember that this is in the form `1*10^18` so make sure there's enough MOR granted to cover the contract fees - 1. To become a provider, offer a model and offer a bid based on the current minimums, you will need to authorize the contract to spend at least `600000000000000000` (0.6 MOR) on your behalf - 1. The Diamond Contract is now authorized to spend MOR on provider's behalf - -1. Create Provider in the Diamond contract via swagger api: - 1. http://localhost:8082/swagger/index.html#/providers/post_blockchain_providers - 1. addStake = Amount of stake for provider to risk - - Minimum Provider stake is `200000000000000000`, (0.2 MOR) - - Provider stake to become a subnet is `10000000000000000000000`, (10,000 MOR) - 1. Endpoint = Your **publicly accessible endpoint** for the proxy-router provider (ip:port or fqdn:port no protocol) eg: `mycoolmornode.domain.com:3333` - -1. Add Model to IPFS: - 1. Go to http://localhost:8082/swagger/index.html#/ipfs/post_ipfs_add - 1. Obtain `Hash` from the JSON response. It's the `ipfsCID` for the model registry - 1. Pin the model to the IPFS network - - Go to http://localhost:8082/swagger/index.html#/ipfs/post_ipfs_pin - - Use the `Hash` from the previous step - -1. Create Model in the contract: - 1. Go to http://localhost:8082/swagger/index.html#/models/post_blockchain_models and enter - 1. modelId: random 32byte/hex that will be used in conjunction with providerId to uniquely identify model (uuid) - 1. ipfsCID: 32byte/hex from the previous step - 1. Fee: fee for the model usage - 1. addStake: "modelMinStake": `100000000000000000`, (0.1 MOR) - 1. Owner: Provider Wallet Address - 1. name: Human Readable model like "Llama 2.0" or "Mistral 2.5" or "Collective Cognition 1.1" - 1. tags: array of tag strings for the model - - **TEE providers:** include the tag `"tee"` (case-insensitive) to opt this model into the full two-hop TEE trust chain. The tag turns on two independent verifications, one at each hop: - - **Phase 1 (consumer → your P-Node):** any v6.0.0+ consumer proxy-router will automatically verify your P-Node's TDX attestation (CPU quote, TLS cert pinning, RTMR3 of the `-tee` image) at session open and on every prompt before forwarding any inference. - - **Phase 2 (your P-Node → your backend LLM):** your v7.0.0+ P-Node will itself verify the backend LLM pointed to by the model's `apiUrl` — CPU TDX quote, TLS pinning, RTMR3 replay of the backend's `docker-compose.yaml`, CPU-GPU nonce binding, and NVIDIA NRAS GPU attestation — at startup and on every prompt. A v6+ consumer benefits from Phase 2 automatically by trusting your attested v7+ P-Node; the consumer itself does not talk to the backend. - - Models without the `tee` tag are treated as standard (non-TEE) providers — neither hop of the chain runs. See [02.3-proxy-router-tee.md](02.3-proxy-router-tee.md) and [02.4-proxy-router-secretvm-quickstart.md](02.4-proxy-router-secretvm-quickstart.md) for the full story. - - Other common tags include model-type hints: `llm`, `embedding`, `stt`, `tts`. - 1. Capture the `modelID` from the JSON response - **NOTE** The returned `modelID` is a combination of your requested modelID and your providerID and will be required to update your models-config.json file AND when offering bids - -1. Update the models-config.json file with the new modelID and restart the proxy-router - 1. Navigate to the proxy-router directory and open the `models-config.json` file - 1. Add the new modelID to the JSON array of models - 1. Save the file and restart the proxy-router - -1. Offer Model Bid in the contract: - 1. Navigate to http://localhost:8082/swagger/index.html#/bids/post_blockchain_bids and enter - 1. modelID: Model ID Created above - 1. pricePerSecond: "bidPricePerSeconMin `10000000000`, (0.00000001 MOR) - 1. Click Execute and capture the `bidID` from the JSON response - ----------------- \ No newline at end of file diff --git a/docs/04-consumer-setup.md b/docs/04-consumer-setup.md deleted file mode 100644 index 63f4b694..00000000 --- a/docs/04-consumer-setup.md +++ /dev/null @@ -1,90 +0,0 @@ -### Consumer from Release (Local LLM, Proxy-Router & MorpheusUI): - -This is the simplest way to get started with the Morpheus Lumerin Node as a Consumer. This will allow you to interact with the Morpheus network and the models offered on the network as a consumer. - -It will run 3 different pieces of software on your local machine: -* `proxy-router` - the same software as the provider side, but with different environment variables and a different role -* `MorpheusUI` - Electron GUI that enables the user to interact with the models (via the API) to browse offered bids, purchase and send prompts -* [Optional] `llama.cpp` (llama-server) - a simple sample AI model that can be run on the same machine as the proxy-router and MorpheusUI to show how the components work together and run local (free) inference (to launch this, include the `local` argument when starting the node) - -## Installation Steps: -1. Obtain the software: - * Package: Download latest release for your operating system: https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/releases - - Mainnet releases will have no suffix (eg: `v2.3.0`) - - Testnet releases will be suffixed with `*-test` (eg: `v2.2.56-test`) - -1. Extract the zip to a local folder (examples) - * Windows: `(%USERPROFILE%)/Downloads/morpheus)` - * Linux & MacOS: `~/Downloads/morpheus` - * On MacOS you will need to execute `xattr -c mor-launch mor-cli proxy-router MorpheusUI.app` in a command window to remove the quarantine flag on MacOS - -1. [OPTIONAL] Examine the .env file included in the package and make any necessary updates for your setup - * See [proxy-router.all.env](./proxy-router.all.env) for a list of environment variables that can be set in the `.env` file - -1. Launch the node - this should open a command window to see local LLM model server and proxy-router start and then should launch the user interface - * Windows: Double click the `mor-launch.exe` (You will need to tell Windows Defender this is ok to run) - * Linux & MacOS: Open a terminal and navigate to the folder and run `./mor-launch` - * **NOTE** By Default, the Morpheus node will launch the proxy-router and then the user interface (UI). If you want to also run a local model for testing or understanding how the system works without having to use MOR, execute `./mor-launch local` (or for Windows `./mor-launch.exe local`) to start the local model server before the router and UI. - -1. Startup User Interface: - * Read & accept terms & Conditions - * Set a strong password (this is for the MorpheusUI only) - * Follow the instructions for creating a new wallet (be sure to save the mnemonic in a safe place) - * [OPTIONAL] to use existing Wallet** - - Instead of creating an new wallet and if you have the existing wallet's mnemonic, when prompted, select **`Recover your wallet Saved Mnemonic`** instead. - * [OPTIONAL] Startup CLI Interface: Linux & MacOS: Open a terminal and navigate to the folder and run `./mor-cli` - -## Validation Steps: -1. Once the proxy-router is running, you can navigate to the Swagger API Interface (http://localhost:8082/swagger/index.html as example) to validate that the proxy-router is running and listening for blockchain events - * You can also check the logs in the `./data` directory for any errors or issues that may have occurred during startup - -1. Local Test: Once the UI is up and running, - * You should see tokens for ETH and MOR that you sent to this wallet earlier. - - If this is a new wallet, you will need to send MOR and ETH to this wallet to be able to interact with the blockchain - - This can be done externally via metamask or usual BASE faucets - * Once you have a funded Wallet, you can interact with the local model - * Click on the `Chat` icon on the left side of the screen - * Make sure the `Local Model` is selected - * Begin your conversation with the model by typing in the chat window and pressing `Enter` - - You should see the model respond with the appropriate response to the prompt you entered, if not, there may be an issue with the local model service - -1. Remote Test: Once you've verified that your wallet can access the blockchain and you can see the local model working, you can switch to a remote model and test that as well - * In the `Chat` window, select `Change Model ` - - Select a different model from remote providers - - DropDown and select the contract address of the model you want to use - - Click Change - - Click Open Session - - MUST Enter at least **5** MOR to open session - * You can now chat with the remote model and see the responses in the chat window - -1. Closeout - * Manually End all Remote Sessions: - - In the Chat Window, click on the Time icon to the right of the Model line - this will expand and show current sessions, click the "X" next to each one to make sure it's closed - * Closing the MorpheusUI window should leave the CMD window open - - You’ll have to ctrl-c in the window to kill the local model and proxy-router -1. Cleanup - * When testing multiple versions or if you get into an inconsistent state, you may need to clean up the local environment - - **Ensure that you have (or saved) your `wallet mnemonic or private key` before proceeding!** - - Close the MorpheusUI window - - Close the CMD window (or CTRL+C to stop the processes) - - Delete the following files/folders from your downloaded, unzipped Morpheus folder - ``` bash - # Mac and Ubuntu Commands: - rm .cookie proxy.conf - rm -rf ~/Library/Logs/morpheus-ui - rm -rf ~/Library/Application\ Support/morpheus-ui - rm -rf data - - # For MacOS, you may need to remove the quarantine flag on the files - xattr -c proxy-router MorpheusUI.app mor-launch mor-cli - - # Windows Commands: - del .cookie proxy.conf - rmdir /s /q data - rmdir /s /q %USERPROFILE%\AppData\Roaming\morpheus-ui - ``` - * Check these other locations for Morpheus related files and delete them if necessary - - Windows:  `%USERPROFILE%\AppData\Roaming\morpheus-ui` - - Linux: `~/.config/morpheus-ui` - - MacOS: `~/Library/Application Support/morpheus-ui` - * At this point, all stored is removed and you can start fresh with a new wallet or recover an existing wallet per instructions above diff --git a/docs/04a-consumer-setup-source.md b/docs/04a-consumer-setup-source.md deleted file mode 100644 index faed42dd..00000000 --- a/docs/04a-consumer-setup-source.md +++ /dev/null @@ -1,197 +0,0 @@ -# Consumer Node Setup from Source (Draft - 2024-08-05) -This document provides a step-by-step guide to setting up a Consumer Node for the Morepheus Network so that you can setup session and interact with the remote providers. - -## Pre-requisites: -* Create or use an existing ERC-20 wallet that has MOR and ETH on BASE - you can use Metamask (new wallet..not derived) or any other ERC-20 wallet. You will need to have access to the wallet's private key **NEVER SHARE THIS WITH ANYONE** for steps below to authorize the contract to spend on your behalf. - -## TL;DR -* Install and Configure the proxy-router node (once) -* Authorize the contract to spend on your behalf (once) -* Query the blockchain for various models / providers & get the ModelID `Id` (every session) -* Create a session with the provider using the ModelID `Id` (every session) -* Interact with the provider by sending the prompt (every session) - -## Detail: -================================== -### A. Proxy-Router CLI Setup -#### 1. Install OS-Specific Dependencies -* git (https://git-scm.com/) -* go (https://golang.org/) Version >= 1.22 - -#### 2. Clone & Navigate to the Repository -```bash -git clone https://github.com/MorpheusAIs/Morpheus-Lumerin-Node.git #this will get you the DEV branch (daily updates) -cd Morpheus-Lumerin-Node/proxy-router -``` -#### 3. Edit the .env configuration file -```bash -cp .env.example .env -vi .env -``` -Modify the following entries to match your configuration for wallet and ethereum node: -* `WALLET_PRIVATE_KEY=` # Private Key from your Wallet as Consumer or Provider (needed for the proxy-router to sign transactions) -* `ETH_NODE_ADDRESS=wss://` # Recommend using your own private ETH Node Address for better performance (via Alchemy or Infura) -Save the .env file and exit the editor - -#### 4. Build and start the proxy-router -```bash -./build.sh -./proxy-router -``` -After the iniial setup, you can execute `git pull` to get the latest updates and re-run the `./build.sh` and `./proxy-router` to update the proxy-router with the latest changes. - -#### 5. Confirm that the build is successful and console should show similar to below after started (and listening on specified ports 8082 for Swagger API and 3333 for the proxy-router): - -You can also test http://localhost:8082/swagger/index.html to confirm the API is running and accessible. - -``` -Loaded config: {AIEngine:{OpenAIBaseURL: OpenAIKey:} Blockchain:{EthNodeAddress: EthLegacyTx:false ExplorerApiUrl:} Environment:development Marketplace:{DiamondContractAddress:0x6aBE1d282f72B474E54527D93b979A4f64d3030a MorTokenAddress:0x7431ada8a591c955a994a21710752ef9b882b8e3 WalletPrivateKey:} Log:{Color:true FolderPath: IsProd:false JSON:false LevelApp:info LevelConnection:info LevelProxy:info LevelScheduler:info LevelContract:} Proxy:{Address:0.0.0.0:3333 MaxCachedDests:5 StoragePath:} System:{Enable:false LocalPortRange:1024 65535 NetdevMaxBacklog:100000 RlimitHard:524288 RlimitSoft:524288 Somaxconn:100000 TcpMaxSynBacklog:100000} Web:{Address:0.0.0.0:8082 PublicUrl:localhost:8082}} -2024-07-23T12:58:04.560735 INFO APP proxy-router TO BE SET AT BUILD TIME -2024-07-23T12:58:08.249559 INFO APP connected to ethereum node: wss://base-mainnet.g.alchemy.com/v2/, chainID: 8453 -2024-07-23T12:58:08.278792 INFO BADGER All 0 tables opened in 0s -2024-07-23T12:58:08.28444 INFO BADGER Discard stats nextEmptySlot: 0 -2024-07-23T12:58:08.284515 INFO BADGER Set nextTxnTs to 0 -2024-07-23T12:58:08.284769 WARN Using env wallet. Private key persistance unavailable -2024-07-23T12:58:08.290268 INFO proxy state: running -2024-07-23T12:58:08.290507 INFO HTTP http server is listening: 0.0.0.0:8082 -2024-07-23T12:58:08.290631 INFO Wallet address: -2024-07-23T12:58:08.290841 INFO started watching events, address 0x6aBE1d282f72B474E54527D93b979A4f64d3030a -2024-07-23T12:58:08.290866 INFO TCP tcp server is listening: 0.0.0.0:3333 -``` -================================== -### B. Authorize the contract to spend on your behalf -Either via the swagger interface http://localhost:8082/swagger/index.html#/wallet/post_blockchain_allowance or following CLI, you can authorize the contract to spend on your behalf. **This only needs to be done once per wallet, or when funds have been depleted.** - -`curl -X 'POST' 'http://localhost:8082/blockchain/approve?spender=0x6aBE1d282f72B474E54527D93b979A4f64d3030a&amount=3' -H 'accept: application/json' -d ''` # Approve the contract to spend 3 MOR tokens on your behalf - -### C. Query the blockchain for various models / providers (Get ModelID) -You can query the blockchain for various models and providers to get the ModelID. This can be done via the swagger interface http://localhost:8082/swagger/index.html#/marketplace/get_marketplace_models or following CLI: -* `curl -X 'GET' 'http://localhost:8082/wallet' -H 'accept: application/json'` # Returns the wallet ID (confirm that it matches your wallet) -* `curl -X 'GET' 'http://localhost:8082/blockchain/models' -H 'accept: application/json'` # Returns the list of models and providers - * The first model in the list is the default model that you can use for testing purposes...see example below - * `Id` is the ID of the model that you will use to create a session with the provider. - * `Name` is the type of model offered - -``` -{ - "models": [ - { - "Id": "0x6a4813e866a48da528c533e706344ea853a1d3f21e37b4c8e7ffd5ff25779018", - "IpfsCID": "0x0000000000000000000000000000000000000000000000000000000000000000", - "Fee": 0, - "Stake": 0, - "Owner": "0x0eb467381abbc5b71f275df0c8a4e0ed8561f46f", - "Name": "llama2:7b", - "Tags": [], - "CreatedAt": 1721220139, - "IsDeleted": false - }, - { - "Id": "0x72eb5a6a575cdfb59e650994240961db2b1d915dbaa7c009b53b20fe8b9d2d7c", - "IpfsCID": "0x019ae5515ec6259cf835639fd645620811fe951f54c55ae5c85c1bb101cdcc3a", - "Fee": 42, - "Stake": 0, - "Owner": "0x65bbb982d9b0afe9aed13e999b79c56ddf9e04fc", - "Name": "CollectiveCognition-v1.1-Mistral-7b", - "Tags": [], - "CreatedAt": 1721222411, - "IsDeleted": false - }, - { - "Id": "0x84b6df5c84e1e6ae59c90e1639e3e77148d140065ef2cd4fba7f41cc7440e2c5", - "IpfsCID": "0xa3b9c9e18f25d3be47a2c8f0b1d5e6c78492fa7bcd34e9a1f6c2d3a5e4f9b7c1", - "Fee": 42, - "Stake": 0, - "Owner": "0xb8f836c167d60e20e44baf62d4d46c9e26fea97f", - "Name": "CapybaraHermes-v2.5-Mistral-7b", - "Tags": [], - "CreatedAt": 1721224046, - "IsDeleted": false - } - ] -} -``` - -### D. Create a session with the provider -```bash -curl -s -X 'POST' 'http://localhost:8082/blockchain/models//session' \ --H 'accept:application/json' \ --H 'Content-Type: application/json' \ --d '{"sessionDuration": 600}' -``` -Now that the session is open, you can send inference queries to the provider and process responses in usual OpenAI format. -Your Wallet (on https://base.blockscout.com/address/) should show the transaction for the session creation. - -### E. Interact with the provider -* Send the prompt (Standard OpenAI format) with session_id in the header to interact. -* Minimally, you need to provide the `content` and `role` in the messages block and (currently) `"stream":true` for the remote prompt to work. -```bash -curl -X 'POST' \ - 'http://localhost:8082/v1/chat/completions' \ - -H 'accept: application/json' \ - -H 'session_id: ' \ - -H 'Content-Type: application/json' \ - -d '{ - "messages": [ - { - "content": "tell me a joke", - "role": "user" - } - ], - "stream": true - }' -``` - - -### Quick and Dirty Sample: -`curl -X 'POST' 'http://localhost:8082/blockchain/approve?spender=0x6aBE1d282f72B474E54527D93b979A4f64d3030a&amount=3' -H 'accept: application/json' -d ''` - # approves the smart contract to spend 3 MOR tokens on your behalf - -`curl -s -X 'GET' 'http://localhost:8082/wallet' -H 'accept: application/json' | jq .address` - # returns the wallet ID (confirm that it matches your wallet) - -`curl -s -X 'GET' 'http://localhost:8082/blockchain/models' -H 'accept: application/json' | jq -r '.models[] | "\(.Id), \(.Name)"'` - # returns model ID and Name ... copy the ID for the next step `0x84b6df5c84e1e6ae59c90e1639e3e77148d140065ef2cd4fba7f41cc7440e2c5` - -`curl -s -X 'POST' 'http://localhost:8082/blockchain/models/0x84b6df5c84e1e6ae59c90e1639e3e77148d140065ef2cd4fba7f41cc7440e2c5/session' -H 'accept:application/json' -H 'Content-Type: application/json' -d '{"sessionDuration": 600}' | jq .sessionId` - # returns the session ID ... copy the ID for the next step `0x089111479fa2847106b4f7b17eace2e9b37e0d3c0db331b4e01a6e24de827477` - -```bash -curl -X 'POST' \ - 'http://localhost:8082/v1/chat/completions' \ - -H 'accept: application/json' \ - -H 'session_id: 0x089111479fa2847106b4f7b17eace2e9b37e0d3c0db331b4e01a6e24de827477' \ - -H 'Content-Type: application/json' \ - -d '{ - "messages": [ - { - "content": "tell me a joke", - "role": "user" - } - ], - "stream": true - }' -``` -#### Sample Output: -``` -data: {"id":"chatcmpl-8wtgv86nUWMJneEObprWKXcWKX81PAAo","object":"chat.completion.chunk","created":1721758293,"model":"llama2","choices":[{"index":0,"delta":{"content":"Why"},"finish_reason":null,"content_filter_results":{"hate":{"filtered":false},"self_harm":{"filtered":false},"sexual":{"filtered":false},"violence":{"filtered":false}}}]} -data: {"id":"chatcmpl-8wtgv86nUWMJneEObprWKXcWKX81PAAo","object":"chat.completion.chunk","created":1721758293,"model":"llama2","choices":[{"index":0,"delta":{"content":" don"},"finish_reason":null,"content_filter_results":{"hate":{"filtered":false},"self_harm":{"filtered":false},"sexual":{"filtered":false},"violence":{"filtered":false}}}]} -data: {"id":"chatcmpl-8wtgv86nUWMJneEObprWKXcWKX81PAAo","object":"chat.completion.chunk","created":1721758293,"model":"llama2","choices":[{"index":0,"delta":{"content":"'"},"finish_reason":null,"content_filter_results":{"hate":{"filtered":false},"self_harm":{"filtered":false},"sexual":{"filtered":false},"violence":{"filtered":false}}}]} -data: {"id":"chatcmpl-8wtgv86nUWMJneEObprWKXcWKX81PAAo","object":"chat.completion.chunk","created":1721758293,"model":"llama2","choices":[{"index":0,"delta":{"content":"t"},"finish_reason":null,"content_filter_results":{"hate":{"filtered":false},"self_harm":{"filtered":false},"sexual":{"filtered":false},"violence":{"filtered":false}}}]} -data: {"id":"chatcmpl-8wtgv86nUWMJneEObprWKXcWKX81PAAo","object":"chat.completion.chunk","created":1721758293,"model":"llama2","choices":[{"index":0,"delta":{"content":" scientists"},"finish_reason":null,"content_filter_results":{"hate":{"filtered":false},"self_harm":{"filtered":false},"sexual":{"filtered":false},"violence":{"filtered":false}}}]} -data: {"id":"chatcmpl-8wtgv86nUWMJneEObprWKXcWKX81PAAo","object":"chat.completion.chunk","created":1721758293,"model":"llama2","choices":[{"index":0,"delta":{"content":" trust"},"finish_reason":null,"content_filter_results":{"hate":{"filtered":false},"self_harm":{"filtered":false},"sexual":{"filtered":false},"violence":{"filtered":false}}}]} -data: {"id":"chatcmpl-8wtgv86nUWMJneEObprWKXcWKX81PAAo","object":"chat.completion.chunk","created":1721758293,"model":"llama2","choices":[{"index":0,"delta":{"content":" atoms"},"finish_reason":null,"content_filter_results":{"hate":{"filtered":false},"self_harm":{"filtered":false},"sexual":{"filtered":false},"violence":{"filtered":false}}}]} -data: {"id":"chatcmpl-8wtgv86nUWMJneEObprWKXcWKX81PAAo","object":"chat.completion.chunk","created":1721758294,"model":"llama2","choices":[{"index":0,"delta":{"content":"?"},"finish_reason":null,"content_filter_results":{"hate":{"filtered":false},"self_harm":{"filtered":false},"sexual":{"filtered":false},"violence":{"filtered":false}}}]} -data: {"id":"chatcmpl-8wtgv86nUWMJneEObprWKXcWKX81PAAo","object":"chat.completion.chunk","created":1721758294,"model":"llama2","choices":[{"index":0,"delta":{"content":"\n"},"finish_reason":null,"content_filter_results":{"hate":{"filtered":false},"self_harm":{"filtered":false},"sexual":{"filtered":false},"violence":{"filtered":false}}}]} -data: {"id":"chatcmpl-8wtgv86nUWMJneEObprWKXcWKX81PAAo","object":"chat.completion.chunk","created":1721758294,"model":"llama2","choices":[{"index":0,"delta":{"content":"\n"},"finish_reason":null,"content_filter_results":{"hate":{"filtered":false},"self_harm":{"filtered":false},"sexual":{"filtered":false},"violence":{"filtered":false}}}]} -data: {"id":"chatcmpl-8wtgv86nUWMJneEObprWKXcWKX81PAAo","object":"chat.completion.chunk","created":1721758294,"model":"llama2","choices":[{"index":0,"delta":{"content":"Because"},"finish_reason":null,"content_filter_results":{"hate":{"filtered":false},"self_harm":{"filtered":false},"sexual":{"filtered":false},"violence":{"filtered":false}}}]} -data: {"id":"chatcmpl-8wtgv86nUWMJneEObprWKXcWKX81PAAo","object":"chat.completion.chunk","created":1721758294,"model":"llama2","choices":[{"index":0,"delta":{"content":" they"},"finish_reason":null,"content_filter_results":{"hate":{"filtered":false},"self_harm":{"filtered":false},"sexual":{"filtered":false},"violence":{"filtered":false}}}]} -data: {"id":"chatcmpl-8wtgv86nUWMJneEObprWKXcWKX81PAAo","object":"chat.completion.chunk","created":1721758294,"model":"llama2","choices":[{"index":0,"delta":{"content":" make"},"finish_reason":null,"content_filter_results":{"hate":{"filtered":false},"self_harm":{"filtered":false},"sexual":{"filtered":false},"violence":{"filtered":false}}}]} -data: {"id":"chatcmpl-8wtgv86nUWMJneEObprWKXcWKX81PAAo","object":"chat.completion.chunk","created":1721758294,"model":"llama2","choices":[{"index":0,"delta":{"content":" up"},"finish_reason":null,"content_filter_results":{"hate":{"filtered":false},"self_harm":{"filtered":false},"sexual":{"filtered":false},"violence":{"filtered":false}}}]} -data: {"id":"chatcmpl-8wtgv86nUWMJneEObprWKXcWKX81PAAo","object":"chat.completion.chunk","created":1721758294,"model":"llama2","choices":[{"index":0,"delta":{"content":" everything"},"finish_reason":null,"content_filter_results":{"hate":{"filtered":false},"self_harm":{"filtered":false},"sexual":{"filtered":false},"violence":{"filtered":false}}}]} -data: {"id":"chatcmpl-8wtgv86nUWMJneEObprWKXcWKX81PAAo","object":"chat.completion.chunk","created":1721758294,"model":"llama2","choices":[{"index":0,"delta":{"content":"!"},"finish_reason":null,"content_filter_results":{"hate":{"filtered":false},"self_harm":{"filtered":false},"sexual":{"filtered":false},"violence":{"filtered":false}}}]} -data: {"id":"chatcmpl-8wtgv86nUWMJneEObprWKXcWKX81PAAo","object":"chat.completion.chunk","created":1721758294,"model":"llama2","choices":[{"index":0,"delta":{"content":"\u003c|im_end|\u003e"},"finish_reason":null,"content_filter_results":{"hate":{"filtered":false},"self_harm":{"filtered":false},"sexual":{"filtered":false},"violence":{"filtered":false}}}]} -data: {"id":"chatcmpl-8wtgv86nUWMJneEObprWKXcWKX81PAAo","object":"chat.completion.chunk","created":1721758294,"model":"llama2","choices":[{"index":0,"delta":{},"finish_reason":"stop","content_filter_results":{"hate":{"filtered":false},"self_harm":{"filtered":false},"sexual":{"filtered":false},"violence":{"filtered":false}}}]} -``` - - diff --git a/docs/05-bid-purchase.md b/docs/05-bid-purchase.md deleted file mode 100644 index 219040be..00000000 --- a/docs/05-bid-purchase.md +++ /dev/null @@ -1 +0,0 @@ -# TODO - detail steps for consumer to navigate in the MorpheusUI, select & purchase remote model \ No newline at end of file diff --git a/docs/06-model-interaction.md b/docs/06-model-interaction.md deleted file mode 100644 index 0d6ed1e4..00000000 --- a/docs/06-model-interaction.md +++ /dev/null @@ -1 +0,0 @@ -# TODO - Detailed setps once bid has been purchased to interact with the model (might be model dependent). Also include how to close model early, check on time remaining, etc. \ No newline at end of file diff --git a/docs/99-troubleshooting.md b/docs/99-troubleshooting.md deleted file mode 100644 index de299f44..00000000 --- a/docs/99-troubleshooting.md +++ /dev/null @@ -1,41 +0,0 @@ -# Troubleshooting guides for proxy-router and MorpheusUI desktop applications -* These are some common scenarios and failure modes to watch out for when running the proxy-router and MorpheusUI desktop applications. -* One of the most critical things to remember, especially about the desktop application (MorpheusUI) or the Swagger API (http://localhost:8082/swagger/index.html) is that you **must** have a good startup of the proxy-router. - * If the proxy-router is not running or is not able to connect to the blockchain node, the desktop application will not be able to talk to the blockchain, manage your wallet or send prompts to the provider. - * The proxy-router is the bridge between the blockchain node and the desktop application. It is responsible for routing prompts and responses between the consumer and provider. -* One of the best ways to observe the health of the proxy-router is to start it (either `./proxy-router` or `./mor-launch` for the release) from a terminal or command line session where you can see the output in real-time. -* There are also many options for adding log destination and details of log entries (please see [proxy-router.all.env](./proxy-router.all.env) #Logging Configuration section for more information. - -## Proxy-Router -### Proxy-Router is not starting -* **Expected Result or "How do I know it's good?":** - * The proxy-router should start successfully and be able to connect to the blockchain node and listening on both 8082 and 3333 ports (these are the default ports) - * In the terminal or logs after startup, you should see the following messages with regard to the proxy-router (there will be other messages as well): - ``` - INFO HTTP http server is listening: 0.0.0.0:8082 - INFO TCP tcp server is listening: 0.0.0.0:3333 - ``` - * The other way to verify that the proxy-router has started is to query the Swagger API at http://localhost:8082/swagger/index.html (or whatever url you've set in the .env file for your proxy-router IP or DNS address) and see the API documentation. - -* **Symptoms:** The proxy-router is not starting or is crashing immediately after starting. -* **Possible Causes:** - * **.env file misconfiguration** (e.g. missing or incorrect values) - * These four items MUST be accurate to the chain and your OS., Use the example files `/proxy-router/env.main.example` to make sure you have the correct values: - * `DIAMOND_CONTRACT_ADDRESS=` - * `MOR_TOKEN_ADDRESS=` - * `BLOCKSCOUT_API_URL=` - * `ETH_NODE_CHAIN_ID=` - * `PROXY_STORAGE_PATH=` - * If you are running the proxy-router by itself (without the UI), you will need to set the private key of your provider wallet in the `WALLET_PRIVATE_KEY=` - * **IF** you use your own ETH node (Alchemy, Infura, etc.) to communicate with the blockchain, you will need to make sure that the `ETH_NODE_URL=` entry in the .env file is correct for your chain. - * We recommend https:// instead of wss:// for the ETH_NODE_URL ...which also means that `ETH_NODE_USE_SUBSCRIPTIONS=false` should be set in the .env file - - * **models-config.json misconfiguration** (e.g. missing or incorrect values) - * The `models-config.json` file is used to direct the proxy to find the models that the proxy-router will use to route prompts and responses between consumers and providers. - * Ensure that: - * the `MODELS_CONFIG_PATH=` in your .env file is correct and points to the correct directory and file and has the right permissions - * the `models-config.json` should follow the formatting shown in the example file [models-config.json.md](./models-config.json.md) -* **Resolution:** - * Check the .env and models-config.json file configuration and ensure that the blockchain node is accessible. - * Restart the proxy-router and check the logs for any errors related to the connection. - \ No newline at end of file diff --git a/docs/RELEASE_CHECKLIST.md b/docs/RELEASE_CHECKLIST.md new file mode 100644 index 00000000..e62cbc9f --- /dev/null +++ b/docs/RELEASE_CHECKLIST.md @@ -0,0 +1,58 @@ +# Documentation release checklist + +Run through this checklist as part of every release of the Morpheus Lumerin Node. The goal: keep `/docs` truthful, current, and aligned with the binaries and contracts shipped in the release. + +## Per-release tasks + +### 1. Update canonical numbers and addresses + +- [ ] [`docs/get-started/networks-and-tokens.mdx`](get-started/networks-and-tokens.mdx) — confirm chain IDs, MOR token, and Diamond addresses match the release. Bump `last_verified`. +- [ ] [`README.md`](../readme.md) — same table sanity-check. + +### 2. Refresh affected pages + +For each substantive change in the release, identify the affected `audience` and `product` tags in the docs frontmatter and bump `last_verified` on every matching page that reflects the change. + +| Change category | Audiences to sweep | +|-----------------|--------------------| +| proxy-router HTTP API change | `developer`, all consumer/provider tags | +| MorpheusUI change | `consumer` | +| TEE / attestation change | `provider-full`, `developer`, `consumer` | +| New backend integration (`apiType`) | `provider-full`, `provider-resale`, `developer` | +| Contract change | all | +| New mor.org / tech.mor.org / active.mor.org behavior | `consumer`, `prosumer`, `provider-*` (touch ecosystem mirrors) | + +### 3. Regenerate API reference + +- [ ] Confirm [`proxy-router/docs/swagger.yaml`](../proxy-router/docs/swagger.yaml) is up to date (auto-regenerated by the CI/CD build pipeline via `swag init`). +- [ ] If endpoint shapes changed, update the curated subset in [`docs/reference/api-endpoints.mdx`](reference/api-endpoints.mdx) and bump its `last_verified`. +- [ ] If the **hosted Morpheus Inference API** product (separate from this repo, documented at [apidocs.mor.org](https://apidocs.mor.org)) has shipped breaking changes, refresh [`docs/inference-api/overview.mdx`](inference-api/overview.mdx) and bump its `last_verified`. + +### 4. Refresh ecosystem mirrors + +For each page under `docs/ecosystem/` whose `source_url` may have changed: + +- [ ] Visit `source_url`, compare to mirror text. +- [ ] If only superficial / live data drift: bump `last_verified`. +- [ ] If meaningful structural change: rewrite, then bump `last_verified`. +- [ ] If the source has gone away: remove the page; add a redirect in [`docs.json`](docs.json). + +### 5. Run CI locally before merging + +- [ ] `cd docs && mint dev` boots without errors. +- [ ] `mint broken-links` returns clean (or all flagged links are intentional external links). +- [ ] No pages have `last_verified` older than two minor releases (the [docs CI workflow](../.github/workflows/docs.yml) raises warnings). + +### 6. Update redirects if pages moved + +- [ ] Every removed or renamed `.mdx` has a redirect entry in [`docs.json`](docs.json) `redirects`. +- [ ] No internal markdown links point at deleted paths (`grep` the repo). + +### 7. Final sweep + +- [ ] [`AGENTS.md`](../AGENTS.md) lookup table still points at correct pages. +- [ ] [`.cursor/rules/morpheus.mdc`](../.cursor/rules/morpheus.mdc) rules still reflect current behavior. + +## When in doubt + +If this checklist is ambiguous for a particular change, **be conservative**: bump `last_verified` only on pages whose content you re-read and confirmed. A stale `last_verified` is better than a falsely-confident one. diff --git a/docs/User Compute Note Setup via AWS.md b/docs/User Compute Note Setup via AWS.md deleted file mode 100644 index fb7fddd2..00000000 --- a/docs/User Compute Note Setup via AWS.md +++ /dev/null @@ -1,108 +0,0 @@ -# User Compute Note Setup via AWS - -### Purpose -This guide has been developed to help setup your Morpheus compute node within AWS using EC2. This guide will help you setup an LLM model within AWS EC2, and connect to the Morpehus Proxy-Router to provide compute through the Morpheus ecosystem. Please note that the Morpheus Compute Ecosystem is still in testnet, and this guide is serving as a first draft, which will be modified for optimization and to address feedback. - -## Setting up your LLM Instance - -1. Sign into AWS and Open AWS Console -2. Go to EC2 Dashboard and Select, Launch Instances -3. Name the instance and choose “Amazon Linux” - - ![Instance Setup](https://github.com/user-attachments/assets/d9dd288c-d594-4584-9185-b80628756ff7) - -4. Choose your instance type: THIS IS A KEY STEP. The instance type you choose will directly impact which model you can run and the associated performance of that model. For this testing, I will use the TinyLlama model with m5.xlarge, larger instances will be needed for larger models (this is for testing). - - ![Instance Selection](https://github.com/user-attachments/assets/e3752a2f-88a1-4c72-81d7-6fd175bad893) - -5. Select your Key Pair, or create one if you haven’t - - ![Key Pair Selection](https://github.com/user-attachments/assets/700b2bdc-efe9-435a-8e1f-f022a1e3ec6e) - - -6. Create your security group: This step is critical for security. You will need to specify the ports that will be opened and who they can be accessed by. For the communication between the LLM and Proxy Router to work properly, you need to enable inbound traffic from port range 8080-8082. Additionally, to connect to your instance you need to enable traffic on port 20 for your IP. Outbound traffic can remain open, depending on your personal security preferences. - - Security Groups - -7. Configure Storage: Choose the storage space needed for the model - -![Configure Storage](https://github.com/user-attachments/assets/218cd1ed-c26e-4fd3-8187-5121387b5dc7) - -8. Click Launch Instance -9. Go back to the dashboard and click on your new instance -10. Click “Connect” and choose “Connect using EC2 Instance Connect - -Connect to Instance - -### Configuring your Instance - -1. Once the terminal windows opens, you will need to complete some configuration to run the model. Run the following commands, one at a time -2. `sudo yum install git -y` -3. `sudo yum install golang-go -y` -4. `sudo yum groupinstall "Development Tools" -y` -5. `git clone https://github.com/ggerganov/llama.cpp.git -cd llama.cpp -make -j 8` - -Download and host the model -Now you are ready to install your model and host it. You will need a few key pieces of information for this. First, you will need your Public IPv4 DNS name and the host you will be running on (we are using 8080 as default). Next, you will need the model_url, model_collection, and model_file_name, which you can find from a Huggingface directory (must be GGUF). We will be using Tinyllama for testing with the information below. - -Public IPv4 DNS from EC2 Dashboard = model_host - -![IPv4 DNS](https://github.com/user-attachments/assets/c2d0b3c3-8d85-4b2a-854a-179336f4dd10) - -Model on Hugging Face: https://huggingface.co/TheBloke/TinyLlama-1.1B-Chat-v1.0-GGUF/blob/main/tinyllama-1.1b-chat-v1.0.Q4_K_M.gguf -Model URL, Collection and File Name extracted for below - -1. Within the terminal, ensure you are in the llama director with the following command: -2. `cp llama.cpp` -3. Download and host your model. You need to edit the parameters from the code below with your own information mentioned above. This will take some time to run -4. `model_host=ec2-3-147-83-19.us-east-2.compute.amazonaws.com -model_port=8080 -model_url=https://huggingface.co/TheBloke -model_collection=TinyLlama-1.1B-Chat-v1.0-GGUF -model_file_name=tinyllama-1.1b-chat-v1.0.Q4_K_M.gguf -wget -O models/${model_file_name} ${model_url}/${model_collection}/resolve/main/${model_file_name} -./llama-server -m models/${model_file_name} --host ${model_host} --port ${model_port} --n-gpu-layers 4096` -5. You will get the following response when complete - - ![LLM Code Compelte](https://github.com/user-attachments/assets/7bdd6d2a-159b-4c9c-9d13-b9ec098e42ad) - -6. To check that your host is running correctly, go to a web browser and type in http://: -7. You will see the llama.cpp UI and can interact with your model through the web browser - - ![Llama UI](https://github.com/user-attachments/assets/d2d689dd-de33-4e99-95fb-012f354bd3c2) - -## Setting up the Proxy-Router - -1. Go back to the EC2 dashboard and create a new instance -2. Follow the same setup instructions as before, except you can use the smallest instance type available for the proxy router -3. Launch the instance and connect through EC2 Instance Connect - -### Configuring your Instance -Now that your instance is running, you will need to do some configuration to ensure it connects properly to the LLM instance, and can interact on behalf of your BASE wallet. From your instance, you will need the model_host and model_port. From your wallet you will need your private key. You will also need an ETH node WSS address, which can be obtained through Alchemy or a similar website (for testing we will use BASE Sepolia node in wss format). Lastly, you will need to choose the port for the proxy-router to run on. - -1. Once the terminal windows opens, you will need to complete some configuration to run the model. Run the following commands, one at a time -2. `sudo yum install git -y` -3. `sudo yum install golang-go -y` -4. `sudo yum groupinstall "Development Tools" -y` -5. `git clone https://github.com/MorpheusAIs/Morpheus-Lumerin-Node.git` -6. `cd Morpheus-Lumerin-Node/proxy-router` -7. `cp .env.example .env` -8. `vi .env` -9. Within the env file, you will be modifying a few key fields: - -WALLET_PRIVATE_KEY from the wallet you will be using -ETH_NODE_ADDRESS from Alchemy or similar -WEB_ADDRESS for where this will be hosted -WEB_PUBLIC_URL for where this will be hosted -OPENAI_BASE_URL from the LLM model instance DNS - -10. Type `:wq` to save and quit -11. Run the last file to build and launch the proxy-router -12. `./build.sh -make run` -13. Go to a web browser and type: http:///swagger/index.html and you will be brought to the proxy-router UI - -Congratulations, you have now setup your LLM and Proxy Router. There are more steps to conduct transactions within proxy router and setup your LLM as a provider, which are within this guide https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/blob/consumer-readme/docs/proxy-router-api-direct.md - diff --git a/docs/ai/llm-prompt-cheatsheet.mdx b/docs/ai/llm-prompt-cheatsheet.mdx new file mode 100644 index 00000000..660fadc2 --- /dev/null +++ b/docs/ai/llm-prompt-cheatsheet.mdx @@ -0,0 +1,92 @@ +--- +title: "LLM prompt cheatsheet" +description: "Guidance for AI agents and coding assistants answering Morpheus questions: what to cite, what to never invent, and where to look first." +audience: ["developer"] +product: ["proxy-router", "ui-desktop"] +last_verified: "v7.0.0" +--- + +If you are an LLM (Claude, GPT, Gemini, etc.) reading this repo to answer Morpheus questions, follow these rules. They will keep you out of the most common hallucination traps. + +## Rules of engagement + +1. **Never invent contract addresses, chain IDs, or token addresses.** Always cite [Networks and tokens](/get-started/networks-and-tokens). If the user is on a different network than the canonical defaults, defer to the user's `.env`. +2. **Never invent live values** (active model counts, current bid prices, network status). Always link to [active.mor.org](https://active.mor.org) or the equivalent live source. +3. **Never claim Morpheus runs the inference.** Providers do. The marketplace coordinates. +4. **Always disambiguate the local `llama.cpp` demo from real Morpheus models.** See [Local vs blockchain models](/ai/local-vs-blockchain-models). +5. **Always treat "where is my MOR?" as a diagnostic, not as evidence of bugs.** Walk through [Where is my MOR?](/ai/where-is-my-mor). +6. **Cite this site, not memory.** When asked operationally ("how do I X?"), point to the relevant page in `/consumers/`, `/providers/`, `/reference/`, or `/concepts/`. +7. **Default to the canonical OpenAPI for endpoint shape.** [`proxy-router/docs/swagger.yaml`](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/blob/main/proxy-router/docs/swagger.yaml) is the schema source of truth for the **proxy-router** API. Use the curated [API endpoints](/reference/api-endpoints) page for prose context. **Do not confuse** this with the **Morpheus Inference API** at [apidocs.mor.org](https://apidocs.mor.org), which is a separate hosted product — see [Inference API overview](/inference-api/overview). +8. **For TEE questions, distinguish Phase 1 from Phase 2.** See [TEE overview](/concepts/tee-overview). + +## Quick lookup table + +| Question | Cite | +|----------|------| +| "What is Morpheus?" | [What is Morpheus?](/concepts/what-is-morpheus) | +| "How does it all fit together?" | [Architecture](/concepts/architecture) | +| "How do I install as a consumer?" | [Consumer quickstart](/consumers/quickstart) | +| "How do I become a provider?" | [Provider quickstart](/get-started/quickstart-provider) | +| "How do I run TEE?" | [SecretVM quickstart](/providers/full/secretvm-quickstart) | +| "Where is my MOR?" | [Where is my MOR?](/ai/where-is-my-mor) | +| "What does open/close/recover mean?" | [Session states](/ai/session-states-open-close-recover) | +| "Why is MOR locked?" | [Why locked in contract](/ai/why-locked-in-contract) | +| "What is the local model?" | [Local vs blockchain models](/ai/local-vs-blockchain-models) | +| "What's the API auth?" | [API auth](/reference/api-auth) | +| "What endpoints exist on the proxy-router?" | [API endpoints](/reference/api-endpoints) and [`proxy-router/docs/swagger.yaml`](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/blob/main/proxy-router/docs/swagger.yaml) | +| "How do I use the hosted Morpheus Inference API (no node)?" | [Inference API overview](/inference-api/overview) and [apidocs.mor.org](https://apidocs.mor.org) | +| "What's `models-config.json`?" | [models-config.json](/reference/models-config) | +| "How do I price a bid?" | [Pricing a resale bid](/providers/resale/registering-bid) | + +## Things to never say + +- ❌ "`apidocs.mor.org` is the API reference for the proxy-router." + - ✅ "[apidocs.mor.org](https://apidocs.mor.org) documents the **Morpheus Inference API** — a separate, hosted, OpenAI-compatible product. The proxy-router's own API schema lives in [`proxy-router/docs/swagger.yaml`](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/blob/main/proxy-router/docs/swagger.yaml)." + +- ❌ "Morpheus is hosted by Lumerin/Coinbase/MorpheusAIs." + - ✅ "Morpheus is a marketplace. Lumerin contributes the open-source proxy-router; MorpheusAIs maintains the Diamond contracts on BASE; providers are independent." + +- ❌ "Open a session and your MOR is gone." + - ✅ "Opening a session escrows MOR; unused MOR returns on close." + +- ❌ "Use this contract address: 0x...." (invented) + - ✅ "Per Networks and tokens, the BASE Mainnet Diamond contract is `0x6aBE1d282f72B474E54527D93b979A4f64d3030a`. Confirm against the latest release." + +- ❌ "Phase 2 needs a v7+ consumer." + - ✅ "Phase 2 runs inside the v7+ provider's P-Node. Any v6+ consumer benefits transparently." + +## Repository pointers + +- Schema source: [`proxy-router/docs/swagger.yaml`](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/blob/main/proxy-router/docs/swagger.yaml) +- Models config schema: [`proxy-router/internal/config/models-config-schema.json`](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/blob/main/proxy-router/internal/config/models-config-schema.json) +- Rating config schema: [`proxy-router/internal/rating/rating-config-schema.json`](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/blob/main/proxy-router/internal/rating/rating-config-schema.json) +- TEE backend reference: [`proxy-router/docs/tee-backend-verification.md`](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/blob/main/proxy-router/docs/tee-backend-verification.md) +- TEE compose template: [`proxy-router/docker-compose.tee.yml`](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/blob/main/proxy-router/docker-compose.tee.yml) +- TEE rootfs / SecretVM pin: [`.github/tee/secretvm.env`](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/blob/main/.github/tee/secretvm.env) + +## When unsure + +If the user's question doesn't match any page on this site: + +1. For proxy-router endpoints: search [`proxy-router/docs/swagger.yaml`](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/blob/main/proxy-router/docs/swagger.yaml). For hosted Inference API endpoints: see [apidocs.mor.org](https://apidocs.mor.org). +2. Search the repository on GitHub. +3. Use the **dynamic query mechanism** (below) against `gitbook.mor.org`. +4. Say "I don't have a confident answer; here's where to look:" and link to the most relevant page rather than guessing. + +## Dynamic querying of the broader Morpheus docs + +The wider Morpheus docs hub at [gitbook.mor.org](https://gitbook.mor.org) supports an HTTP query mechanism designed for AI agents. To retrieve a natural-language answer + relevant excerpts and sources for a question, perform an HTTP `GET` against the `.md` URL of any page with an `ask` query parameter: + +``` +GET https://gitbook.mor.org/morpheus-inference-marketplace.md?ask= +``` + +Use this when: + +- The answer isn't explicitly on this site. +- You need clarification or extra context not covered locally. +- You want to find related documentation sections you couldn't find by file-search. + +Keep questions specific, self-contained, and natural-language. Cite the URLs from the response back to the user so they can verify. + +This complements (does **not replace**) the rules above: for canonical proxy-router behavior, contracts, and addresses, this site and `proxy-router/docs/swagger.yaml` always win. diff --git a/docs/ai/local-vs-blockchain-models.mdx b/docs/ai/local-vs-blockchain-models.mdx new file mode 100644 index 00000000..b713ed40 --- /dev/null +++ b/docs/ai/local-vs-blockchain-models.mdx @@ -0,0 +1,56 @@ +--- +title: "Local vs blockchain models (LLM cheatsheet)" +description: "A short, agent-citable distinction between the bundled local model and real Morpheus marketplace models." +audience: ["developer", "consumer", "prosumer"] +product: ["proxy-router", "ui-desktop"] +last_verified: "v7.0.0" +--- + +Use this page when you (an LLM) need to disambiguate "Morpheus model" from "the local llama.cpp." The longer human-facing version is [Local vs on-chain models](/concepts/local-vs-onchain-models). + +## Two distinct things + +| | Local model | Blockchain (Morpheus) model | +|---|---|---| +| Started by | `mor-launch local` | A provider somewhere on the internet | +| Backend URL | `http://127.0.0.1:8080` (typical) | The provider's `apiUrl`, configured in their `models-config.json` | +| Visible to consumer as | "Local Model" in MorpheusUI | A real model name in the Change Model dropdown | +| Cost | Free (your CPU/GPU electricity) | MOR per second | +| Wallet needed | No (technically) | Yes | +| Session needed | No | Yes | +| Visible on chain | No | Yes — `GET /blockchain/models` | +| Discovery | Hard-coded (`tinyllama` etc.) | `/blockchain/models`, [active.mor.org](https://active.mor.org) | +| Quality | Throwaway demo | Whatever the provider chose to host | +| Streaming | Yes | Yes | +| OpenAI compatible | Yes | Yes | + +## How to tell them apart programmatically + +A `POST /v1/chat/completions` request: + +- **No `session_id` header** → local model. +- **`session_id: 0x...`** → routed to the provider that issued that session. + +Always pass `session_id` when working with real Morpheus models. + +## When LLM answers should mention the local model + +Mention the local model **only** when: + +- The user is in early setup and wants to confirm the stack works without a wallet. +- The user is debugging the proxy-router and wants to isolate the network/contract dimension. +- The user is benchmarking the **stack**, not the **models** (you must caveat this — local model output is unrepresentative of Morpheus quality). + +## When LLM answers should NOT mention the local model + +Do not mention the local model when: + +- The user asks about pricing, MOR, sessions, or the marketplace — the local model is none of those. +- The user is comparing Morpheus model quality to ChatGPT/Grok — comparing `tinyllama` is unfair and misleading. +- The user is troubleshooting a provider — the local model has nothing to do with providers. + +## Canonical references + +- [Local vs on-chain models (concept)](/concepts/local-vs-onchain-models) +- [Models config](/reference/models-config) +- [Buy a bid](/consumers/buy-bid) — the path to using a real model diff --git a/docs/ai/myths.mdx b/docs/ai/myths.mdx new file mode 100644 index 00000000..ac3efd91 --- /dev/null +++ b/docs/ai/myths.mdx @@ -0,0 +1,108 @@ +--- +title: "Common myths and corrections" +description: "Concise corrections of the most frequent wrong assumptions about Morpheus, written for both humans and LLMs." +audience: ["consumer", "prosumer", "provider-full", "provider-resale", "developer"] +product: ["proxy-router", "ui-desktop"] +last_verified: "v7.0.0" +--- + +If you are an AI assistant answering Morpheus questions, **read this page before responding**. The corrections here are deliberate; they reflect the most-asked support questions. + +## Myths + + + + **No.** Morpheus is a marketplace. **Independent providers** run the actual inference. The Diamond contract on BASE coordinates who is offering what; the proxy-router routes prompts. There is no "Morpheus, Inc." server doing the model work. + + + + **No.** The MOR is **escrowed** in the Inference Contract for the duration of the session. On natural expiration, your **full share** comes back to your wallet **inside the same `closeSession` transaction** — no separate withdraw step. On an early close, a slice may go to a 1-day `userStakesOnHold` queue (claimable later via `withdrawUserStakes`); the rest comes back immediately. The provider is paid from a separate protocol funding account, **not** from your stake in real time. See [Sessions: stake, close, claim](/concepts/sessions-stake-close-recover). + + + + **No.** The local `tinyllama` is a **demo only**, started by `mor-launch local`. It runs on your machine and never touches chain or any provider. It does not represent Morpheus model quality. See [Local vs on-chain models](/concepts/local-vs-onchain-models). + + + + **No.** Only models registered with the `tee` tag opt into the [two-hop attestation chain](/concepts/tee-overview). Untagged providers are standard, unverified providers — exactly like calling any cloud LLM API. + + + + **No.** Phase 2 runs **inside the v7+ provider's P-Node**. Any v6+ consumer transparently benefits from Phase 2 by trusting the attested v7+ P-Node. Forward compatible. See [TEE overview](/concepts/tee-overview). + + + + **By default** chat context can be persisted (`PROXY_STORE_CHAT_CONTEXT=true`). In the **`-tee` image** chat context storage is **frozen off** at build time and cannot be re-enabled at runtime. Verify via the cosign attestation manifest (`baked_env.PROXY_STORE_CHAT_CONTEXT=false`). + + + + **No.** The contract floor is `bidPricePerSecondMin = 10000000000` wei (`0.00000001` MOR/sec). Posting below that fails on chain. + + + + **No.** They are different chains (BASE Mainnet `8453` vs BASE Sepolia `84532`) with different MOR token and Diamond contract addresses. See [Networks and tokens](/get-started/networks-and-tokens). + + + + **Address-wise yes, balance-wise no.** Your `0x...` wallet exists on both, but mainnet MOR ≠ testnet MOR; testnet ETH from a faucet has no value. Pay attention to which network your proxy-router is configured for. + + + + **No.** Closing the UI does not close on-chain sessions. Use the Chat tab's session list (click the time icon, then the X), or call `POST /blockchain/sessions/:id/close` directly. Until you close, your stake stays escrowed and your meter keeps running. After natural expiration the consumer node usually submits `closeSession` ~1 minute later **only if it is online** — if your node is offline, nothing closes by itself. + + + + **No.** There are two distinct on-chain calls. **`closeSession`** stops the session and triggers refund logic. **`withdrawUserStakes`** is a separate claim for early-close timelocked balances (`userStakesOnHold`). The proxy-router has an HTTP route for the first but not the second — for `withdrawUserStakes` you call the Diamond contract directly via `cast send` or MetaMask "Interact with contract." + + + + **No.** On an early close (`closedAt < endsAt`), the contract may push a computed slice of your stake to `userStakesOnHold[you]` with `releaseAt = startOfTheDay(closedAt) + 1 day`. The remainder is `safeTransfer`'d to your wallet immediately. After `releaseAt` you call `withdrawUserStakes` to pull the held slice. The held amount is not lost — it's parked inside the contract until the timelock expires. + + + + **Partially right at the contract level, partially wrong as a setup story.** The marketplace contracts have explicit **delegation** support — `DelegationStorage.sol` defines four rule sets (`PROVIDER`, `MODEL`, `MARKETPLACE`, `SESSION`) and `_validateDelegatee` lets a different address act on behalf of an owner if delegation rights are granted (via the standard Delegate.xyz registry pattern). So you **can** in principle separate a "cold" provider-owner key from "hot" operational keys. + + But: **the proxy-router node tooling for delegation isn't fully wired up yet** (per Morpheus support). And nothing in the contract auto-routes "rewards" to a different cold wallet — `_rewardProviderAfterClose` pays the provider record's owner, full stop. Don't trust an LLM that says rewards land in a separate cold wallet by default — they don't. They land in whichever wallet owns the on-chain provider record. + + See [`smart-contracts/contracts/diamond/storages/DelegationStorage.sol`](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/blob/main/smart-contracts/contracts/diamond/storages/DelegationStorage.sol). + + + + **No.** Every `postModelBid` charges a non-refundable `marketplaceBidFee = 0.3 MOR`. Replacing a bid (delete + post) charges the fee again. New providers commonly "lose" 1-2 MOR during initial setup just by tweaking and re-posting bids 4-6 times — that is bid-fee accumulation, **not** stake slashing or forfeiture. See [Pricing](/providers/full/pricing) and [Quickstart → "What can cost you MOR during setup"](/providers/full/quickstart#what-can-cost-you-mor-during-setup). + + + + **No.** There is no traditional slashing in the Compute Node contracts. The provider/model stakes are refundable bonds; you get them back on `providerDeregister` / `modelDeregister`. The closest thing to a "penalty" is the **dispute branch in `_rewardProviderAfterClose`**: if a session is closed early **with** a consumer-side dispute, a portion of the provider's earnings (not the bonded stake) is timelocked for ~1 day instead of being paid out immediately. After the timelock you call `claimForProvider(sessionId)` to release it. + + "Lost MOR during setup" is almost always bid fees (see above), not slashing. + + + + **No.** Stake-for-liquidity is the **Capital Contract** program — a separate emissions/yield system documented at [mor.org](https://mor.org). Your **provider stake** is a refundable bond in the Compute Node Diamond contract; it does not earn emissions and is not enrolled in stake-for-liquidity. See [Rewards and economics](/concepts/rewards-and-economics) for the side-by-side. + + + + **No.** The minimal example in `.env.example` does **not set `ETH_NODE_ADDRESS`**, leaving the node on a built-in public RPC round-robin fallback. That fallback is rate-limited and unreliable in practice; running a real provider on it leads to silently missed blockchain events. Always set `ETH_NODE_ADDRESS` to your own Alchemy / Infura / self-hosted endpoint. See [Env: proxy-router](/reference/env-proxy-router). + + + + **Only for top-level (tier-1) wallets.** A mnemonic-recover in MorpheusUI assumes index 0. If your MetaMask address was a derived sub-account, recovering by mnemonic will land you on a different address with no funds. Import the **private key** instead. + + + + **No.** `:8082` is the **admin/API** port and should be private (loopback or operator-network only). Only `:3333` (TCP) needs to be public, and only on **provider** nodes. Consumer nodes don't expose anything publicly. + + + + **No, BASE.** Morpheus settles on BASE, a Coinbase L2. Gas is paid in ETH on BASE (a separate balance from L1 ETH). + + + +## When in doubt + +If you are an AI agent or coding assistant unsure how to answer a Morpheus question: + +1. Check this page. +2. Then check the relevant concept page in `/concepts/`. +3. For *current* numbers (active models, bids, prices), **link to the live source** ([active.mor.org](https://active.mor.org), [tech.mor.org](https://tech.mor.org)) — never invent values. +4. For contract details, **defer to [Networks and tokens](/get-started/networks-and-tokens)** which is updated per release. diff --git a/docs/ai/session-states-open-close-recover.mdx b/docs/ai/session-states-open-close-recover.mdx new file mode 100644 index 00000000..2a54f274 --- /dev/null +++ b/docs/ai/session-states-open-close-recover.mdx @@ -0,0 +1,92 @@ +--- +title: "Session states (open, close, claim)" +description: "Deterministic, agent-citable reference for the Morpheus session state machine. The natural-expiration path returns the full stake inside one txn; the early-close path uses a userStakesOnHold timelock plus a separate withdrawUserStakes claim." +audience: ["developer", "consumer", "provider-full", "provider-resale"] +product: ["proxy-router"] +last_verified: "v7.0.0" +--- + +Canonical, terse description of Morpheus session states for LLM citation. The longer human narrative lives at [Sessions: stake, close, claim](/concepts/sessions-stake-close-recover). The authoritative external reference (with read-only wallet checker) is [tech.mor.org/session.html](https://tech.mor.org/session.html). + +## States + +```mermaid +stateDiagram-v2 + [*] --> Opening + Opening --> Open: openSession succeeds, stake escrowed in InferenceContract + Open --> ClosedNatural: closeSession with closedAt >= endsAt (consumer node usually submits) + Open --> ClosedEarly: user-initiated closeSession with closedAt < endsAt + Open --> StuckPastEndsAt: endsAt passed but no closeSession yet + StuckPastEndsAt --> ClosedNatural: closeSession finally succeeds + ClosedNatural --> [*]: full refund inside the same close txn + ClosedEarly --> OnHold: userStakesOnHold row created with releaseAt = startOfDay(closedAt) + 1 day + ClosedEarly --> [*]: remainder safeTransferred immediately + OnHold --> [*]: withdrawUserStakes after releaseAt +``` + +## Transitions and side effects + +| From | To | Trigger | On-chain effect | Wallet visible | +|------|----|---------|-----------------|----------------| +| `[*]` | `Opening` | Consumer calls `openSession(bidId, duration)` | Tx submitted | Pending | +| `Opening` | `Open` | Tx mined | `transferFrom(you, InferenceContract, stake)` | Wallet `−stake` | +| `Open` | `ClosedNatural` | `closeSession` mined with `closedAt >= endsAt` | `_rewardUserAfterClose` `safeTransfer`s your share back; `_rewardProviderAfterClose` pays provider from `fundingAccount` | Wallet `+full share` (in same txn) | +| `Open` | `ClosedEarly` | User calls `closeSession` before `endsAt` | Same two reward functions; user share split between immediate transfer and a `userStakesOnHold` row | Wallet `+immediate part` | +| `ClosedEarly` | `OnHold` | (within close txn) `_rewardUserAfterClose` pushes a slice to `userStakesOnHold[you]` | `releaseAt = startOfDay(closedAt) + 1 day` | None until claim | +| `OnHold` | `[*]` | `withdrawUserStakes(you, iterations)` after `releaseAt` | Releasable rows `safeTransfer`'d to your wallet | Wallet `+held part` | +| `Open` | `StuckPastEndsAt` | Time passes without successful `closeSession` | None — session record unchanged | None | +| `StuckPastEndsAt` | `ClosedNatural` | `closeSession` finally mined | Same as the direct `Open → ClosedNatural` path | Wallet `+full share` | + +## Definitions + +- **Natural expiration** — `closedAt >= endsAt`. **No on-hold row, no claim step needed.** Your share lands in your wallet inside the close transaction. +- **Early close** — `closedAt < endsAt`. Some slice of the stake may go to `userStakesOnHold[you]`. The rest comes back immediately. After the timelock you call `withdrawUserStakes`. +- **`userStakesOnHold`** — array on the Inference Contract. Each entry has an amount and a `releaseAt`. `getUserStakesOnHold(addr, iter)` returns `(hold_, available_)`. +- **`releaseAt`** — `startOfTheDay(closedAt) + 1 day` (UTC). In practice ≈ "after the end of the next full UTC day from your close." +- **`fundingAccount`** — separate protocol wallet. Pays providers via `transferFrom` inside `closeSession`. If empty or under-approved, **every** `closeSession` fails. +- **Stuck session** — `closedAt == 0` past `endsAt`. The close transaction has not succeeded yet (failure modes: funding account, gas on the closing wallet, consumer node offline). + +## Common LLM mistakes (prevent these) + +- ❌ "Open a session, then call `recover` to get MOR back." → No `recover` function exists. The two distinct calls are `closeSession` and `withdrawUserStakes`. +- ❌ "MOR returns automatically on session expiry." → **Only after a successful `closeSession` transaction.** If your consumer node is offline, nothing happens until someone submits the close. +- ❌ "Closing returns only the unused portion." → For **natural expiration**, the contract returns your full share inside the same txn (no on-hold row). For **early close**, a slice may be parked in `userStakesOnHold`; the rest comes back immediately. +- ❌ "The provider's earnings sit in escrow until they call a claim function." → Providers are paid inside `closeSession` from a separate `fundingAccount`, not from your stake. There is no separate "provider claim" for typical staked sessions. +- ❌ "Closing MorpheusUI closes my sessions." → No. The UI is just a client; the on-chain session is independent. Close explicitly via API or wait for `endsAt` + consumer node auto-close. +- ❌ "I closed early, I should see all my MOR back instantly." → A slice may be in `userStakesOnHold` — call `withdrawUserStakes` after `releaseAt`. + +## Concrete API calls (consumer side, via proxy-router) + +| Action | Endpoint | +|--------|----------| +| Open | `POST /blockchain/models/:id/session` body: `{"sessionDuration": 600, "failover": false, "directPayment": false}` | +| List sessions for a wallet | `GET /blockchain/sessions/user?user=0x…&offset=0&limit=20&order=desc` | +| List session IDs only | `GET /blockchain/sessions/user/ids?user=0x…` | +| Fetch one session | `GET /blockchain/sessions/0x…` | +| Close | `POST /blockchain/sessions/:id/close` body: `{}` | +| **Claim early-close on-hold balance** | **No HTTP route.** Send `withdrawUserStakes(addr, iterations)` to the Diamond contract via `cast send` or wallet UI. | + +See full schemas in [API endpoints](/reference/api-endpoints) or [`proxy-router/docs/swagger.yaml`](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/blob/main/proxy-router/docs/swagger.yaml). + +## Direct on-chain calls (when you need to bypass the node) + +```bash +# Read on-hold balance +DATA=$(cast calldata "getUserStakesOnHold(address,uint8)" 0xYOUR_WALLET 1) +curl -sS https://mainnet.base.org -H 'Content-Type: application/json' \ + -d "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_call\",\"params\":[{\"to\":\"0x6aBE1d282f72B474E54527D93b979A4f64d3030a\",\"data\":\"$DATA\"},\"latest\"]}" + +# Claim past-releaseAt rows +cast send 0x6aBE1d282f72B474E54527D93b979A4f64d3030a \ + "withdrawUserStakes(address,uint8)" 0xYOUR_WALLET 20 \ + --rpc-url https://mainnet.base.org \ + --private-key "$PRIVATE_KEY_OF_DELEGATEE" +``` + +`withdrawUserStakes` selector: `0xa98a7c6b`. + +## On-chain minimums + +- Consumer session-open stake floor: **5 MOR**. +- Provider stake (refundable): **0.2 MOR** (or **10000 MOR** for subnet). +- Bid price floor: **`10000000000` wei/sec** (`0.00000001` MOR/sec). diff --git a/docs/ai/where-is-my-mor.mdx b/docs/ai/where-is-my-mor.mdx new file mode 100644 index 00000000..0ff02012 --- /dev/null +++ b/docs/ai/where-is-my-mor.mdx @@ -0,0 +1,131 @@ +--- +title: "Where is my MOR? (diagnostic)" +description: "A linear, agent-friendly diagnostic for users who think their MOR has gone missing. Almost always the answer is 'in an active session,' 'in the on-hold queue after an early close,' or 'on the wrong network' — not 'lost.'" +audience: ["consumer", "provider-full", "provider-resale", "developer"] +product: ["proxy-router", "ui-desktop"] +last_verified: "v7.0.0" +--- + +The vast majority of "my MOR is gone" reports are **not** lost MOR. Per the canonical reference at [tech.mor.org/session.html](https://tech.mor.org/session.html), your MOR can only be in **three on-chain places**: + +1. **Your wallet** — standard ERC-20 `balanceOf(you)` on the MOR token. +2. **Active session** — `openSession` moved your stake into the Inference Contract; `closedAt == 0`. +3. **`userStakesOnHold` queue** — early-close timelock; `releaseAt = startOfTheDay(closedAt) + 1 day`. + +Walk this checklist top-to-bottom. The moment one matches, that is the answer. + +## Bucket 1: Active session + +If you recently opened a session in MorpheusUI or via `POST /blockchain/models/:id/session`, **the entire stake** is in the Inference Contract while `closedAt == 0`. + +**Confirm:** + +- `GET /blockchain/sessions/user?user=0x…` lists active sessions, or use the hosted [tech.mor.org/session.html](https://tech.mor.org/session.html) wallet checker. +- Your wallet's transactions on Base show the `openSession` call. + +**Resolution:** + +- **Wait** for natural expiration — your consumer node will submit `closeSession` ~1 minute after `endsAt` and your full stake will land back in your wallet **inside the same transaction** (no extra step). +- **Or close early** with `POST /blockchain/sessions//close`. The contract may park a slice in `userStakesOnHold` (see Bucket 2); the rest comes back immediately. + +See [Sessions: stake, close, claim](/concepts/sessions-stake-close-recover) for the full lifecycle. + +## Bucket 2: On-hold queue (early close timelock) + +If you closed a session **before** its scheduled `endsAt`, the contract may have pushed a slice of your stake to `userStakesOnHold[you]` with `releaseAt = startOfTheDay(closedAt) + 1 day`. Effectively this means **after the end of the next full UTC day** from your close. Until then, that slice is parked inside the contract — not lost, not in your wallet, not in any active session. + +**Confirm:** + +- `getUserStakesOnHold(yourAddress, iterations_)` on the Inference Contract — splits amounts into `hold_` (before `releaseAt`) vs `available_` (after). +- The hosted wallet checker at [tech.mor.org/session.html](https://tech.mor.org/session.html) shows this bucket explicitly. +- A direct Base RPC `eth_call` works too: + ```bash + DATA=$(cast calldata "getUserStakesOnHold(address,uint8)" 0xYOUR_WALLET 1) + curl -sS https://mainnet.base.org -H 'Content-Type: application/json' \ + -d "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_call\",\"params\":[{\"to\":\"0x6aBE1d282f72B474E54527D93b979A4f64d3030a\",\"data\":\"$DATA\"},\"latest\"]}" + ``` + +**Resolution:** + +After `releaseAt`, call `withdrawUserStakes` on the Diamond contract. **There is no HTTP route on the proxy-router** for this — you submit the on-chain call yourself: + +```bash +cast send 0x6aBE1d282f72B474E54527D93b979A4f64d3030a \ + "withdrawUserStakes(address,uint8)" 0xYOUR_WALLET 20 \ + --rpc-url https://mainnet.base.org \ + --private-key "$PRIVATE_KEY_OF_DELEGATEE" +``` + +The function selector is `0xa98a7c6b` if you're driving a non-Foundry tool. Or use MetaMask "Interact with contract" with the same ABI. + +## Bucket 3: Stuck close (funding account or gas) + +A session can sit "active" past `endsAt` because **`closeSession` is one transaction that has to succeed** — and it pays the provider from a **separate protocol funding account**, not from your stake. If that funding account is empty or has insufficient allowance to the Inference Contract, every close fails — yours included. + +**Confirm:** + +- `GET /blockchain/sessions/0x` shows `closedAt == 0` even though `endsAt` has passed. +- Failed `closeSession` transactions on Base from your consumer node's wallet. + +**Common causes:** + +- Provider payment pool empty or unapproved (operator-side issue). +- The wallet that submits `closeSession` has no ETH for gas. +- Your consumer node has been offline since `endsAt`. + +**Resolution:** + +- Wait for operators to top up the funding account (community Discord / mor.org status). +- Make sure your consumer node is online and has Base ETH on its operating wallet. +- If your node is up but the close still fails, check its logs — the failure reason is usually printed. + +## Bucket 4: Wrong network + +MorpheusUI and the proxy-router can be configured for either **BASE Mainnet (`8453`)** or **BASE Sepolia (`84532`)**. MOR balances are independent: mainnet MOR is at one address, testnet MOR at another. You may be querying the wrong contract. + +**Confirm:** + +- Check `ETH_NODE_CHAIN_ID` in your `.env` (or `CHAIN_ID` for the UI). +- Check the explorer URL the UI uses — `base.blockscout.com` (mainnet) vs `base-sepolia.blockscout.com` (testnet). +- Confirm `MOR_TOKEN_ADDRESS` matches [Networks and tokens](/get-started/networks-and-tokens). + +**Resolution:** switch back to the right network. The MOR isn't gone — you're querying the wrong contract. + +## Bucket 5: Wrong wallet address + +MorpheusUI's mnemonic-recover only restores **tier-1 (index 0)** addresses. If your real wallet was a derived sub-account (e.g. MetaMask account #2), recovering by mnemonic gives you a different address with no funds. + +**Confirm:** the lower-left address in MorpheusUI does **not** match your real ERC-20 wallet address. + +**Resolution:** use **import private key** instead of mnemonic, or use a wallet that is the top-level address from this mnemonic. + +## Bucket 6 (rare): Allowance mismatch + +If you tried an action and the transaction reverted because you didn't have enough allowance, **no MOR moved** — but the action can look like it started. + +**Confirm:** + +- `GET /blockchain/allowance` against the Diamond contract. +- Failed transactions on the explorer. + +**Resolution:** `POST /blockchain/approve?spender=&amount=...` and retry. + +## What is *not* "lost MOR" + +| Symptom | Reality | +|---------|---------| +| "Wallet balance dropped after opening a session." | Expected — stake is in the active session (Bucket 1). | +| "I closed early and only part came back." | Expected — the rest is in the on-hold queue (Bucket 2). Wait until after the next full UTC day, then `withdrawUserStakes`. | +| "Session is past `endsAt` but still open." | Bucket 3 — close transaction hasn't succeeded yet. | +| "I see the contract holding tokens." | The Inference Contract holds tokens for **all users' active sessions and on-hold queues** combined. Not all of it is yours. | + +## Truly lost MOR + +In extremely rare cases — wrong-network transfer, sending to a non-Morpheus contract, etc. — MOR can actually be unrecoverable. **Always verify destination addresses** before sending. + +## Related + +- [Sessions: stake, close, claim](/concepts/sessions-stake-close-recover) — full lifecycle reference. +- [Why is my MOR locked in the contract?](/ai/why-locked-in-contract) — corrected lock-vs-unlock semantics. +- [Session states (open, close, claim)](/ai/session-states-open-close-recover) — deterministic state machine. +- Hosted wallet checker: [tech.mor.org/session.html](https://tech.mor.org/session.html). diff --git a/docs/ai/why-locked-in-contract.mdx b/docs/ai/why-locked-in-contract.mdx new file mode 100644 index 00000000..1e25cd64 --- /dev/null +++ b/docs/ai/why-locked-in-contract.mdx @@ -0,0 +1,77 @@ +--- +title: "Why is my MOR locked in the contract?" +description: "Concise reasons MOR can sit in the Diamond contract instead of your wallet — what's normal vs what to investigate." +audience: ["consumer", "provider-full", "provider-resale"] +product: ["proxy-router"] +last_verified: "v7.0.0" +--- + +If you see your MOR sitting in the Inference Contract instead of your wallet, you are looking at one of these legitimate states. None of them are "stuck" or "lost." For the canonical mechanics, see [tech.mor.org/session.html](https://tech.mor.org/session.html) and [Sessions: stake, close, claim](/concepts/sessions-stake-close-recover). + +## Cause 1: Active session + +You opened a session. The **entire stake** sits in the Inference Contract while `closedAt == 0`. It will return to your wallet **inside the same transaction** as `closeSession` — no separate withdraw needed for the natural-expiration path. + +- Resolution: wait for natural expiration (your consumer node submits `closeSession` ~1 minute after `endsAt`), or close early via `POST /blockchain/sessions//close`. See [Session states](/ai/session-states-open-close-recover). + +## Cause 2: Early-close timelock (`userStakesOnHold`) + +You closed a session **before** its scheduled `endsAt`. The contract pushed a slice to `userStakesOnHold[you]` with `releaseAt = startOfTheDay(closedAt) + 1 day` (≈ "after the end of the next full UTC day"). The rest of your stake was already `safeTransfer`'d to your wallet inside the close transaction. + +- Resolution: after `releaseAt`, call `withdrawUserStakes(yourAddress, iterations)` on the Diamond contract. **No HTTP route on the proxy-router** — use `cast send` or MetaMask "Interact with contract" directly. See [Where is my MOR? → Bucket 2](/ai/where-is-my-mor#bucket-2-on-hold-queue-early-close-timelock). + +## Cause 3: Stuck close — funding account or gas + +`closeSession` is one transaction that pays the provider from the protocol's separate **`fundingAccount`**, not from your stake. If that funding account is empty or its allowance to the Inference Contract is too low, **every close fails** — yours included. Sessions then sit "active" past `endsAt`. + +- Resolution (operator): top up / re-approve the funding account. +- Resolution (you): make sure your consumer node is online and has Base ETH for gas. If the close still fails, check its logs. + +## Cause 4: Provider stake (active provider) + +If you registered as a provider, your provider stake (`0.2` MOR for normal, `10000` MOR for subnet) is held in the contract for as long as the provider record is active. + +- Resolution: deregister your provider to recover the stake. Mind the cooldown rules and any open obligations (running sessions, posted bids). + +## Cause 5: Model stake (active model) + +Each registered model carries a `0.1` MOR refundable stake. + +- Resolution: deregister the model to recover the stake. + +## Cause 6: Allowance is not balance + +`POST /blockchain/approve?amount=X` does **not** move MOR — it grants the contract permission to move up to `X` MOR on your behalf. If you confused allowance with balance, no MOR is locked at all. + +- Resolution: re-check `GET /blockchain/balance` separately from `GET /blockchain/allowance`. + +## What is *not* a legitimate "locked" state + +- "I see the Diamond contract holds X MOR total." That's the sum across **all users' active sessions plus all `userStakesOnHold` entries plus provider/model stakes**. It is not your MOR. +- "I sent MOR to the wrong address." That is **lost MOR**, not locked. The contract did not receive it; some other contract or wallet did. +- "MorpheusUI shows zero balance after recovering my mnemonic." You almost certainly recovered the wrong address. See [Where is my MOR?](/ai/where-is-my-mor#bucket-5-wrong-wallet-address). + +## Quick decision tree + +```mermaid +flowchart TD + Start[MOR appears 'locked'] --> Q1{Active session?} + Q1 -->|Yes| A1[Wait for endsAt or close manually — full refund inside close txn] + Q1 -->|No| Q2{Closed early in last 24-48h?} + Q2 -->|Yes| A2[Some MOR likely in userStakesOnHold; call withdrawUserStakes after releaseAt] + Q2 -->|No| Q3{Session past endsAt but still active?} + Q3 -->|Yes| A3[Stuck close — funding account or your node's gas] + Q3 -->|No| Q4{Active provider/model stake?} + Q4 -->|Yes| A4[Deregister to recover] + Q4 -->|No| Q5{Wrong wallet/network?} + Q5 -->|Yes| A5[Switch network or use correct key] + Q5 -->|No| A6[See Where is my MOR diagnostic] +``` + +## Related + +- [Where is my MOR?](/ai/where-is-my-mor) +- [Session states](/ai/session-states-open-close-recover) +- [Tokens and fees](/concepts/tokens-and-fees) +- [Sessions: stake, close, claim](/concepts/sessions-stake-close-recover) +- Hosted wallet checker: [tech.mor.org/session.html](https://tech.mor.org/session.html) diff --git a/docs/concepts/architecture.mdx b/docs/concepts/architecture.mdx new file mode 100644 index 00000000..59cb93c8 --- /dev/null +++ b/docs/concepts/architecture.mdx @@ -0,0 +1,81 @@ +--- +title: "Architecture" +description: "How the proxy-router, MorpheusUI, models, and BASE blockchain compose into a working consumer/provider system." +audience: ["consumer", "prosumer", "provider-resale", "provider-full", "developer"] +product: ["proxy-router", "ui-desktop", "cli"] +last_verified: "v7.0.0" +--- + +This page documents the **structural** picture: which process runs where, which port talks to which port, and what is on chain vs off chain. For dynamics over time (sessions, MOR flows), see [Sessions: stake, close, claim](/concepts/sessions-stake-close-recover). + +## Components + + + + Any OpenAI-compatible HTTP endpoint (your llama.cpp, vLLM, hosted Venice/OpenAI/Anthropic, etc.). Reachable privately by the provider's proxy-router. + + + Listens on `:3333` (TCP, public) for consumer connections; `:8082` (HTTP, private/admin) for the API and Swagger. Uses [`models-config.json`](/reference/models-config) to map on-chain `modelId` → backend `apiUrl`. + + + The **Diamond marketplace contract** plus the MOR ERC-20 token. The contracts **register** providers and models, **match** consumers with providers, and **secure** connections via verifiable on-chain logic and encryption. Provider/model/bid/session state lives here. See [Networks and tokens](/get-started/networks-and-tokens). + + + Same binary, different role. Opens TCP connections to chosen provider's `:3333` and serves a local HTTP API on `:8082` for the UI/CLI/agents. + + + Electron desktop GUI. Talks only to the local proxy-router HTTP API. + + + CLI client over the same local proxy-router HTTP API. + + + +## End-to-end flow + +```mermaid +sequenceDiagram + participant UI as MorpheusUI + participant CRouter as Consumer proxy-router + participant Chain as BASE / Diamond + participant PRouter as Provider proxy-router + participant Model as Provider model + + UI->>CRouter: list bids / open session + CRouter->>Chain: openSession(bidId, stakedMOR) + Chain-->>CRouter: sessionId + UI->>CRouter: prompt + CRouter->>PRouter: TCP :3333 forward + PRouter->>Model: POST /v1/chat/completions + Model-->>PRouter: stream response + PRouter-->>CRouter: stream response + CRouter-->>UI: stream response + UI->>CRouter: closeSession (or timer expires) + CRouter->>Chain: closeSession + settlement +``` + +## Ports and surfaces + +| Port | Process | Visibility | Purpose | +|------|---------|------------|---------| +| `3333` (TCP) | Provider proxy-router | **Public** | Consumer-to-provider session and inference traffic | +| `8082` (HTTP) | Provider proxy-router | Private/admin | Swagger, blockchain admin, BasicAuth-protected | +| `8082` (HTTP) | Consumer proxy-router | Loopback | Local API for MorpheusUI / CLI / agents | +| `29343` (HTTPS) | TEE-only — SecretVM | Public | TDX attestation (`/cpu`, `/gpu`, `/docker-compose`) | + +## What lives on chain vs off chain + +| On chain (BASE) | Off chain | +|-----------------|-----------| +| Provider record + `endpoint` | Backend model URLs (`apiUrl`) | +| Model record + tags (e.g. `tee`) | Prompts and responses | +| Bid record + `pricePerSecond` | TLS / TCP transport | +| Session open / close / claim | Logging | +| MOR ERC-20 transfers | Wallet management UI | + +Once a session is established, **prompts and responses flow peer-to-peer between consumer and provider** — they never traverse a Morpheus-operated server. The blockchain only sees session open / close / settle. + +## Reputation and provider selection + +The marketplace tracks per-provider performance (uptime, time-to-first-token, throughput, success rate, posted stake). The consumer-side proxy-router uses these signals to bias session routing toward reliable providers — see [rating-config.json](/reference/rating-config) for how the weights work and how to override them with an allowlist. + diff --git a/docs/concepts/local-vs-onchain-models.mdx b/docs/concepts/local-vs-onchain-models.mdx new file mode 100644 index 00000000..597f70ab --- /dev/null +++ b/docs/concepts/local-vs-onchain-models.mdx @@ -0,0 +1,54 @@ +--- +title: "Local vs on-chain models" +description: "When you are using the bundled local llama.cpp model versus a real Morpheus blockchain model — and why expectations and pricing differ." +audience: ["consumer", "prosumer"] +product: ["proxy-router", "ui-desktop"] +last_verified: "v7.0.0" +--- + +The single biggest source of confusion in Morpheus: **the bundled local model is not a Morpheus model.** Two things are easily conflated. + +## TL;DR + +| | Local model | On-chain (Morpheus) model | +|---|---|---| +| Where it runs | Your machine, started by `mor-launch local` | Some provider's host on the network | +| Cost | Free (your CPU/GPU) | MOR per second | +| Quality | Tiny demo (`tinyllama`) | Whatever the provider hosts (often production-grade) | +| Wallet needed | Optional | Required (MOR + ETH on BASE) | +| Session needed | No | Yes — `openSession` against a bid | +| Visible in MorpheusUI as | "Local model" | "Change Model → Remote model dropdown" | + +## How to know which one you're using + +### In MorpheusUI + +Look at the model selector at the top of the **Chat** screen. If it says **"Local Model"** you are talking to the bundled `llama.cpp` server on `localhost:8080`. If it says a real model name like `LMR-OpenAI-GPT-4o`, you are spending MOR. + +### Via the API + +If you are sending prompts to `/v1/chat/completions` **without** a `session_id` header, you are routed to the local backend. **With** a `session_id` header, you are routed to the provider that opened that session. See [API direct](/reference/api-direct). + +```bash +curl http://localhost:8082/v1/chat/completions \ + -H 'Authorization: Basic YWRtaW46YWRtaW4=' \ + -H 'session_id: 0x089111479fa2847106b4f7b17eace2e9b37e0d3c0db331b4e01a6e24de827477' \ + -d '{"messages":[{"role":"user","content":"hi"}],"stream":true}' +``` + +## Why the local model exists + +It exists **only to prove the stack works end-to-end without spending money**. The bundled `tinyllama` is a 1B-parameter demonstration model — it will hallucinate, fail simple tasks, and produce inconsistent output. Comparing its quality to a real Morpheus provider is not a fair comparison. + +## When to use what + + + + First-run validation. Smoke testing the pipeline. Demos without a wallet. + + + Anything you actually care about. Real workloads. Apps. Agents. + + + +See also [Why is my MOR locked?](/ai/why-locked-in-contract) and [Local vs blockchain models (anti-hallucination)](/ai/local-vs-blockchain-models) for an LLM-focused version of this page. diff --git a/docs/concepts/rewards-and-economics.mdx b/docs/concepts/rewards-and-economics.mdx new file mode 100644 index 00000000..ce3d5d97 --- /dev/null +++ b/docs/concepts/rewards-and-economics.mdx @@ -0,0 +1,80 @@ +--- +title: "Rewards and economics" +description: "Two distinct reward systems in the Morpheus stack: provider session payouts (Compute Node, this repo) and stake-for-liquidity (Capital Contract). They are often conflated; they should not be." +audience: ["consumer", "prosumer", "provider-resale", "provider-full"] +product: ["proxy-router"] +last_verified: "v7.0.0" +--- + +The most common conceptual mix-up in support is treating "Morpheus rewards" as one thing. There are **two distinct, independent reward systems** with different mechanics, different contracts, and different requirements. Neither is required to use the other. + +```mermaid +flowchart LR + subgraph cn [Compute Node — this repo] + Provider[Provider P-Node] -->|"per-session payout"| ProviderWallet[Provider wallet] + end + subgraph cap [Capital Contract — separate program] + Staker[MOR holder] -->|"lock MOR"| Pool[Stake-for-liquidity pool] + Pool -->|"emission rewards"| StakerWallet[Staker wallet] + end +``` + +## System 1 — Compute Node session payouts (this repo) + +**Who earns:** providers who host models and serve consumer sessions. + +**How it's earned:** for every consumer session that closes against your bid, the contract pays you `pricePerSecond × duration` (capped by your proportional stake limit, see below). Payment happens **inside `closeSession`** via `_rewardProviderAfterClose`, from the **protocol `fundingAccount`** for stake-pool sessions, or **directly from the consumer's wallet** for sessions opened with `directPayment: true`. Either way, the amount you earn is the same per second of service. + +**Where it goes:** the provider wallet that owns the on-chain provider record. + +**Cap:** `PROVIDER_REWARD_LIMITER_PERIOD` (currently 1 day) caps how much a provider can earn per period proportional to their staked amount. Beyond the cap, sessions still bill the consumer but the provider waits for the next period to earn more. Code: [`SessionRouter.sol::_claimForProvider`](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/blob/main/smart-contracts/contracts/diamond/facets/SessionRouter.sol). + +**Disputes / on-hold:** if the consumer disputes a session and closes early, a portion of the provider's reward is parked in a per-day timelock similar to the consumer's `userStakesOnHold` queue. Code: [`SessionRouter.sol::_rewardProviderAfterClose`](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/blob/main/smart-contracts/contracts/diamond/facets/SessionRouter.sol). To pull the unlocked portion later, call `claimForProvider(sessionId)`. + +**No node, no payout.** This system requires running the proxy-router and registering on chain. + +## System 2 — Stake-for-liquidity (Capital Contract) + +**Who earns:** any MOR holder who locks MOR in the Capital Contract / stake-for-liquidity program. + +**How it's earned:** locked MOR earns emission-style rewards over time. The reward formula is governed by the Capital Contract, **not by this repo's Compute Node contracts**. + +**Where it goes:** the staker's wallet (subject to whatever lock and claim semantics the Capital Contract enforces). + +**Cap:** governed by Capital Contract parameters. See [mor.org](https://mor.org) and the canonical MorpheusAIs docs. + +**No node required.** This system is a pure DeFi staking flow. You don't run software; you just lock tokens. + +## Side-by-side + +| Aspect | Compute Node session payout | Capital Contract stake-for-liquidity | +|--------|------------------------------|--------------------------------------| +| Repo | This repo (proxy-router + Diamond) | Separate Capital Contract | +| Action required | Run a provider node, host a model | Lock MOR | +| Earns from | Consumer sessions you serve | Emission rewards | +| Currency in | MOR (consumer stake) | MOR (your locked principal) | +| Currency out | MOR (per-session) | MOR (emissions) | +| Tied to your hardware | Yes | No | +| Tied to your provider stake | Yes (proportional limiter) | No | +| Where to read more | This site | [mor.org](https://mor.org), upstream MorpheusAIs/Docs | + +## What they have in common + +- Both denominate everything in **MOR** on **BASE**. +- Both can use the same wallet, but **don't have to**. +- The on-chain provider stake (the `0.2` MOR or `10000` MOR refundable bond) **is part of System 1**, not System 2 — depositing it does not enrol you in stake-for-liquidity. + +## A common mistake + +> "I read I earn a 'staking reward proportional to my stake' — does that mean my provider stake is also enrolled in stake-for-liquidity?" + +**No.** The "proportional to your stake" wording in System 1 means the **per-period earnings cap**, not a separate staking reward. Your provider stake is a refundable bond that lets you participate; it doesn't earn emissions. + +If you want stake-for-liquidity emissions, you need to interact with the **Capital Contract** separately. + +## Related + +- [Tokens and fees](/concepts/tokens-and-fees) — provider stake, model stake, bid fee, gas. +- [Sessions: stake, close, claim](/concepts/sessions-stake-close-recover) — the lifecycle of consumer-side stake. +- [Pricing your bid](/providers/full/pricing) — how `pricePerSecond` interacts with the per-period cap. +- [Inference API overview](/inference-api/overview) — the hosted gateway, billed differently again (per-token over the marketplace). diff --git a/docs/concepts/sessions-stake-close-recover.mdx b/docs/concepts/sessions-stake-close-recover.mdx new file mode 100644 index 00000000..2b34cf68 --- /dev/null +++ b/docs/concepts/sessions-stake-close-recover.mdx @@ -0,0 +1,168 @@ +--- +title: "Sessions: stake, close, claim" +description: "The complete lifecycle of a Morpheus session — open, stake, close (natural vs early), and the on-hold timelock for early closes. Why MOR is not 'gone' just because the session is open." +audience: ["consumer", "provider-full", "provider-resale", "developer"] +product: ["proxy-router"] +last_verified: "v7.0.0" +--- + +This is the most misunderstood part of Morpheus. The vast majority of "where is my MOR?" support questions resolve here. Read carefully. + + +The canonical reference for this lifecycle (with a read-only Base wallet checker) is [tech.mor.org/session.html](https://tech.mor.org/session.html). The page below is the curated repo-side summary; if it ever disagrees with `tech.mor.org`, that page wins. + + +## End-to-end flow + +```mermaid +flowchart TB + Wallet1["1. MOR in your wallet"] --> Open["2. Approve + Open session"] + Open --> Active["3. Active session"] + Active --> NaturalPath["Natural expiration path"] + Active --> EarlyPath["Early close path"] + + subgraph NaturalPath + direction TB + NatClose["4a. Consumer node submits close ~1 minute after endsAt"] + NatNoLock["5a. No timelock"] + NatRefund["6a. Full refund inside the same close txn"] + NatClose --> NatNoLock --> NatRefund + end + + subgraph EarlyPath + direction TB + EarlyClose["4b. User calls close via API/app"] + EarlyLock["5b. Slice may go to userStakesOnHold (1-day timelock)"] + EarlyClaim["6b. Call withdrawUserStakes after the timelock"] + EarlyClose --> EarlyLock --> EarlyClaim + end + + NaturalPath --> Wallet2["7. MOR back in your wallet"] + EarlyPath --> Wallet2 +``` + +## The three places your MOR can be on chain + +The Morpheus consumer node (proxy-router) does **not** custody tokens — it just calls the same Inference Contract functions you could call directly from `cast` or MetaMask. So your consumer MOR is always in exactly one of three places: + + + + Standard ERC-20 `balanceOf(you)` on the MOR token. Anything the contract `safeTransfer`s to you during `closeSession` or `withdrawUserStakes` lands here. + + + `openSession` does `transferFrom(you, InferenceContract, amount)`. While `closedAt == 0`, your stake lives inside the session record — not in your wallet, not yet in the on-hold queue. + + + `userStakesOnHold[user]` array. Entries are only created on **certain early closes** (`closedAt < endsAt`) with `releaseAt = startOfTheDay(closedAt) + 1 day`. After that timestamp you call `withdrawUserStakes` to move them to your wallet. + + + +## Walkthrough + + + + Standard ERC-20 balance, like any token. + + + `openSession(bidId, sessionDuration)` does `transferFrom(you, Diamond, amount)`. The whole stake moves out of your wallet into the Inference Contract for the duration of the session. The session has a scheduled `endsAt` derived from `pricePerSecond × sessionDuration`. + + + Until `endsAt` (or until you close early), the session is active and your stake is reserved for inference with the chosen provider. + + + Closing always happens in a single on-chain `closeSession` call. The path splits depending on **when** the close happens: + + - **Natural expiration (`closedAt ≥ endsAt`)** — your consumer node usually submits the close transaction itself ~1 minute after `endsAt` (assuming it's online and caught up). + - **Early close (`closedAt < endsAt`)** — you (or your app/agent) call close via API / `cast` before the scheduled end. This is the first user-initiated step on the early-close path. + + + + + **No on-hold row, no timelock.** The contract `safeTransfer`s your share back to your wallet **inside the same `closeSession` transaction**. You don't need a separate "withdraw" step. + + + The contract may push a computed slice of your stake to `userStakesOnHold[you]` with `releaseAt = startOfTheDay(closedAt) + 1 day`. The rest is `safeTransfer`'d to your wallet immediately. The held slice is *not* lost — it's parked inside the contract until the timelock passes. **How much is held depends on how long the session ran and the agreed price** — it's not a simple "minutes left on the clock" slider, and the rule mirrors how natural-expiration settlement would have paid out. + + + + + + + Already done in step 5a. No further action needed. + + + After the timelock passes (≈ "after the end of the next full UTC day" from `closedAt`), call `withdrawUserStakes(yourAddress, iterations)` on the Diamond contract. The held rows that have passed `releaseAt` move to your wallet. **There is no HTTP route for this on the proxy-router today** — you call it directly via `cast send`, MetaMask "Interact with contract", or your wallet app's withdraw / claim flow. + + ```bash + # Mainnet; replace placeholders + cast send 0x6aBE1d282f72B474E54527D93b979A4f64d3030a \ + "withdrawUserStakes(address,uint8)" 0xYOUR_CONSUMER_WALLET 20 \ + --rpc-url https://mainnet.base.org \ + --private-key "$PRIVATE_KEY_OF_DELEGATEE" + ``` + + + + + Spendable MOR back in your wallet — either right after a successful natural-expiration close, or after an early close + claim once the timelock allows it. + + + +## How the provider gets paid (and what your stake has to do with it) + +Your stake **is not** what pays the provider in real time. Inside `closeSession`: + +1. The contract sets `closedAt` and marks the session inactive. +2. **`_rewardUserAfterClose`** — your share is computed and either `safeTransfer`'d to your wallet (natural expiration) or split between an immediate transfer and an `userStakesOnHold` row (early close). +3. **`_rewardProviderAfterClose`** — pays the provider for time actually used. For typical staked sessions, the payment comes from the protocol's separate **`fundingAccount` via `transferFrom`**, **not** from your stake in that same step. + +The practical implication: if the protocol's funding wallet is empty or has insufficient allowance to the Inference Contract, **no session can close** — yours included. That's a different failure mode from a stuck consumer node and is handled by the Morpheus operators, not by you. It can manifest as sessions sitting "active" past their `endsAt`. + +## States (with the on-hold queue made explicit) + +```mermaid +stateDiagram-v2 + [*] --> Opening + Opening --> Open: openSession succeeds, stake escrowed, sessionId issued + Open --> ClosedNatural: closeSession after endsAt (consumer node usually submits) + Open --> ClosedEarly: user-initiated close before endsAt + ClosedNatural --> [*]: full refund inside the same txn + ClosedEarly --> OnHold: contract may park a slice in userStakesOnHold (releaseAt = startOfDay(closedAt) + 1 day) + ClosedEarly --> [*]: remainder transferred immediately + OnHold --> [*]: withdrawUserStakes after releaseAt +``` + +## What "recover" really means + +Older docs (and even some early Morpheus discussion) used the word "recover" loosely. There is no single `recover` RPC. There are two distinct on-chain calls: + +- **`closeSession`** stops the session and triggers refund logic. +- **`withdrawUserStakes`** is the *separate* claim action for early-close timelocked balances. + +If a session is genuinely stuck (e.g. funding account empty, your consumer node offline past `endsAt`), the resolution is still a successful `closeSession` followed, if needed, by `withdrawUserStakes`. There is no other path. + +## On-chain calls (consumer, via proxy-router) + +| Action | Endpoint | +|--------|----------| +| List models | `GET /blockchain/models` | +| Open session | `POST /blockchain/models/:id/session` | +| List sessions for a wallet | `GET /blockchain/sessions/user?user=0x…` | +| List session IDs only (lighter) | `GET /blockchain/sessions/user/ids?user=0x…` | +| Fetch one session | `GET /blockchain/sessions/0x…` | +| Close a session | `POST /blockchain/sessions/0x…/close` | +| Claim early-close on-hold balance | **No HTTP route** — call `withdrawUserStakes` on the Diamond contract directly | + +See [API endpoints](/reference/api-endpoints) for full curl examples. + +## Read-only wallet check (off-site) + +[tech.mor.org/session.html](https://tech.mor.org/session.html) has a hosted read-only wallet checker that shows your MOR split across the three buckets (wallet / active session / on-hold). Use it whenever the wallet balance "looks wrong." + +## Minimums (from the contract) + +- **Consumer session open**: `5` MOR minimum. +- **Bid price floor**: `10000000000` wei/sec (`0.00000001` MOR/sec). +- **Provider stake**: `0.2` MOR (or `10000` MOR for a subnet provider). + +These are governance-controlled and can change; check [Networks and tokens](/get-started/networks-and-tokens) and the [release notes](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/releases). diff --git a/docs/concepts/tee-overview.mdx b/docs/concepts/tee-overview.mdx new file mode 100644 index 00000000..408f6b71 --- /dev/null +++ b/docs/concepts/tee-overview.mdx @@ -0,0 +1,64 @@ +--- +title: "TEE: trusted execution overview" +description: "The two-hop trust chain (consumer → P-Node → backend LLM) introduced in v7.0.0. What it guarantees, what it does not, and how it is enforced." +audience: ["consumer", "provider-full", "developer"] +product: ["proxy-router"] +last_verified: "v7.0.0" +--- + +TEE (Trusted Execution Environment) verification on Morpheus is a **two-hop chain**, with each hop attested separately. The on-chain `tee` tag on a model triggers both hops: + +``` +C-Node (v6.0.0+) ─Phase 1─▶ P-Node -tee image (v7.0.0+) ─Phase 2─▶ Backend LLM (SecretVM) +``` + +- **Phase 1** is what the **consumer's proxy-router** runs against the provider's P-Node. +- **Phase 2** is what the **provider's P-Node (v7.0.0+)** runs against its own backend LLM. The consumer never sees Phase 2 directly. +- A v6.0.0+ consumer paired with a v7.0.0+ provider gets the full chain transparently — **no consumer-side upgrade is needed** to benefit from Phase 2. + +## What Phase 1 proves + +When a v6.0.0+ C-Node opens a session for a `tee`-tagged model, the consumer's proxy-router proves the following about the provider's P-Node, at session open and on every prompt: + +- The proxy-router binary is the exact binary built by the official CI/CD from a known commit (verified via cosign signature on the `-tee` image). +- Chat context storage is disabled and cannot be re-enabled (baked in at image build, enforced by RTMR3). +- Logging is in production mode and cannot be increased to capture prompts. +- Blockchain config (contracts, chain ID, blockscout URL) is immutable, frozen for the target network. +- The image has not been tampered with (RTMR3 replay of the published deployed compose against the live TDX quote). +- The TLS certificate terminating the connection is pinned into the quote's `reportData[0:32]`, so no TLS-terminating proxy or CDN can sit between the consumer and the P-Node. +- A ~50 ms fast path (quote hash + TLS fingerprint compare) re-checks on every prompt; any drift triggers full re-verification. + +## What Phase 2 proves + +Phase 2 runs **entirely inside the provider's P-Node**. For each `tee`-tagged model, the v7+ P-Node proves the following about the backend LLM at startup and on every prompt: + +- Backend's CPU TDX quote is independently verified (`AttestBackend` at startup, `FastVerifyBackend` per prompt). +- Backend's TLS certificate fingerprint is pinned into the CPU quote's `reportData[0:32]`; the onward HTTP client refuses any non-matching certificate. +- Backend's GPU attestation nonce is bound to the CPU quote via `reportData[32:64]`; GPU evidence is independently verified by **NVIDIA NRAS**. +- Backend's `docker-compose.yaml` is recovered from `:29343/docker-compose` and **RTMR3 is replayed** against the live TDX quote — proving the exact set of models loaded. +- MRTD + RTMR0-2 are looked up in the published SecretVM TDX artifact registry to confirm firmware/VM/kernel/initramfs. +- Per-model attestation state is exposed on `GET /v1/models/attestation` for monitoring and forensics. + +## What it does *not* prove + +- It does **not** prove the *quality* of the model's output. TEE attests the *software*, not the *answer*. +- It does **not** prove the model wasn't fine-tuned in a problematic way before being baked into the backend image. +- It does **not** prove anything about non-TEE (untagged) providers. A non-`tee` model has no attestation chain at all. +- AMD SEV-SNP measurements are not yet computed in CI/CD; only Intel TDX RTMR3 is published in the manifest today. + +## How to use it + + + + Use a v6.0.0+ proxy-router. When you open a session against a `tee`-tagged model, attestation runs automatically. + + + Deploy the `-tee` image on SecretVM, register your model with the `tee` tag. + + + Cosign verification, RTMR3 recomputation, attestation manifest fields. + + + The full Phase 2 reference lives at [`proxy-router/docs/tee-backend-verification.md`](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/blob/main/proxy-router/docs/tee-backend-verification.md). + + diff --git a/docs/concepts/tokens-and-fees.mdx b/docs/concepts/tokens-and-fees.mdx new file mode 100644 index 00000000..fa67bac9 --- /dev/null +++ b/docs/concepts/tokens-and-fees.mdx @@ -0,0 +1,74 @@ +--- +title: "Tokens, fees, and economics" +description: "MOR vs ETH on BASE, who pays what when, and where the on-chain minimums come from." +audience: ["consumer", "prosumer", "provider-resale", "provider-full"] +product: ["proxy-router"] +last_verified: "v7.0.0" +--- + +Two tokens, one chain. **MOR** is the unit of payment inside the Morpheus marketplace; **ETH on BASE** pays the underlying gas to the BASE Layer-2 network. + +## Token roles + +| | MOR | ETH (on BASE) | +|---|---|---| +| What is it? | Morpheus marketplace token (ERC-20) | BASE L2 native gas token | +| Used for | Provider stake, model stake, bid fees, consumer session stake, settlement | All BASE transaction gas | +| Required for consumers? | Yes (to open sessions) | Yes (to pay gas) | +| Required for providers? | Yes (stake, bid fee) | Yes (to pay gas) | + +Token addresses by network are listed in [Networks and tokens](/get-started/networks-and-tokens). + +## Fee surfaces + + + + Total = `pricePerSecond * sessionDuration` (minimum `5` MOR). Paid in MOR, escrowed in the Inference Contract on `openSession`. On **natural expiration** (`closedAt >= endsAt`) your full share is `safeTransfer`'d back to your wallet inside the same `closeSession` transaction. On **early close** a slice may go to `userStakesOnHold` (1-day timelock), to be claimed later via `withdrawUserStakes`. The provider is paid by the contract from a separate protocol `fundingAccount`, not from your stake in real time. See [Sessions: stake, close, claim](/concepts/sessions-stake-close-recover). + + + + Refundable bond posted when registering a provider. Minimum `0.2` MOR for a normal provider, `10000` MOR for a subnet provider. Returned (minus penalties) on provider deregistration. + + + + Refundable bond posted when registering a model. Minimum `0.1` MOR. + + + + Non-refundable fee paid when posting a bid. `0.3` MOR. + + + + All on-chain calls (open, close, claim, register, etc.) consume BASE gas, paid in ETH. Keep a small ETH buffer per wallet. + + + +## Net cost to become a provider (one-time minimum) + +``` +provider stake (0.2) + + model stake (0.1) + + bid fee (0.3) + ---------------- + ~ 0.6 MOR + ETH gas +``` + +Plus you must approve at least `~0.6` MOR to the Diamond contract. See [Register on chain](/providers/full/register-onchain). + +## Net cost to consume (per session) + +``` +session stake = pricePerSecond * sessionDuration + (minimum 5 MOR escrowed at open) +``` + +The full stake is escrowed at open. **Natural expiration** returns the full share to your wallet in one transaction. **Early close** splits the refund: a slice may be timelocked in `userStakesOnHold` for ~1 UTC day before you can claim it via `withdrawUserStakes`. See [Sessions: stake, close, claim](/concepts/sessions-stake-close-recover). + +## Two reward systems (do not conflate) + +The Morpheus stack has two independent reward systems that are easy to mix up: + +1. **Compute Node session payouts** (this repo): providers earn MOR per second of sessions they serve. Paid inside `closeSession`. Tied to your provider stake's per-period limiter, but the stake itself is a refundable bond, not a yield-bearing position. +2. **Capital Contract / stake-for-liquidity** (separate program at [mor.org](https://mor.org)): MOR holders lock MOR and earn emission rewards. Not part of this repo. Does **not** require running a node. + +Your provider stake **is not** enrolled in the Capital Contract. See [Rewards and economics](/concepts/rewards-and-economics) for the side-by-side breakdown. diff --git a/docs/concepts/what-is-morpheus.mdx b/docs/concepts/what-is-morpheus.mdx new file mode 100644 index 00000000..5df52cc9 --- /dev/null +++ b/docs/concepts/what-is-morpheus.mdx @@ -0,0 +1,93 @@ +--- +title: "What is Morpheus?" +description: "An opinionated explainer of the Morpheus Inference Marketplace: a decentralized, peer-to-peer marketplace for AI inference, coordinated by smart contracts on BASE." +audience: ["consumer", "prosumer", "provider-resale", "provider-full", "developer"] +product: ["proxy-router", "ui-desktop"] +last_verified: "v7.0.0" +--- + +The **Morpheus Inference Marketplace** is where decentralized AI becomes accessible to everyone. It connects people who need compute power (consumers) with providers who supply it, all coordinated by smart contracts on BASE. Instead of a centralized service, requests and responses flow **directly** between consumer and provider in a peer-to-peer system. + +The Morpheus Lumerin Node is the open-source software stack that **wires actual prompts and inference to that marketplace**. It is the missing piece between "there is a contract on chain" and "I am chatting with a model." + +## Why decentralized inference matters + +Decentralized inference breaks the dependency on centralized providers who control access, pricing, and availability of AI infrastructure. In a decentralized system: + +- **Anyone can contribute** resources, and **anyone can use them** — an open, resilient, competitive market. +- **No single points of failure.** No one provider's outage takes the network down. +- **Costs stay fair** through transparent on-chain incentives, not vendor pricing power. +- **Innovation isn't gated** by the decisions of a few large players. + +It's about shifting power from closed platforms to an open network where inference is a shared, community-driven resource. + +## Design + +```mermaid +flowchart LR + Consumer[Consumer + proxy-router] -->|"open session"| Compute[Compute Node contracts on BASE] + Provider[Provider + proxy-router] -->|"register, post bids"| Compute + Compute -->|"match"| Consumer + Consumer <-->|"prompts and responses, peer-to-peer"| Provider +``` + +At the centre of the marketplace are the **Compute Node contracts** (the Diamond marketplace on BASE). They: + +- **Register** providers and the models they host. +- **Match** consumers with available providers. +- **Secure** connections through encryption and verifiable on-chain logic. + +To participate, **both sides** run a **proxy-router** — a lightweight binary (this repo) that talks to the contracts and manages session lifecycle. Once a session is open, the consumer's prompts go directly to the provider's model and the responses come back the same way — **no middleman, no inference flowing through a Morpheus-operated server**. + +## Three core ideas + + + + Once a session is open, prompts and responses go **directly** between consumer and provider — no Morpheus-operated server in the data path. The blockchain only sees session open / close / settle, never the inference itself. + + + Pricing is **per-second of session time**, not per-token. Consumers stake MOR for a fixed duration; the MOR is escrowed and refunded on close (full refund on natural expiration; early close uses a 1-day timelock for part of the refund). See [Sessions: stake, close, claim](/concepts/sessions-stake-close-recover). + + + Providers with strong uptime, time-to-first-token, throughput, and success rate are matched more often by the consumer-side rating system. See [rating-config.json](/reference/rating-config) for how the weights work. + + + +## What Morpheus is *not* + +- **Not a hosted service.** There is no "Morpheus, Inc." running the inference. Providers are independent operators. +- **Not on-chain inference.** The blockchain coordinates the marketplace; it does not execute prompts. +- **Not a wallet.** MorpheusUI manages a key for convenience; the keys, ETH, and MOR are all standard ERC-20 / EOA primitives on BASE. +- **Not token-priced.** Pricing is denominated in **session time** (`pricePerSecond`), not tokens. Long contexts and short contexts cost the same per second. + +## Two ways to use Morpheus + +You can either **run a node** (peer-to-peer, self-custody, native to the marketplace) or **use the hosted API Gateway** (no node, simple API key). + +| Path | What it gives you | When to pick it | +|------|-------------------|-----------------| +| **Run a node** (this repo) | Direct, self-custody, peer-to-peer access to the marketplace; full TEE chain available | You want self-custody, attestation, automation, or to be a provider | +| **Hosted Inference API** ([apidocs.mor.org](https://apidocs.mor.org)) | OpenAI-compatible API key against a hosted gateway; powers the Morpheus Chat App and lite clients | You just want to plug Morpheus into an OpenAI-compatible app or framework | + +See [Inference API overview](/inference-api/overview) for the hosted path. + +## Where Morpheus, NodeNeo, Everclaw, app.mor.org fit + +| Surface | Audience | What it does | +|---------|----------|--------------| +| `app.mor.org` (Morpheus Chat App) | Consumers | Hosted chat UI; powered by the API Gateway | +| MorpheusUI (this repo) | Consumers + small providers | Local Electron desktop chat with self-custodial wallet | +| NodeNeo ([nodeneo.io](https://nodeneo.io)) | Consumers + prosumers | Cross-platform consumer experience | +| Everclaw ([everclaw.xyz](https://everclaw.xyz)) | Agent developers | Skill / SDK that talks to a local AI gateway backed by Morpheus | +| MyProvider ([myprovider.mor.org](https://myprovider.mor.org)) | Providers | Hosted operator GUI for provider node management | +| **Inference API Gateway** ([apidocs.mor.org](https://apidocs.mor.org)) | Developers / API users | Hosted, OpenAI-compatible inference gateway — separate product, no node required. See [Inference API overview](/inference-api/overview). | +| `tech.mor.org` | All | Calculators, status, sessions, throughput, TEE explainers | +| `active.mor.org` | All | Live network status, active models, active bids | +| `gitbook.mor.org` | All / agents | Broader Morpheus docs hub. Supports an `?ask=` query mechanism for AI agents — see [llm-prompt-cheatsheet](/ai/llm-prompt-cheatsheet#dynamic-querying-of-the-broader-morpheus-docs). | + +See [Ecosystem](/ecosystem/overview) for curated, mirrored summaries with attribution. + +## Further reading (canonical, off-site) + +- [Intro to Morpheus Compute Node](https://github.com/MorpheusAIs/Docs/blob/main/!KEYDOCS%20README%20FIRST!/Compute%20Providers/Compute%20Node/Intro%20to%20Morpheus%20Compute%20Node.md) — the upstream MorpheusAIs/Docs explainer of the Compute Node design. +- [Discord — #morpheus-compute-node](https://discord.com/channels/1151741790408429580/1167520834139738289) — community questions. diff --git a/docs/consumers/buy-bid.mdx b/docs/consumers/buy-bid.mdx new file mode 100644 index 00000000..d7e3daf7 --- /dev/null +++ b/docs/consumers/buy-bid.mdx @@ -0,0 +1,74 @@ +--- +title: "Open a session (buy a bid)" +description: "How to open a Morpheus session via MorpheusUI or the API: pick a model, select a bid, stake MOR, and what happens next." +audience: ["consumer"] +product: ["proxy-router", "ui-desktop"] +last_verified: "v7.0.0" +source: "docs/05-bid-purchase.md" +--- + +Opening a session = "buying a bid." You stake MOR for a fixed duration; the proxy-router routes prompts to the chosen provider until the session closes (or you close it). The MOR is **escrowed**, not spent up-front — see [Sessions: stake, close, claim](/concepts/sessions-stake-close-recover) before you panic about a dropping wallet balance. + +## Via MorpheusUI + + + + Lower-left of MorpheusUI shows your wallet address; the Wallet tab shows MOR and ETH balances. You need at least `5` MOR for a session and a small ETH balance for gas. + + + Chat tab → **Change Model** → pick from the remote dropdown (anything other than "Local Model"). The dropdown lists models registered in the Diamond marketplace contract. + + + Click **Open Session**. Enter a stake (minimum `5` MOR). Confirm. + + + A transaction will be submitted. Once confirmed, the session is open and you can prompt. + + + Two paths: + + - **Natural expiration** — if you let the session run to its `endsAt`, your consumer node submits `closeSession` ~1 minute later (assuming it's online) and your **full share** lands back in your wallet inside that one transaction. + - **Early close** — click the time icon next to the model line; click **X** next to the session. The contract may park a slice in `userStakesOnHold` (1-day timelock); the rest comes back immediately. After the timelock you must call `withdrawUserStakes` to claim the held slice. + + + +## Via the API + +```bash +curl -X POST 'http://localhost:8082/blockchain/models//session' \ + -H 'Content-Type: application/json' \ + -H 'Authorization: Basic ' \ + -d '{"sessionDuration": 600, "failover": false, "directPayment": false}' +``` + +Response: + +```json +{ "sessionID": "0x8e12df2f764b416c0ea1936a253c2a4be01005651c2d73f22dd0d72520f93ca1" } +``` + +Close it: + +```bash +curl -X POST 'http://localhost:8082/blockchain/sessions//close' \ + -H 'Authorization: Basic ' -d '{}' +``` + +## What you should expect + +- **Wallet balance drops by the staked amount** the instant the open transaction is mined. The MOR is now in the Inference Contract on Base for the duration of the session. +- **Natural expiration**: at `endsAt`, your consumer node submits `closeSession` ~1 minute later and the **full share** of your stake lands in your wallet inside that single transaction. No separate withdraw needed. +- **Early close**: a slice may go to `userStakesOnHold` with `releaseAt = startOfTheDay(closedAt) + 1 day` (≈ "after the end of the next full UTC day"). The rest is returned immediately. After `releaseAt`, call `withdrawUserStakes(yourAddress, iterations)` directly on the Diamond contract — there is no HTTP route on the proxy-router. +- **The provider is paid from a separate protocol funding account**, not from your stake in real time. If that funding account is empty or under-approved, every `closeSession` fails — yours included. The session sits "active" past `endsAt` until operators top it up. See [Why is my MOR locked?](/ai/why-locked-in-contract) and [Sessions: stake, close, claim](/concepts/sessions-stake-close-recover). +- For a hosted read-only wallet checker that splits your MOR across the three on-chain buckets (wallet / active session / on-hold), see [tech.mor.org/session.html](https://tech.mor.org/session.html). + +## Picking a good bid + +There is no single right answer; consider: + +- **`pricePerSecond`** — lower is cheaper but providers compete on quality and uptime. +- **Provider reputation / stake** — higher provider stake means more skin in the game. +- **TEE vs non-TEE** — `tee`-tagged models give you cryptographic guarantees about the running software (see [TEE overview](/concepts/tee-overview)). +- **Throughput / capacity** — see live data at [active.mor.org](https://active.mor.org). + +For a `rating-config.json` that prefers certain providers automatically, see [rating-config](/reference/rating-config). diff --git a/docs/consumers/chat.mdx b/docs/consumers/chat.mdx new file mode 100644 index 00000000..930ce105 --- /dev/null +++ b/docs/consumers/chat.mdx @@ -0,0 +1,83 @@ +--- +title: "Chat, audio, and embeddings" +description: "Send prompts to a remote Morpheus model: streaming chat completions, audio transcription / TTS, and embeddings — all with OpenAI-compatible payloads." +audience: ["consumer", "developer"] +product: ["proxy-router"] +last_verified: "v7.0.0" +--- + +Once a session is open, you talk to the proxy-router exactly like you would talk to OpenAI: same routes, same body schemas. The only difference is the `session_id` header and the BasicAuth header for the local API. + +## Headers + +| Header | Required | Purpose | +|--------|----------|---------| +| `Authorization: Basic ` | Yes | Auth to your local proxy-router. See [API auth](/reference/api-auth). | +| `session_id: 0x...` | Yes (for remote) | Which open Morpheus session to route through. Omit for the bundled local model. | +| `Content-Type` | As needed | `application/json` or `multipart/form-data`. | + +## Chat completions + +Streaming, OpenAI-compatible, model field is **set by the provider** based on `session_id`: + +```bash +curl -X POST 'http://localhost:8082/v1/chat/completions' \ + -H 'Content-Type: application/json' \ + -H 'Authorization: Basic YWRtaW46YWRtaW4=' \ + -H 'session_id: 0x8e12df2f764b416c0ea1936a253c2a4be01005651c2d73f22dd0d72520f93ca1' \ + -d '{ + "messages": [ + {"role": "system", "content": "You are a helpful assistant."}, + {"role": "user", "content": "Tell me about AI."} + ], + "stream": true + }' +``` + +Streaming responses are SSE (`text/event-stream`); non-streaming returns `application/json`. + +## Audio transcriptions + +`POST /v1/audio/transcriptions` — multipart form-data; the body is forwarded to the provider, so any field the provider accepts will pass through. Common fields: `file`, `language`, `response_format`, `timestamp_granularities[]`, `enable_diarization`. + +```bash +curl -X POST 'http://localhost:8082/v1/audio/transcriptions' \ + -H 'Authorization: Basic YWRtaW46YWRtaW4=' \ + -H 'session_id: 0x...' \ + -F 'file=@harvard.wav' +``` + +## Audio speech (TTS) + +```bash +curl -X POST 'http://localhost:8082/v1/audio/speech' \ + -H 'Content-Type: application/json' \ + -H 'Authorization: Basic YWRtaW46YWRtaW4=' \ + -H 'session_id: 0x...' \ + -d '{"input": "Hello world.", "voice": "af_alloy"}' +``` + +Response is `audio/mpeg` (or whatever `response_format` you specified). + +## Embeddings + +```bash +curl -X POST 'http://localhost:8082/v1/embeddings' \ + -H 'Content-Type: application/json' \ + -H 'Authorization: Basic YWRtaW46YWRtaW4=' \ + -H 'session_id: 0x...' \ + -d '{"input": "The quick brown fox jumped over the lazy dog", "encoding_format": "float"}' +``` + +## Closing a session early + +Always close manually if you are finished well before the session timer expires. Unused stake returns to your wallet on close. + +```bash +curl -X POST 'http://localhost:8082/blockchain/sessions//close' \ + -H 'Authorization: Basic YWRtaW46YWRtaW4=' -d '{}' +``` + +## Full schema + +See [API endpoints](/reference/api-endpoints) for our curated subset, or [`proxy-router/docs/swagger.yaml`](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/blob/main/proxy-router/docs/swagger.yaml) for the full schema. diff --git a/docs/consumers/install-from-source.mdx b/docs/consumers/install-from-source.mdx new file mode 100644 index 00000000..af5a5e0d --- /dev/null +++ b/docs/consumers/install-from-source.mdx @@ -0,0 +1,126 @@ +--- +title: "Install from source" +description: "Set up a consumer node from the GitHub source so you can interact with remote providers via the API." +audience: ["consumer", "developer"] +product: ["proxy-router", "cli"] +last_verified: "v7.0.0" +source: "docs/04a-consumer-setup-source.md" +--- + +This guide builds the proxy-router from source and walks through the API-only consumer flow (no MorpheusUI). For an Electron-included experience, see the [packaged installs](/consumers/quickstart). For a four-terminal source walk-through (llama.cpp + proxy-router + UI + CLI), see [macOS install](/consumers/install/macos). + +## Pre-requisites + +- An ERC-20 wallet on BASE with MOR + ETH (use a top-level, not derived, address). **Never share your private key.** + +## TL;DR + + + + Once. + + + Once per wallet (or whenever the allowance is depleted). + + + Per session. + + + Per session. + + + Per session. + + + +## A. Build & run the proxy-router + + + + `git` (https://git-scm.com), `go` 1.22+ (https://golang.org). + + + ```bash + git clone https://github.com/MorpheusAIs/Morpheus-Lumerin-Node.git + cd Morpheus-Lumerin-Node/proxy-router + ``` + + + ```bash + cp .env.example .env + vi .env + ``` + Set at minimum: + - `WALLET_PRIVATE_KEY=` — your wallet's private key. + - `ETH_NODE_ADDRESS=wss://...` — recommended: an Alchemy/Infura BASE WSS endpoint. + Reference: [Env: proxy-router](/reference/env-proxy-router). + + + ```bash + ./build.sh + ./proxy-router + ``` + On future updates: `git pull && ./build.sh && ./proxy-router`. + Confirm Swagger at `http://localhost:8082/swagger/index.html`. + + + +## B. Authorize the contract + +Either via Swagger or curl. **Once per wallet**, or when allowance is depleted. + +```bash +curl -X POST \ + 'http://localhost:8082/blockchain/approve?spender=0x6aBE1d282f72B474E54527D93b979A4f64d3030a&amount=3' \ + -H 'accept: application/json' -d '' +``` + +## C. Query for a model + +```bash +curl -X GET 'http://localhost:8082/wallet' -H 'accept: application/json' +curl -X GET 'http://localhost:8082/blockchain/models' -H 'accept: application/json' +``` + +Pick an `Id` from the response and use it as `` below. See the [API endpoints](/reference/api-endpoints) reference for the full schema. + +## D. Open a session + +```bash +curl -s -X POST \ + 'http://localhost:8082/blockchain/models//session' \ + -H 'accept: application/json' \ + -H 'Content-Type: application/json' \ + -d '{"sessionDuration": 600}' +``` + +The transaction will appear in your wallet's history at `https://base.blockscout.com/address/`. + +## E. Prompt + +```bash +curl -X POST 'http://localhost:8082/v1/chat/completions' \ + -H 'accept: application/json' \ + -H 'session_id: ' \ + -H 'Content-Type: application/json' \ + -d '{ + "messages": [{"role":"user","content":"tell me a joke"}], + "stream": true + }' +``` + +The response is OpenAI-compatible SSE. + +## Quick-and-dirty one-liner + +```bash +# Approve, query wallet, list models, open a session, prompt +curl -X POST 'http://localhost:8082/blockchain/approve?spender=0x6aBE1d282f72B474E54527D93b979A4f64d3030a&amount=3' -H 'accept: application/json' -d '' +curl -s 'http://localhost:8082/wallet' | jq .address +curl -s 'http://localhost:8082/blockchain/models' | jq -r '.models[] | "\(.Id), \(.Name)"' +SESSION=$(curl -s -X POST 'http://localhost:8082/blockchain/models//session' \ + -H 'Content-Type: application/json' -d '{"sessionDuration":600}' | jq -r .sessionId) +curl -X POST 'http://localhost:8082/v1/chat/completions' \ + -H "session_id: $SESSION" -H 'Content-Type: application/json' \ + -d '{"messages":[{"role":"user","content":"tell me a joke"}],"stream":true}' +``` diff --git a/docs/consumers/install/docker.mdx b/docs/consumers/install/docker.mdx new file mode 100644 index 00000000..f6e9f3fc --- /dev/null +++ b/docs/consumers/install/docker.mdx @@ -0,0 +1,73 @@ +--- +title: "Docker (consumer)" +description: "Run a consumer-side proxy-router in Docker. The MorpheusUI Electron app is not containerized; pair this with the desktop UI or hit the API directly." +audience: ["consumer", "developer"] +product: ["proxy-router"] +last_verified: "v7.0.0" +--- + +The proxy-router itself is published as a Docker image at `ghcr.io/morpheusais/morpheus-lumerin-node`. As a **consumer** you typically run it locally next to MorpheusUI or call its HTTP API directly. The container exposes the same `:8082` admin/API and `:3333` proxy ports. + +## Quickstart + + +For provider-side Docker (with model registration, public `:3333`, etc.), see [Provider Docker](/providers/full/proxy-router-docker). The two flows share the same image and 90% of the configuration. + + + + + Create a host directory you will mount into the container: + ```bash + mkdir -p ~/morpheus-data + cd ~/morpheus-data + cat > proxy-router.env <<'EOF' + AUTH_CONFIG_FILE_PATH=/app/data/proxy.conf + COOKIE_FILE_PATH=/app/data/.cookie + RATING_CONFIG_PATH=/app/data/rating-config.json + PROXY_STORAGE_PATH=/app/data/data + MODELS_CONFIG_PATH=/app/data/models-config.json + ETH_NODE_CHAIN_ID=8453 + BLOCKSCOUT_API_URL=https://base.blockscout.com/api/v2 + DIAMOND_CONTRACT_ADDRESS=0x6aBE1d282f72B474E54527D93b979A4f64d3030a + MOR_TOKEN_ADDRESS=0x7431aDa8a591C955a994a21710752EF9b882b8e3 + WALLET_PRIVATE_KEY= + # Strongly recommended even for consumers — public round-robin fallback + # is rate-limited and unreliable; sessions can fail silently. + ETH_NODE_ADDRESS=https://base-mainnet.g.alchemy.com/v2/ + ETH_NODE_USE_SUBSCRIPTIONS=false + PROXY_ADDRESS=0.0.0.0:3333 + WEB_ADDRESS=0.0.0.0:8082 + WEB_PUBLIC_URL=http://localhost:8082 + EOF + ``` + + + ```bash + docker run -d \ + --name morpheus-proxy-consumer \ + --env-file proxy-router.env \ + -v ~/morpheus-data:/app/data \ + -p 8082:8082 \ + ghcr.io/morpheusais/morpheus-lumerin-node:latest + ``` + The TCP `:3333` port is **not** required for consumers and can be omitted. + + + ```bash + curl http://localhost:8082/healthcheck + ``` + Open Swagger at `http://localhost:8082/swagger/index.html`. + + + +## Networks + +Switch to BASE Sepolia by replacing the four blockchain values in the `.env`. See [Networks and tokens](/get-started/networks-and-tokens). + +## Pairing with MorpheusUI + +If you also want the desktop UI, run the packaged release as in [macOS](/consumers/install/macos) / [Windows](/consumers/install/windows) / [Linux](/consumers/install/linux), but stop the bundled proxy-router and point `PROXY_WEB_URL` (in MorpheusUI's `.env`) at your container's `http://localhost:8082`. + +## Direct API use + +You can skip the UI entirely. See [API direct](/reference/api-direct) for a curl-only walkthrough that opens a session and streams chat completions. diff --git a/docs/consumers/install/linux.mdx b/docs/consumers/install/linux.mdx new file mode 100644 index 00000000..4ec37cd5 --- /dev/null +++ b/docs/consumers/install/linux.mdx @@ -0,0 +1,49 @@ +--- +title: "Linux install" +description: "Run a packaged Morpheus Lumerin Node consumer release on Linux." +audience: ["consumer"] +product: ["proxy-router", "ui-desktop"] +last_verified: "v7.0.0" +--- + +The packaged Linux release contains the proxy-router, MorpheusUI, and an optional bundled `llama.cpp` server. For a source-build walk-through, see [macOS install (from source)](/consumers/install/macos) — the steps are nearly identical on Linux. + +## Steps + + + + ```bash + cd ~/Downloads + curl -L -o morpheus.zip + unzip morpheus.zip -d morpheus + cd morpheus + ``` + Or grab the asset manually from [Releases](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/releases). + + + Edit if you need a custom ETH node, log path, or non-default ports. See [Env: proxy-router](/reference/env-proxy-router). + + + ```bash + ./mor-launch + # Or with the bundled local model: + ./mor-launch local + ``` + + + Accept terms, set a UI password, create or recover a wallet. Save the mnemonic somewhere safe. + + + Open `http://localhost:8082/swagger/index.html`. Use **Local Model** in Chat to verify the pipeline. + + + +## Cleanup + +```bash +rm .cookie proxy.conf +rm -rf ~/.config/morpheus-ui +rm -rf data +``` + +See also: [Troubleshooting](/reference/troubleshooting). diff --git a/docs/consumers/install/macos.mdx b/docs/consumers/install/macos.mdx new file mode 100644 index 00000000..16b13c58 --- /dev/null +++ b/docs/consumers/install/macos.mdx @@ -0,0 +1,141 @@ +--- +title: "macOS install (from source, 4-terminal walk-through)" +description: "Build llama.cpp, the proxy-router, MorpheusUI, and the CLI from source on macOS. For developers and contributors." +audience: ["consumer", "developer"] +product: ["proxy-router", "ui-desktop", "cli"] +last_verified: "v7.0.0" +source: "docs/mac-boot-strap.md" +--- + +A simple guide to get the local `llama.cpp` model, the Lumerin proxy-router, and the MorpheusUI from source running on a Mac. + + +For a packaged install (no compilation), use the [Consumer quickstart](/consumers/quickstart). This page is for developers or contributors. + + + +**Wallet:** if you start with an existing MetaMask wallet, use a **tier-1** (top-level) address, not a derived/secondary one. MorpheusUI's mnemonic-recover flow does not work properly with secondary addresses derived under the same mnemonic. + + +## Dependencies + +| Tool | Minimum | +|------|---------| +| `git` | latest | https://git-scm.com | +| `go` | 1.22+ | https://golang.org | +| `node`| 20+ | https://nodejs.org | +| `make`| any | https://www.gnu.org/software/make | +| `yarn`| any | https://yarnpkg.com | + +## Step A — llama.cpp (terminal 1) + +You will need a port for the local model server (`8080` in this guide). This setup is one-time. + + + + ```bash + git clone https://github.com/ggerganov/llama.cpp.git + cd llama.cpp + make -j 8 + ``` + + + Set general variables: + ```bash + model_host=127.0.0.1 + model_port=8080 + ``` + Then pick a model (full set in [`docs/mac-boot-strap.md`](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/blob/main/docs/mac-boot-strap.md)): + ```bash + model_url=https://huggingface.co/TheBloke + model_collection=TinyLlama-1.1B-Chat-v1.0-GGUF + model_file_name=tinyllama-1.1b-chat-v1.0.Q4_K_M.gguf + ``` + + + ```bash + wget -O models/${model_file_name} \ + ${model_url}/${model_collection}/resolve/main/${model_file_name} + ./llama-server -m models/${model_file_name} \ + --host ${model_host} --port ${model_port} --n-gpu-layers 4096 + ``` + + + Open `http://127.0.0.1:8080` and confirm the local llama.cpp UI responds. + + + +## Step B — proxy-router (terminal 2) + +You'll need: +- Wallet **private key** (do not share, used in `.env`) +- ETH node WSS or HTTPS URL (Alchemy/Infura) for BASE +- Ports for the proxy (`3333`) and API (`8082`) + + + + ```bash + git clone https://github.com/MorpheusAIs/Morpheus-Lumerin-Node.git + cd Morpheus-Lumerin-Node/proxy-router + ``` + + + ```bash + cp .env.example .env + vi .env + ``` + See [Env: proxy-router](/reference/env-proxy-router) for every field. + + + ```bash + ./build.sh + make run + ``` + Allow firewall prompts on first launch. + + + Confirm log lines like: + ``` + INFO proxy state: running + INFO HTTP http server is listening: 0.0.0.0:8082 + INFO TCP tcp server is listening: 0.0.0.0:3333 + ``` + Open `http://localhost:8082/swagger/index.html`. + + + +## Step C — MorpheusUI (terminal 3) + +```bash +cd /Morpheus-Lumerin-Node/MorpheusUI +cp .env.example .env +vi .env # confirm PROXY_WEB_URL points at the proxy-router API port +yarn install +yarn dev +``` + +The Electron app launches into onboarding. Confirm: +- Lower-left shows your ERC-20 wallet. +- Wallet tab shows MOR + ETH balances. +- Chat tab is set to `Provider: (local)` by default. + +## Step D — CLI (terminal 4) + +```bash +cd /Morpheus-Lumerin-Node/cli +cp .env.example .env +vi .env # confirm API_HOST is http://localhost:8082 +make build +./mor-cli -h +./mor-cli healthcheck +``` + +## Cleaning and troubleshooting + +- Save your wallet mnemonic before any cleanup. +- `rm -rf ./node_modules` from inside `MorpheusUI` if dependencies get stuck. +- `rm -rf ~/Library/Application\ Support/MorpheusUI` to start with a fresh wallet store. +- Dangling processes: `ps -ax | grep electron` / `ps -ax | grep proxy-router` then `kill -9 `. +- Locked log files in `./data/`: `lsof | grep /proxy-router/data/` and kill the holding process. + +For more, see [Troubleshooting](/reference/troubleshooting). diff --git a/docs/consumers/install/windows.mdx b/docs/consumers/install/windows.mdx new file mode 100644 index 00000000..980a138a --- /dev/null +++ b/docs/consumers/install/windows.mdx @@ -0,0 +1,45 @@ +--- +title: "Windows install" +description: "Run a packaged Morpheus Lumerin Node consumer release on Windows." +audience: ["consumer"] +product: ["proxy-router", "ui-desktop"] +last_verified: "v7.0.0" +--- + +The packaged Windows release contains the proxy-router, MorpheusUI, and an optional bundled `llama.cpp` server. For source builds, see [macOS install](/consumers/install/macos) and adapt the toolchain. + +## Steps + + + + Get the latest Windows zip from [Releases](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/releases). Mainnet builds have no suffix; testnet builds end in `-test`. + + + Recommended location: `%USERPROFILE%\Downloads\morpheus`. + + + Edit only if you need a custom ETH node, log path, or non-default ports. See [Env: proxy-router](/reference/env-proxy-router). + + + Double-click `mor-launch.exe`. Windows Defender may prompt — allow it. To also start the bundled local model: + ```cmd + mor-launch.exe local + ``` + + + Accept terms, set a UI password, create or recover a wallet. Save the mnemonic somewhere safe. + + + Open `http://localhost:8082/swagger/index.html`. Try the **Local Model** in the Chat tab to verify the local pipeline. + + + +## Cleanup + +```cmd +del .cookie proxy.conf +rmdir /s /q data +rmdir /s /q %USERPROFILE%\AppData\Roaming\morpheus-ui +``` + +See also: [Troubleshooting](/reference/troubleshooting). diff --git a/docs/consumers/quickstart.mdx b/docs/consumers/quickstart.mdx new file mode 100644 index 00000000..8f2bdbe8 --- /dev/null +++ b/docs/consumers/quickstart.mdx @@ -0,0 +1,130 @@ +--- +title: "Consumer quickstart" +description: "Install the bundled Consumer release (proxy-router + MorpheusUI + optional local llama.cpp), fund a wallet, and chat." +audience: ["consumer"] +product: ["proxy-router", "ui-desktop"] +last_verified: "v7.0.0" +source: "docs/04-consumer-setup.md" +--- + +This is the simplest way to get started with the Morpheus Lumerin Node as a consumer. It runs three pieces of software on your local machine: + +- `proxy-router` — same binary as the provider side, configured for the consumer role. +- `MorpheusUI` — Electron GUI to browse bids, open sessions, and chat. +- *(Optional)* `llama.cpp` — bundled sample model for free local-only testing. Started by passing `local` to `mor-launch`. + +## Installation + + + + Grab the latest archive for your OS from the [GitHub releases page](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/releases). + - Mainnet builds have no suffix (e.g. `v7.0.0`). + - Testnet builds end in `-test` (e.g. `v7.0.0-test`). + + + + + ```bash + cd ~/Downloads/morpheus + xattr -c mor-launch mor-cli proxy-router MorpheusUI.app + ``` + + + ```bash + cd ~/Downloads/morpheus + ``` + + + Extract to `%USERPROFILE%/Downloads/morpheus`. + + + + + Inspect the bundled `.env` and edit only if you need advanced behavior (custom log destination, private ETH node, alternate ports). Reference: [Env: proxy-router](/reference/env-proxy-router). + + + + + ```bash + ./mor-launch + # Or, to also start the bundled local model: + ./mor-launch local + ``` + + + Double-click `mor-launch.exe`. Allow Defender. To run the bundled local model: `mor-launch.exe local`. + + + A terminal window will show the proxy-router (and local model if requested) starting; MorpheusUI will launch on top. + + + - Read & accept the terms. + - Set a strong password (this protects MorpheusUI's local key store; it is not your wallet password). + - Either **create** a new wallet (write down the mnemonic) or **recover** an existing top-level wallet via mnemonic. + - **Optional** CLI: in another terminal, `./mor-cli` (Linux/macOS). + + + +## Validation + + + + Open `http://localhost:8082/swagger/index.html` — the Swagger UI should render. + Logs in `./data/` capture detail. See [Troubleshooting](/reference/troubleshooting). + + + In MorpheusUI's **Chat** tab, ensure **Local Model** is selected. Type a prompt and press Enter. A response confirms the local model + proxy-router pipeline works. + + + Click **Change Model**, select a remote provider model, click **Change**, then **Open Session**. Stake at least `5` MOR (contract minimum). Chat away. + + + - Manually close all remote sessions: in the Chat window, click the time icon next to the model line, then the **X** next to each open session. + - Closing the MorpheusUI window leaves the launcher CMD open. Use `Ctrl-C` there to stop the local model and proxy-router. + + + +## Cleanup + +If you need to reset to a fresh state (different release, broken state): + + +**Save your wallet mnemonic / private key first.** Cleanup deletes the local key store. + + + + + ```bash + rm .cookie proxy.conf + rm -rf ~/Library/Logs/morpheus-ui + rm -rf ~/Library/Application\ Support/morpheus-ui + rm -rf data + xattr -c proxy-router MorpheusUI.app mor-launch mor-cli + ``` + Linux: also check `~/.config/morpheus-ui`. + + + ```cmd + del .cookie proxy.conf + rmdir /s /q data + rmdir /s /q %USERPROFILE%\AppData\Roaming\morpheus-ui + ``` + + + +## Next steps + + + + Walk through opening a session and selecting a remote model. + + + Prompts, streaming, audio, embeddings. + + + Build the binaries yourself for development. + + + Proxy-router not starting? Wallet not funded? + + diff --git a/docs/consumers/troubleshooting.mdx b/docs/consumers/troubleshooting.mdx new file mode 100644 index 00000000..8108c282 --- /dev/null +++ b/docs/consumers/troubleshooting.mdx @@ -0,0 +1,50 @@ +--- +title: "Consumer troubleshooting" +description: "The most common consumer-side problems and their fixes." +audience: ["consumer"] +product: ["proxy-router", "ui-desktop"] +last_verified: "v7.0.0" +--- + +This page focuses on consumer-side symptoms. For provider-side or deeper proxy-router operational issues, see the full [Reference: troubleshooting](/reference/troubleshooting). + +## "Where is my MOR?" / wallet balance dropped + +You almost certainly opened a session. The MOR is escrowed in the Diamond contract, not lost. See: +- [Sessions: stake, close, claim](/concepts/sessions-stake-close-recover) +- [Where is my MOR?](/ai/where-is-my-mor) +- [Why is my MOR locked in the contract?](/ai/why-locked-in-contract) + +## MorpheusUI shows zero balance after recovering my wallet + +You probably recovered a **derived** address from your mnemonic. MorpheusUI only resolves the top-level address from a mnemonic. Use a tier-1 wallet, or import the private key directly. + +## "Provider not responding" or stuck mid-prompt + +- Confirm the proxy-router is still running (check the launcher CMD window or `http://localhost:8082/healthcheck`). +- The provider may be down. Close the session early; an immediate partial refund hits your wallet, and any timelocked slice in `userStakesOnHold` becomes claimable via `withdrawUserStakes` after ~1 UTC day: + ```bash + curl -X POST 'http://localhost:8082/blockchain/sessions//close' \ + -H 'Authorization: Basic ' -d '{}' + ``` +- Try a different model from a different provider. + +## Local model returns nonsense + +The bundled `tinyllama` is a **demonstration model only**. It will hallucinate, miscount, and contradict itself. Don't compare it to a real Morpheus model. See [Local vs on-chain models](/concepts/local-vs-onchain-models). + +## Swagger / API not reachable on `:8082` + +- Check the launcher terminal for proxy-router errors. +- Common cause: invalid ETH node URL or wrong chain/contract addresses. See [proxy-router env reference](/reference/env-proxy-router). +- macOS: ensure `xattr -c` removed quarantine flags from the binaries. + +## `xattr` / quarantine errors on macOS + +```bash +xattr -c mor-launch mor-cli proxy-router MorpheusUI.app +``` + +## I want to start over completely + +Save the mnemonic first, then follow [Cleanup](/consumers/quickstart#cleanup). diff --git a/docs/docs.json b/docs/docs.json new file mode 100644 index 00000000..d2848036 --- /dev/null +++ b/docs/docs.json @@ -0,0 +1,280 @@ +{ + "$schema": "https://mintlify.com/docs.json", + "theme": "mint", + "name": "Morpheus Lumerin Node", + "description": "The canonical Morpheus DeAI knowledge base for humans and AI agents. Curated, role-based docs covering consumers, prosumers, providers, the proxy-router API, TEE attestation, and the broader Morpheus ecosystem.", + "colors": { + "primary": "#7C3AED", + "light": "#A78BFA", + "dark": "#4C1D95" + }, + "favicon": "/images/favicon.png", + "navigation": { + "tabs": [ + { + "tab": "Docs", + "groups": [ + { + "group": "Get started", + "pages": [ + "get-started/introduction", + "get-started/quickstart-consumer", + "get-started/quickstart-provider", + "get-started/networks-and-tokens" + ] + }, + { + "group": "Inference API (hosted)", + "pages": [ + "inference-api/overview" + ] + }, + { + "group": "Concepts", + "pages": [ + "concepts/what-is-morpheus", + "concepts/architecture", + "concepts/sessions-stake-close-recover", + "concepts/local-vs-onchain-models", + "concepts/tee-overview", + "concepts/tokens-and-fees", + "concepts/rewards-and-economics" + ] + }, + { + "group": "Consumers", + "pages": [ + "consumers/quickstart", + { + "group": "Install", + "pages": [ + "consumers/install/macos", + "consumers/install/windows", + "consumers/install/linux", + "consumers/install/docker" + ] + }, + "consumers/install-from-source", + "consumers/buy-bid", + "consumers/chat", + "consumers/troubleshooting" + ] + }, + { + "group": "Prosumers", + "pages": [ + "prosumers/overview", + "prosumers/c-node-setup", + "prosumers/gateway-for-everclaw", + "prosumers/running-local-agents" + ] + }, + { + "group": "Providers - Resale", + "pages": [ + "providers/resale/overview", + "providers/resale/container-pnode", + "providers/resale/reselling-venice", + "providers/resale/registering-bid" + ] + }, + { + "group": "Providers - Full P-Node", + "pages": [ + "providers/full/quickstart", + "providers/full/model-setup", + "providers/full/proxy-router-docker", + "providers/full/proxy-router-akash", + "providers/full/aws", + "providers/full/tee-reference", + "providers/full/secretvm-quickstart", + "providers/full/headless", + "providers/full/myprovider-gui", + "providers/full/register-onchain", + "providers/full/verify-setup", + "providers/full/pricing" + ] + }, + { + "group": "AI knowledge", + "pages": [ + "ai/myths", + "ai/where-is-my-mor", + "ai/session-states-open-close-recover", + "ai/why-locked-in-contract", + "ai/local-vs-blockchain-models", + "ai/llm-prompt-cheatsheet" + ] + }, + { + "group": "Ecosystem", + "pages": [ + "ecosystem/overview", + "ecosystem/mor-org", + "ecosystem/active-status", + "ecosystem/tech-mor-org", + "ecosystem/myprovider", + "ecosystem/everclaw", + "ecosystem/nodeneo", + "ecosystem/app-mor-org", + "ecosystem/attribution" + ] + }, + { + "group": "Reference", + "pages": [ + "reference/api-overview", + "reference/api-auth", + "reference/env-proxy-router", + "reference/env-ui-desktop", + "reference/models-config", + "reference/rating-config", + "reference/api-direct", + "reference/api-endpoints", + "reference/troubleshooting", + "reference/glossary" + ] + } + ] + } + ], + "global": { + "anchors": [ + { + "anchor": "GitHub", + "href": "https://github.com/MorpheusAIs/Morpheus-Lumerin-Node", + "icon": "github" + }, + { + "anchor": "Releases", + "href": "https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/releases", + "icon": "tag" + }, + { + "anchor": "mor.org", + "href": "https://mor.org", + "icon": "globe" + }, + { + "anchor": "Inference API", + "href": "https://apidocs.mor.org", + "icon": "plug" + } + ] + } + }, + "logo": { + "light": "/images/logo-light.png", + "dark": "/images/logo-dark.png", + "href": "/" + }, + "navbar": { + "links": [ + { + "label": "Releases", + "href": "https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/releases" + }, + { + "label": "Status", + "href": "https://active.mor.org/status" + } + ], + "primary": { + "type": "github", + "href": "https://github.com/MorpheusAIs/Morpheus-Lumerin-Node" + } + }, + "footer": { + "socials": { + "github": "https://github.com/MorpheusAIs", + "x": "https://x.com/MorpheusAIs" + }, + "links": [ + { + "header": "Product", + "items": [ + { + "label": "app.mor.org", + "href": "https://app.mor.org" + }, + { + "label": "MyProvider", + "href": "https://myprovider.mor.org" + }, + { + "label": "Inference API (hosted)", + "href": "https://apidocs.mor.org" + } + ] + }, + { + "header": "Network", + "items": [ + { + "label": "Status", + "href": "https://active.mor.org/status" + }, + { + "label": "Active models", + "href": "https://active.mor.org/active_models" + }, + { + "label": "Active bids", + "href": "https://active.mor.org/active_bids" + } + ] + }, + { + "header": "Ecosystem", + "items": [ + { + "label": "tech.mor.org", + "href": "https://tech.mor.org" + }, + { + "label": "NodeNeo", + "href": "https://nodeneo.io" + }, + { + "label": "Everclaw", + "href": "https://everclaw.xyz" + } + ] + } + ] + }, + "search": { + "prompt": "Ask anything about Morpheus, the proxy-router, sessions, or providers..." + }, + "redirects": [ + { "source": "/00-overview", "destination": "/concepts/architecture" }, + { "source": "/01-model-setup", "destination": "/providers/full/model-setup" }, + { "source": "/02-provider-setup", "destination": "/providers/full/quickstart" }, + { "source": "/02.1-proxy-router-docker", "destination": "/providers/full/proxy-router-docker" }, + { "source": "/02.2-proxy-router-akash", "destination": "/providers/full/proxy-router-akash" }, + { "source": "/02.3-proxy-router-tee", "destination": "/providers/full/tee-reference" }, + { "source": "/02.4-proxy-router-secretvm-quickstart", "destination": "/providers/full/secretvm-quickstart" }, + { "source": "/02.5-api-auth", "destination": "/reference/api-auth" }, + { "source": "/03-provider-offer", "destination": "/providers/full/register-onchain" }, + { "source": "/04-consumer-setup", "destination": "/consumers/quickstart" }, + { "source": "/04a-consumer-setup-source", "destination": "/consumers/install-from-source" }, + { "source": "/05-bid-purchase", "destination": "/consumers/buy-bid" }, + { "source": "/06-model-interaction", "destination": "/consumers/chat" }, + { "source": "/99-troubleshooting", "destination": "/reference/troubleshooting" }, + { "source": "/proxy-router.all.env", "destination": "/reference/env-proxy-router" }, + { "source": "/ui-desktop.all.env", "destination": "/reference/env-ui-desktop" }, + { "source": "/models-config.json", "destination": "/reference/models-config" }, + { "source": "/rating-config.json", "destination": "/reference/rating-config" }, + { "source": "/proxy-router-api-direct", "destination": "/reference/api-direct" }, + { "source": "/proxy-router-api-endpoints", "destination": "/reference/api-endpoints" }, + { "source": "/mac-boot-strap", "destination": "/consumers/install/macos" }, + { "source": "/User%20Compute%20Note%20Setup%20via%20AWS", "destination": "/providers/full/aws" }, + { "source": "/User-Compute-Note-Setup-via-AWS", "destination": "/providers/full/aws" } + ], + "contextual": { + "options": ["copy", "view", "chatgpt", "claude"] + }, + "seo": { + "indexing": "navigable" + } +} diff --git a/docs/ecosystem/active-status.mdx b/docs/ecosystem/active-status.mdx new file mode 100644 index 00000000..619e435d --- /dev/null +++ b/docs/ecosystem/active-status.mdx @@ -0,0 +1,41 @@ +--- +title: "active.mor.org (live status)" +description: "Mirror summary of active.mor.org — live status, active models, and active bids on the Morpheus marketplace." +audience: ["consumer", "prosumer", "provider-full", "provider-resale", "developer"] +product: ["proxy-router"] +last_verified: "v7.0.0" +source_url: "https://active.mor.org" +--- + + +**Mirrored summary.** Live numbers (counts, prices, latencies) live at [active.mor.org](https://active.mor.org). This page describes the **semantics** of those numbers and how to interpret them. + + +## What's there + +| Endpoint | What it shows | Useful for | +|----------|---------------|-----------| +| [active.mor.org/status](https://active.mor.org/status) | Overall network status | Spotting outages, monitoring uptime | +| [active.mor.org/active_models](https://active.mor.org/active_models) | Models that have active bids and at least one healthy provider | Choosing what to consume; evaluating competition as a provider | +| [active.mor.org/active_bids](https://active.mor.org/active_bids) | Currently posted bids across all models | Pricing decisions; reseller competitive analysis | + +## How to read it + +- **A model "active" here means `(at least one bid posted) AND (provider healthcheck passes)`.** A model on chain that has no healthy provider won't show up here even if its `Diamond` record exists. +- **`pricePerSecond`** values are denominated in MOR. To compare across models with different token economies, multiply by tokens-per-second to get an apples-to-apples cost. +- **Latency / throughput** numbers are aggregated; a single hot provider can pull averages dramatically up or down. + +## When to cite this page + +For an LLM answering "what models are available?" or "what's the going rate?" — **link out** to the appropriate sub-path of `active.mor.org`. Never invent counts or prices. + +## Related canonical pages on this site + +- [Architecture](/concepts/architecture) +- [Pricing a resale bid](/providers/resale/registering-bid) +- [Buy a bid](/consumers/buy-bid) +- [Glossary](/reference/glossary) + +## Source + +- [https://active.mor.org](https://active.mor.org) diff --git a/docs/ecosystem/app-mor-org.mdx b/docs/ecosystem/app-mor-org.mdx new file mode 100644 index 00000000..8ff0b6ae --- /dev/null +++ b/docs/ecosystem/app-mor-org.mdx @@ -0,0 +1,43 @@ +--- +title: "app.mor.org" +description: "Mirror summary of app.mor.org — the hosted Morpheus consumer chat UI." +audience: ["consumer"] +product: ["proxy-router"] +last_verified: "v7.0.0" +source_url: "https://app.mor.org" +--- + + +**Mirrored summary** of [app.mor.org](https://app.mor.org). For current screens and feature behavior, defer to the live site. + + +## What it is + +`app.mor.org` is the hosted **Morpheus Chat App** — a browser-based consumer chat UI powered by the [hosted Morpheus Inference API Gateway](/inference-api/overview). It is the **lowest-friction** way to try Morpheus: no install, no `mor-launch`, no proxy-router on your local machine, no on-chain wallet management. + +## How it differs from MorpheusUI + +| | `app.mor.org` (hosted Chat App) | MorpheusUI (this repo) | +|---|---|---| +| Install | None | Download release | +| Wallet | Account on app.mor.org (no on-chain wallet needed for chat) | Self-custodial wallet (mnemonic / private key) | +| Local model | No | Yes (bundled `tinyllama`) | +| Backed by | Hosted [Inference API](/inference-api/overview) gateway | Direct on-chain sessions through your own proxy-router | +| Pricing | Credits/billing on the Inference API (see [apidocs.mor.org](https://apidocs.mor.org)) | MOR per session-second | +| Underlying network | Same Morpheus marketplace | Same Morpheus marketplace | + +## When to cite which + +- "I just want to try Morpheus right now" → `app.mor.org`. +- "I want a desktop app, optional offline local-only test, full control" → MorpheusUI. +- "I want it on my phone / cross-device" → [NodeNeo](/ecosystem/nodeneo). + +## Related canonical pages on this site + +- [What is Morpheus?](/concepts/what-is-morpheus) +- [Consumer quickstart](/consumers/quickstart) +- [Where is my MOR?](/ai/where-is-my-mor) — same diagnostics apply regardless of client + +## Source + +- [https://app.mor.org](https://app.mor.org) diff --git a/docs/ecosystem/attribution.mdx b/docs/ecosystem/attribution.mdx new file mode 100644 index 00000000..1065e916 --- /dev/null +++ b/docs/ecosystem/attribution.mdx @@ -0,0 +1,43 @@ +--- +title: "Ecosystem attribution" +description: "Sources, licenses, and refresh policy for the mirrored ecosystem pages." +audience: ["consumer", "prosumer", "provider-full", "provider-resale", "developer"] +product: ["proxy-router"] +last_verified: "v7.0.0" +--- + +The pages under [Ecosystem](/ecosystem/overview) are **curated summaries** of public material from the broader Morpheus ecosystem. We mirror **conceptual content** (what something is for, how it relates to the rest of Morpheus); we **do not** snapshot live data (counts, prices, status). + +## Refresh policy + +- Each mirrored page has `last_verified` frontmatter naming the Morpheus Lumerin Node release the content was confirmed against. +- All mirrored pages are reviewed at least once per release and rerun against their `source_url`. +- If a `source_url` changes substantially, we either update the mirror or remove it (to avoid drift). + +## What we mirror + +- High-level descriptions of what each surface is for. +- The relationship between each surface and this repo's code. +- Stable conceptual content (architecture, sessions, TEE). + +## What we do not mirror + +- Live network numbers (model counts, bid prices, latencies). +- Marketing copy that changes frequently. +- Anything that's better consumed live (calculators, dashboards). + +## Sources + +| Page | Source URL | +|------|-----------| +| [mor.org](/ecosystem/mor-org) | https://mor.org | +| [active.mor.org](/ecosystem/active-status) | https://active.mor.org | +| [tech.mor.org](/ecosystem/tech-mor-org) | https://tech.mor.org | +| [MyProvider](/ecosystem/myprovider) | https://myprovider.mor.org | +| [Everclaw](/ecosystem/everclaw) | https://everclaw.xyz | +| [NodeNeo](/ecosystem/nodeneo) | https://nodeneo.io | +| [app.mor.org](/ecosystem/app-mor-org) | https://app.mor.org | + +## Reporting issues + +If a mirrored page contradicts the upstream source, the upstream source is correct — please [open an issue](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/issues) so we can refresh the mirror. diff --git a/docs/ecosystem/everclaw.mdx b/docs/ecosystem/everclaw.mdx new file mode 100644 index 00000000..805f3c86 --- /dev/null +++ b/docs/ecosystem/everclaw.mdx @@ -0,0 +1,48 @@ +--- +title: "Everclaw" +description: "Mirror summary of Everclaw — an agent project with a Morpheus skill for OpenClaw." +audience: ["prosumer", "developer"] +product: ["proxy-router"] +last_verified: "v7.0.0" +source_url: "https://everclaw.xyz" +--- + + +**Mirrored summary** of [everclaw.xyz](https://everclaw.xyz). For current SDK shape, skill catalog, and pricing, defer to the live site. + + +## What it is + +Everclaw is an agent-focused project; it includes a Morpheus skill for **OpenClaw** that lets agents use Morpheus inference through a local HTTP endpoint. From the Morpheus side, Everclaw is a **prosumer / agent integration** — the kind of tool you point at a [C-Node](/prosumers/c-node-setup). + +## How a Morpheus + Everclaw setup works + +```mermaid +flowchart LR + Skill[Everclaw / OpenClaw skill] --> Local["http://127.0.0.1:8082"] + Local --> CRouter[Your C-Node proxy-router] + CRouter --> Network[Morpheus providers on BASE] +``` + +Steps and patterns are documented in [Gateway for Everclaw](/prosumers/gateway-for-everclaw). + +## Relationship to this site + +- This site documents the **C-Node side** — running a proxy-router that Everclaw can talk to, scoping permissions, picking models. +- Everclaw's site is the source of truth for the **skill side** — installation, configuration, available agent capabilities. + +## When to cite Everclaw + +When a user asks "can I use Morpheus with my AI agents?", show: +1. The C-Node setup pattern from this site ([C-Node setup](/prosumers/c-node-setup), [Gateway for Everclaw](/prosumers/gateway-for-everclaw)). +2. A link to [everclaw.xyz](https://everclaw.xyz) for the skill itself. + +## Related canonical pages on this site + +- [Gateway for Everclaw](/prosumers/gateway-for-everclaw) +- [Running local agents](/prosumers/running-local-agents) +- [API auth](/reference/api-auth) — for scoped agent users + +## Source + +- [https://everclaw.xyz](https://everclaw.xyz) diff --git a/docs/ecosystem/mor-org.mdx b/docs/ecosystem/mor-org.mdx new file mode 100644 index 00000000..ed8e0f6b --- /dev/null +++ b/docs/ecosystem/mor-org.mdx @@ -0,0 +1,34 @@ +--- +title: "mor.org" +description: "Mirror summary of mor.org — the marketing and orientation hub for the Morpheus DeAI network." +audience: ["consumer", "prosumer", "provider-full", "provider-resale"] +product: ["proxy-router", "ui-desktop"] +last_verified: "v7.0.0" +source_url: "https://mor.org" +--- + + +**Mirrored summary.** This page summarizes public information about [mor.org](https://mor.org). For current details — community channels, partnership announcements, MOR price, total supply — defer to the live site. + + +## What it is + +[mor.org](https://mor.org) is the public-facing entry point for the Morpheus network. It's where new users land to understand what Morpheus is, who's behind it, and where to go next. + +## What you can do there + +- Read the project overview and pitch. +- Find links to the main user surfaces: [app.mor.org](https://app.mor.org) (hosted chat), [tech.mor.org](https://tech.mor.org) (calculators / tech docs), [active.mor.org](https://active.mor.org) (live network status), [myprovider.mor.org](https://myprovider.mor.org) (provider operator GUI), [apidocs.mor.org](https://apidocs.mor.org) (hosted [Morpheus Inference API](/inference-api/overview)). +- Find the white paper and economic model documentation. +- Find community channels (Discord, X, etc.). + +## Related canonical pages on this site + +- [What is Morpheus?](/concepts/what-is-morpheus) +- [Architecture](/concepts/architecture) +- [Networks and tokens](/get-started/networks-and-tokens) +- [Tokens, fees, and economics](/concepts/tokens-and-fees) + +## Source + +- [https://mor.org](https://mor.org) diff --git a/docs/ecosystem/myprovider.mdx b/docs/ecosystem/myprovider.mdx new file mode 100644 index 00000000..d0884a60 --- /dev/null +++ b/docs/ecosystem/myprovider.mdx @@ -0,0 +1,51 @@ +--- +title: "MyProvider" +description: "Mirror summary of myprovider.mor.org — hosted operator GUI for managing Morpheus provider nodes." +audience: ["provider-full", "provider-resale"] +product: ["proxy-router"] +last_verified: "v7.0.0" +source_url: "https://myprovider.mor.org" +--- + + +**Mirrored summary** of [myprovider.mor.org](https://myprovider.mor.org). For current screens and feature behavior, defer to the live site. + + +## What it is + +A hosted operator dashboard for Morpheus providers. Lets you manage providers, models, bids, and sessions through a GUI rather than scripting against the proxy-router HTTP API. + +## What it gives you + +- **Provider dashboard** — register / update your provider record, view stake, status, and earnings. +- **Model management** — register, tag (including `tee`), and update models. +- **Bid management** — post, edit, and retire bids. +- **Session monitoring** — see active and historical sessions, pending claims, and earnings. +- **Health pings** — quick visibility into whether your `:3333` and `/healthcheck` are reachable. + +## How it relates to this site + +- Conceptually it does the same thing as [Register on chain](/providers/full/register-onchain) and [API endpoints](/reference/api-endpoints). +- Authenticates against your provider's wallet — connect a wallet that owns the provider record on chain. +- Read the privacy and TOS on the site directly before connecting any wallet you care about. + +## When to use MyProvider vs the API + +| Task | Best surface | +|------|--------------| +| First-time provider registration | MyProvider GUI or Swagger | +| Update bids in bulk | API/script | +| TEE attestation inspection | [SecretVM portal](https://secretai.scrtlabs.com/attestation) + cosign | +| Day-to-day operator monitoring | MyProvider GUI | +| Programmatic automation | API ([endpoints reference](/reference/api-endpoints)) | + +## Related canonical pages on this site + +- [MyProvider GUI](/providers/full/myprovider-gui) +- [Register on chain](/providers/full/register-onchain) +- [Headless operation](/providers/full/headless) +- [API endpoints](/reference/api-endpoints) + +## Source + +- [https://myprovider.mor.org](https://myprovider.mor.org) diff --git a/docs/ecosystem/nodeneo.mdx b/docs/ecosystem/nodeneo.mdx new file mode 100644 index 00000000..65013c99 --- /dev/null +++ b/docs/ecosystem/nodeneo.mdx @@ -0,0 +1,38 @@ +--- +title: "NodeNeo" +description: "Mirror summary of NodeNeo — a cross-platform consumer experience for Morpheus." +audience: ["consumer", "prosumer"] +product: ["proxy-router"] +last_verified: "v7.0.0" +source_url: "https://nodeneo.io" +--- + + +**Mirrored summary**, last verified for v7.0.0. For current platforms, screenshots, and feature lists, defer to [nodeneo.io](https://nodeneo.io) (transitioning from `nodeneo.io` formerly under different branding). + + +## What it is + +NodeNeo is a cross-platform consumer-side experience for Morpheus — a complementary surface to MorpheusUI (this repo's Electron desktop app) and `app.mor.org` (the hosted web UI). It targets users who want a polished mobile / cross-device consumer experience while still using the Morpheus marketplace under the hood. + +## How it relates to this repo + +- Under the hood, NodeNeo speaks to a Morpheus C-Node — the same proxy-router code documented on this site. +- A user can be a NodeNeo user while also running MorpheusUI on a desktop; they are separate clients sharing a common wallet (if configured). + +## When to cite NodeNeo + +When a user wants: +- A consumer experience away from a desktop Electron app, **link NodeNeo**. +- A self-hosted, full-featured desktop client with bundled local model, **link MorpheusUI** (this repo). +- A zero-install hosted client to "just try Morpheus," **link [app.mor.org](/ecosystem/app-mor-org)**. + +## Related canonical pages on this site + +- [What is Morpheus?](/concepts/what-is-morpheus) +- [Consumer quickstart](/consumers/quickstart) — for the desktop counterpart +- [app.mor.org (mirror)](/ecosystem/app-mor-org) + +## Source + +- [https://nodeneo.io](https://nodeneo.io) diff --git a/docs/ecosystem/overview.mdx b/docs/ecosystem/overview.mdx new file mode 100644 index 00000000..32ee2fe5 --- /dev/null +++ b/docs/ecosystem/overview.mdx @@ -0,0 +1,44 @@ +--- +title: "Ecosystem overview" +description: "Index of mirrored summaries of the broader Morpheus ecosystem — what each surface is for, and where to read more." +audience: ["consumer", "prosumer", "provider-full", "provider-resale"] +product: ["proxy-router", "ui-desktop"] +last_verified: "v7.0.0" +--- + +These pages are **curated mirrors** of the broader Morpheus ecosystem so AI agents reading this repo can answer ecosystem questions in one place. Each page is a **summary**, not a snapshot of live data — for current numbers we link out. + +## Mirrored surfaces + + + + The marketing / orientation hub for Morpheus. + + + Live status, active models, active bids. + + + Calculators, sessions, TEE, throughput explainers. + + + Hosted operator GUI for provider node management. + + + Agent project + OpenClaw skill for Morpheus. + + + Cross-platform consumer experience. + + + Hosted consumer chat UI. + + + Sources, licenses, refresh cadence. + + + +## Refresh cadence + +Mirrored pages are reviewed at minimum **per release** of the Morpheus Lumerin Node. The `last_verified` frontmatter on each page tracks the last time its content was reconfirmed against the upstream source. + +For live data — counts, prices, status — these mirrors **link out** rather than snapshot. A snapshot drifts; a link doesn't. diff --git a/docs/ecosystem/tech-mor-org.mdx b/docs/ecosystem/tech-mor-org.mdx new file mode 100644 index 00000000..0eb6fd2c --- /dev/null +++ b/docs/ecosystem/tech-mor-org.mdx @@ -0,0 +1,42 @@ +--- +title: "tech.mor.org (calculators, sessions, TEE, throughput)" +description: "Mirror summary of tech.mor.org — Morpheus's technical explainer site with calculators and protocol-level documentation." +audience: ["consumer", "prosumer", "provider-full", "provider-resale", "developer"] +product: ["proxy-router"] +last_verified: "v7.0.0" +source_url: "https://tech.mor.org" +--- + + +**Mirrored summary.** [tech.mor.org](https://tech.mor.org) is the canonical place for Morpheus protocol-level explainers and live calculators. This page summarizes what's there and how it relates to this site. + + +## Sections + +| Sub-area | What it covers | This site's parallel | +|----------|----------------|----------------------| +| **Calculators** | Provider revenue, token-throughput, hardware sizing | (Use the live calculators on `tech.mor.org`) | +| **Sessions** | Open / close / settle mechanics | [Sessions: stake, close, claim](/concepts/sessions-stake-close-recover) | +| **TEE** | The two-hop trust chain, RTMR3, attestation | [TEE overview](/concepts/tee-overview), [TEE reference](/providers/full/tee-reference) | +| **Throughput** | TPS / TTFT / latency expectations | [Architecture](/concepts/architecture) | + +## How they relate + +- Conceptual / architectural narratives live in **both places**, but this site is biased toward *operating* the proxy-router; `tech.mor.org` is biased toward *understanding the protocol*. +- For *live* numbers (TPS / capacity / current network state), use [active.mor.org](/ecosystem/active-status). +- Calculators are interactive on `tech.mor.org`; we don't snapshot them. + +## When to cite this page + +For protocol-level "why does it work this way?" questions, link to `tech.mor.org`. For "how do I run the proxy-router?" questions, stay on this site. + +## Related canonical pages on this site + +- [Concepts → Sessions](/concepts/sessions-stake-close-recover) +- [Concepts → TEE overview](/concepts/tee-overview) +- [Concepts → Tokens and fees](/concepts/tokens-and-fees) +- [Providers → TEE reference](/providers/full/tee-reference) + +## Source + +- [https://tech.mor.org](https://tech.mor.org) diff --git a/docs/get-started/introduction.mdx b/docs/get-started/introduction.mdx new file mode 100644 index 00000000..6b274a68 --- /dev/null +++ b/docs/get-started/introduction.mdx @@ -0,0 +1,71 @@ +--- +title: "Introduction" +description: "What the Morpheus Lumerin Node is, how the moving parts fit together, and which path to follow next." +audience: ["consumer", "prosumer", "provider-resale", "provider-full", "developer"] +product: ["proxy-router", "ui-desktop", "cli"] +last_verified: "v7.0.0" +--- + +The Morpheus Lumerin Node is the open-source software that connects you to the **Morpheus Inference Marketplace** — a decentralized, peer-to-peer marketplace where consumers and independent providers trade AI inference, coordinated by smart contracts on BASE. You interact with it through a desktop chat experience, a CLI, or a direct HTTP API on your local node. + +If you'd rather skip running a node entirely and use a simple OpenAI-compatible API key, see the **hosted [Morpheus Inference API](/inference-api/overview)** ([apidocs.mor.org](https://apidocs.mor.org)). + +For the conceptual picture (decentralization rationale, Compute Node contracts, peer-to-peer routing, reputation system, session-time pricing), see [What is Morpheus?](/concepts/what-is-morpheus). + +## What's in the box + + + + Background process that listens to the BASE blockchain, manages secure consumer/provider sessions, and routes prompts and responses. The same binary serves both sides; only configuration differs. + + + Electron desktop GUI that consumers use to browse bids, open sessions, and chat with models. + + + Command-line client that talks to the proxy-router HTTP API. + + + A throw-away local model bundled for demos so you can try the stack without paying MOR. + + + +## How the pieces talk + +```mermaid +flowchart LR + Consumer[Consumer wallet] --> UI[MorpheusUI] + UI --> ConsumerProxy[Consumer proxy-router] + ConsumerProxy --> Chain[BASE blockchain] + Chain --> ProviderProxy[Provider proxy-router] + ProviderProxy --> Model[Provider AI model] + ConsumerProxy <-->|"prompts and inference"| ProviderProxy +``` + +1. **Consumer** opens a session by staking MOR against a provider's bid on chain. +2. The **consumer proxy-router** opens a TCP connection to the **provider proxy-router** (port 3333 by default) and forwards prompts. +3. The **provider proxy-router** dispatches to the configured backend model (`apiUrl` in [`models-config.json`](/reference/models-config)) and streams the response back. +4. The **BASE blockchain** holds the source of truth for providers, models, bids, and sessions. MOR pays for usage; ETH on BASE pays for gas. + +## Pick your role + + + + No node, no wallet — OpenAI-compatible API key. + + + Install the desktop release, fund a wallet, open a session, chat. + + + Stand up a proxy-router, register a model, post a bid. + + + Deploy a hardened `-tee` image on SecretVM in minutes. + + + Resell Venice / OpenAI / Anthropic capacity on Morpheus. + + + +## Networks and addresses + +See [Networks & tokens](/get-started/networks-and-tokens) for the canonical, per-release MOR token, Diamond contract, and chain-ID values. diff --git a/docs/get-started/networks-and-tokens.mdx b/docs/get-started/networks-and-tokens.mdx new file mode 100644 index 00000000..1d56aab6 --- /dev/null +++ b/docs/get-started/networks-and-tokens.mdx @@ -0,0 +1,66 @@ +--- +title: "Networks and tokens" +description: "BASE mainnet and BASE Sepolia chain IDs, MOR token addresses, and Diamond marketplace contracts shipped with the current release." +audience: ["consumer", "prosumer", "provider-resale", "provider-full", "developer"] +product: ["proxy-router", "ui-desktop"] +last_verified: "v7.0.0" +--- + +The Morpheus Lumerin Node currently targets two networks. The values below are the **canonical addresses for the latest release** — they match what the binary and `-tee` images bake in. Always trust the release notes over any other source. + + +**Wallet**: Both consumers and providers need a BASE-compatible ERC-20 wallet funded with `MOR` (used to pay for sessions and provider stake) and `ETH` on BASE (used to pay gas). + + +## BASE Mainnet + +Used by the `main` branch and main-channel releases. + +| Item | Value | +|------|-------| +| Chain ID | `8453` | +| MOR token | `0x7431aDa8a591C955a994a21710752EF9b882b8e3` | +| Diamond marketplace contract | `0x6aBE1d282f72B474E54527D93b979A4f64d3030a` | +| Block explorer | https://base.blockscout.com/ | +| GitHub branch | https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/tree/main | + +## BASE Sepolia (testnet) + +Used by the `test` branch and `*-test` releases. + +| Item | Value | +|------|-------| +| Chain ID | `84532` | +| MOR token | `0x5C80Ddd187054E1E4aBBfFCD750498e81d34FfA3` | +| Diamond marketplace contract | `0x6e4d0B775E3C3b02683A6F277Ac80240C4aFF930` | +| Block explorer | https://base-sepolia.blockscout.com/ | +| GitHub branch | https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/tree/test | + +## Funding a wallet + + + + Use a top-level (non-derived) ERC-20 wallet. The MorpheusUI's mnemonic recover flow does **not** support secondary/derived addresses. + + + Bridge ETH to BASE Mainnet (or use a BASE Sepolia faucet for testnet). ETH pays gas. + + + Acquire MOR via supported exchanges or convert from ETH inside MorpheusUI. MOR pays for staking, bidding, and consumer sessions. + + + +## On-chain minimums + +These are enforced by the Diamond contract and may change with governance: + +| Action | Minimum | +|--------|---------| +| Provider stake | `0.2` MOR | +| Subnet provider stake | `10000` MOR | +| Model stake | `0.1` MOR | +| Marketplace bid fee | `0.3` MOR | +| Consumer session open | `5` MOR | +| Bid price floor | `0.00000001` MOR / second | + +See [Sessions: stake, close, claim](/concepts/sessions-stake-close-recover) for what these mean and when they unlock. diff --git a/docs/get-started/quickstart-consumer.mdx b/docs/get-started/quickstart-consumer.mdx new file mode 100644 index 00000000..0aa1d407 --- /dev/null +++ b/docs/get-started/quickstart-consumer.mdx @@ -0,0 +1,43 @@ +--- +title: "Consumer quickstart" +description: "The 5-minute path from zero to chatting with a remote model: download, fund a wallet, open a session, prompt." +audience: ["consumer"] +product: ["proxy-router", "ui-desktop"] +last_verified: "v7.0.0" +--- + +This is the shortest path to chat with a remote model on Morpheus. For a full walk-through (including the optional local-only model and cleanup), see [Consumer install](/consumers/quickstart). + + + + Grab the latest package for your OS from the [GitHub releases page](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/releases). Mainnet builds have no suffix (e.g. `v7.0.0`); testnet builds end in `-test`. + + + Extract the zip, then: + + + ```bash + xattr -c mor-launch mor-cli proxy-router MorpheusUI.app + ./mor-launch + ``` + + + Double-click `mor-launch.exe`. Allow Defender if prompted. + + + Add `local` (e.g. `./mor-launch local`) to also start the bundled `llama.cpp` model for free local testing. + + + In MorpheusUI, accept the terms, set a password, and either create a new wallet or recover an existing one with your mnemonic. Save the mnemonic somewhere safe. + + + Send `MOR` and `ETH` on BASE to the wallet address shown in the lower-left of the UI. See [Networks and tokens](/get-started/networks-and-tokens). + + + Click **Chat → Change Model**, pick a remote model, click **Open Session**, stake at least `5` MOR, and prompt away. To close early, expand the session line and click the **X** next to it. + + + + +Confused about MOR appearing "locked" right after opening a session? That is expected — see [Where is my MOR?](/ai/where-is-my-mor) and [Session states](/ai/session-states-open-close-recover). + diff --git a/docs/get-started/quickstart-provider.mdx b/docs/get-started/quickstart-provider.mdx new file mode 100644 index 00000000..15b83212 --- /dev/null +++ b/docs/get-started/quickstart-provider.mdx @@ -0,0 +1,54 @@ +--- +title: "Provider quickstart" +description: "The 10-minute path from zero to a registered Morpheus provider with a live bid." +audience: ["provider-full", "provider-resale"] +product: ["proxy-router"] +last_verified: "v7.0.0" +--- + +This page is the high-level checklist. For the full setup, branch into one of: + + + + Run a proxy-router on your own infrastructure, point it at your model. + + + Deploy the hardened `-tee` image on SecretVM and tag your model `tee`. + + + Resell capacity from Venice / OpenAI / Anthropic. + + + Containerized proxy-router only. + + + Two-instance EC2 setup (LLM + proxy-router). + + + +## Checklist + + + + OpenAI-compatible endpoint reachable from your proxy-router host (e.g. `http://my-model:8080/v1/chat/completions`). + + + BASE wallet with at least `~0.6` MOR (provider stake `+` model stake `+` bid fee) plus a little ETH for gas. See [Networks and tokens](/get-started/networks-and-tokens). + + + The proxy-router needs to be reachable on `host:3333` from the internet so consumers can connect. The Swagger/admin UI on `:8082` should **not** be public — see [API auth](/reference/api-auth). + + + Configure `.env`, `models-config.json`, `rating-config.json` and start the binary. See [Provider quickstart](/providers/full/quickstart). + + + Approve the Diamond contract, register your provider, register your model (with the `tee` tag if you're TEE-enabled), and post a bid. See [Register on chain](/providers/full/register-onchain). Be aware: every `postModelBid` charges a non-refundable `0.3 MOR` `marketplaceBidFee`; finish your local setup before posting your first bid to avoid paying the fee multiple times — see [Pricing](/providers/full/pricing) and [Quickstart → What can cost you MOR](/providers/full/quickstart#what-can-cost-you-mor-during-setup). + + + Don't trust startup logs alone — run the five-step self-check in [Verify your provider setup](/providers/full/verify-setup): healthcheck, public TCP, on-chain records, `active.mor.org` discovery, and a real prompt via the hosted Inference API. This is exactly the procedure Discord support runs when a new provider asks "can you check if my setup is OK?". + + + + +TEE providers must register with the model tag `"tee"` for any of the two-hop attestation chain to engage on the consumer side. See [TEE overview](/concepts/tee-overview). + diff --git a/docs/index.mdx b/docs/index.mdx new file mode 100644 index 00000000..3f3a16cb --- /dev/null +++ b/docs/index.mdx @@ -0,0 +1,69 @@ +--- +title: "Morpheus Lumerin Node Docs" +description: "The canonical knowledge base for Morpheus DeAI: consumers, providers, the proxy-router API, TEE attestation, and the broader Morpheus ecosystem. Curated for humans and AI agents." +sidebarTitle: "Welcome" +audience: ["consumer", "prosumer", "provider-resale", "provider-full", "developer"] +last_verified: "v7.0.0" +--- + +The Morpheus Lumerin Node is the open-source software that lets a desktop chat experience talk to distributed, decentralized LLMs on the Morpheus network. This documentation is the **canonical, human-and-agent-friendly source of truth** for installing, running, and operating that software. + + +**This site replaces the old `/docs/*.md` files.** All previous links such as `/04-consumer-setup` redirect to their new home. See [Get started](/get-started/introduction) or pick a role-based journey below. + + +## Pick your journey + + + + Use the **hosted** [Morpheus Inference API](https://apidocs.mor.org) — no node, no wallet, just an API key. + + + I want to chat with LLMs on Morpheus from my desktop or via `app.mor.org`. + + + I run my own C-Node and an AI gateway for Everclaw or local agents. + + + I have Venice/OpenAI/Anthropic capacity and want to resell it on Morpheus. + + + I host my own models and want to run a Full P-Node, optionally TEE-hardened. + + + +## What's here + + + + Architecture, sessions, TEE, tokens — what every user should understand once. + + + Curated subset of the proxy-router HTTP API; full schema in [`proxy-router/docs/swagger.yaml`](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/blob/main/proxy-router/docs/swagger.yaml). + + + Anti-hallucination pages: where is my MOR, session states, locked-in-contract. + + + Mirrors of mor.org, NodeNeo, Everclaw, MyProvider, with attribution. + + + Env vars, configs, troubleshooting, glossary. + + + Source, releases, and issue tracker. + + + +## Live network resources + +These pages link out to **live data** that changes too often to mirror: + +- **Status, active models, active bids** — [active.mor.org](https://active.mor.org) +- **Calculators, sessions, TEE, throughput** — [tech.mor.org](https://tech.mor.org) +- **Provider portal** — [myprovider.mor.org](https://myprovider.mor.org) +- **Hosted Inference API** (separate product, OpenAI-compatible) — [apidocs.mor.org](https://apidocs.mor.org) + +## For AI agents + +If you are an LLM or coding agent reading this repo, start with the [AI knowledge](/ai/myths) section and the [`AGENTS.md`](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/blob/main/AGENTS.md) file at the repo root. Mintlify also publishes `/llms.txt` and `/llms-full.txt` indexes for this site. diff --git a/docs/inference-api/overview.mdx b/docs/inference-api/overview.mdx new file mode 100644 index 00000000..b2e3a7b0 --- /dev/null +++ b/docs/inference-api/overview.mdx @@ -0,0 +1,95 @@ +--- +title: "Morpheus Inference API (hosted)" +description: "Use Morpheus inference via a hosted OpenAI-compatible HTTPS gateway — no node, no wallet, just an API key." +audience: ["api-user", "developer"] +product: ["inference-api"] +last_verified: "v7.0.0" +source_url: "https://apidocs.mor.org" +--- + +The **Morpheus Inference API** (also called the API Gateway) is a separate hosted product built on top of the Morpheus Inference Marketplace. It gives you OpenAI-compatible inference behind a simple base URL and API key — **no proxy-router, no wallet, no on-chain session management**. It powers integrations, lite clients, and the **Morpheus Chat App** at [app.mor.org](https://app.mor.org). Canonical docs at [apidocs.mor.org](https://apidocs.mor.org). + + +This page summarizes the product. The canonical, full documentation lives at [apidocs.mor.org](https://apidocs.mor.org). For deeper integration guides (Cursor, OpenCode, LangChain, Eliza, n8n, Open Web-UI, Brave Leo, OpenAI Python SDK, Vercel AI SDK), follow the links there. + + +## When to use the Inference API vs running a node + +| You want to... | Use | +|----------------|-----| +| Plug Morpheus into an OpenAI-compatible client without managing infra | **Inference API** ([apidocs.mor.org](https://apidocs.mor.org)) | +| Self-custody your wallet and pay providers directly on-chain | [Run a C-Node](/prosumers/c-node-setup) or [MorpheusUI](/consumers/quickstart) | +| Host models for the marketplace and earn MOR | [Run a P-Node](/providers/full/quickstart) | +| Get cryptographic TEE attestation guarantees on the inference path | [TEE provider chain](/concepts/tee-overview) (requires running your own consumer-side proxy-router) | + +The Inference API abstracts away node operation, sessions, and MOR escrow into a simple API-key model. Behind the scenes it talks to the same Morpheus marketplace this repo's proxy-router does. + +## Quickstart + +Per [apidocs.mor.org](https://apidocs.mor.org): + + + + Create an account at [app.mor.org](https://app.mor.org) and log in. + + + Generate an API key and confirm automation is enabled. + + + Either chat through the hosted **test** page, or start integrating immediately. + + + +``` +Inference API base URL: https://api.mor.org/api/v1 +``` + +## Using it with the OpenAI Python SDK + +The Inference API speaks the OpenAI HTTP shape, so any OpenAI-compatible client works: + +```python +from openai import OpenAI + +client = OpenAI( + base_url="https://api.mor.org/api/v1", + api_key="", +) + +response = client.chat.completions.create( + model="", + messages=[{"role": "user", "content": "Hello"}], +) +``` + +Same pattern for the Vercel AI SDK, LangChain, Eliza, n8n, Cursor, OpenCode, Open Web-UI, Brave Leo, etc. Specific integration guides for each: [apidocs.mor.org](https://apidocs.mor.org). + +## What this product is *not* + +- **Not the proxy-router HTTP API.** That's a different surface — a local API exposed by the [proxy-router](/concepts/architecture) on `:8082` when you self-host. If you're running a node, you talk to it directly; you do not use `api.mor.org` for that. +- **Not the only way to use Morpheus.** It's the easiest, but you give up self-custody of the wallet and direct on-chain control of sessions in exchange. Casual chat users with the same trade-off can use [app.mor.org](/ecosystem/app-mor-org) directly (no API integration needed). +- **Not the whole marketplace.** The list of models exposed through `apidocs.mor.org` / `app.mor.org` is the **bootstrap set** the gateway curated when the system launched — not every model on the marketplace. Independent providers can register additional models and bids on chain that won't appear in the gateway's catalog. To see the live full marketplace, query [active.mor.org/active_models.json](https://active.mor.org/active_models.json) and [active.mor.org/active_bids.json](https://active.mor.org/active_bids.json), or run your own proxy-router and use [`GET /blockchain/models`](/reference/api-endpoints#get-models). + +## Pricing + +The hosted API runs on a credits/billing model — see [apidocs.mor.org](https://apidocs.mor.org) for current terms. The underlying **marketplace** itself is priced per **session-time** (`pricePerSecond`), not per token — see [Tokens and fees](/concepts/tokens-and-fees). + +## Relationship to this repository + +```mermaid +flowchart LR + Client[Your OpenAI-shaped client] -->|"api key"| Gateway[Hosted API Gateway] + Gateway -.uses.-> Marketplace[Compute Node contracts on BASE] + Gateway -.uses.-> ProviderProxy[Provider proxy-routers] + SelfHost[Your own C-Node from this repo] -->|"direct"| Marketplace + SelfHost -->|"direct"| ProviderProxy +``` + +The Inference API is built on the same Morpheus marketplace this repo's proxy-router talks to. If you want to **self-host** that gateway behavior (your own wallet, your own MOR, no third-party billing, full control), follow [C-Node setup](/prosumers/c-node-setup) and call your local proxy-router instead. + +## Related + +- [What is Morpheus?](/concepts/what-is-morpheus) +- [Architecture](/concepts/architecture) +- [Hosted consumer surface — app.mor.org / Morpheus Chat App](/ecosystem/app-mor-org) +- [Self-hosted consumer alternative — C-Node setup](/prosumers/c-node-setup) diff --git a/docs/mac-boot-strap.md b/docs/mac-boot-strap.md deleted file mode 100644 index 45e3c1b9..00000000 --- a/docs/mac-boot-strap.md +++ /dev/null @@ -1,210 +0,0 @@ -## "Simple Run From Mac" - 4 terminal windows - -### Overview -- This is a simple guide to get the Llama.cpp model, Lumerin proxy-router and MorpheusUI from source running on a Mac -- This is a guide for a developer or someone familiar with the codebase and build process -- Wallet: if you’re going to start with an existing wallet from something like MetaMask (recommended)…make sure it’s a tier 1, not a derived or secondary address. Desktop-ui recover from mnemonic won’t work properly if you try to recover a secondary address with the primary mnemonic. -- Install & Configure OS-Specific Dependencies - * git (https://git-scm.com/) - * go (https://golang.org/) Version >= 1.22 - * node (https://nodejs.org/) Version >= 20 - * make (https://www.gnu.org/software/make/) - * yarn (https://yarnpkg.com/) - -- Four basic steps: - 1. Clone, build select model and run local Llama.cpp model - 2. Clone the Morpheus-Lumerin-Node repo from Github - 3. Configure, Build and run the proxy-router - 4. Configure, Build and run the MorpheusUI - 5. Configure, Build and run the cli - -## **A. LLAMA.CPP** -* Open first terminal / cli window -* You will need to know what port you want the local mode to listen on (8080 in this example) -* This work should only need to be done once as it provides a local model for validation of the local proxy-router - -**1. Clone LLamaCPP Repo & Build** -```sh -git clone https://github.com/ggerganov/llama.cpp.git -cd llama.cpp -make -j 8 -``` - -**2. Set General Variables:** -* In same CLI window set the variables that the model command line will use (or you can build out a .env file with these and the others below) - ```sh - model_host=127.0.0.1 - model_port=8080 - ``` - -**3. Set Model Specific Variables:** (pick one of the variable blocks below) -* https://huggingface.co/TheBloke - * Llama-2-7B-Chat-GGUF / llama-2-7b-chat.Q5_K_M.gguf (7.28GB RAM required) - ``` - model_url=https://huggingface.co/TheBloke - model_collection=Llama-2-7B-Chat-GGUF - model_file_name=llama-2-7b-chat.Q5_K_M.gguf - ``` - * CollectiveCognition-v1.1-Mistral-7B-GGUF / collectivecognition-v1.1-mistral-7b.Q5_K_M.gguf - ``` - model_url=https://huggingface.co/TheBloke - model_collection=CollectiveCognition-v1.1-Mistral-7B-GGUF - model_file_name=collectivecognition-v1.1-mistral-7b.Q5_K_M.gguf - ``` - * TinyLlama-1.1B-Chat-v1.0-GGUF / tinyllama-1.1b-chat-v1.0.Q4_K_M.gguf - ``` - model_url=https://huggingface.co/TheBloke - model_collection=TinyLlama-1.1B-Chat-v1.0-GGUF - model_file_name=tinyllama-1.1b-chat-v1.0.Q4_K_M.gguf - ``` - * CapybaraHermes-2.5-Mistral-7B-GGUF / capybarahermes-2.5-mistral-7b.Q5_K_M.gguf - ``` - model_url=https://huggingface.co/TheBloke - model_collection=CapybaraHermes-2.5-Mistral-7B-GGUF - model_file_name=capybarahermes-2.5-mistral-7b.Q5_K_M.gguf - ``` - - -**4. Download and run the model using the variables set above:** -```sh -wget -O models/${model_file_name} ${model_url}/${model_collection}/resolve/main/${model_file_name} -./llama-server -m models/${model_file_name} --host ${model_host} --port ${model_port} --n-gpu-layers 4096 -``` - -* OPTIONAL To leave this running in the background (and tail -f nohup.out to monitor) -```sh -wget -O models/${model_file_name} ${model_url}/${model_collection}/resolve/main/${model_file_name} -nohup ./llama-server -m models/${model_file_name} --host ${model_host} --port ${model_port} --n-gpu-layers 4096 & -tail -f nohup.out -``` - -**5. Validate that the local model is running:** -* Navigate to `http://127.0.0.1:8080` in a browser to see the model interface and test inferrence -* You should also see (in the terminal window) the interaction with the model and the responses - -## **B. PROXY-ROUTER** -* Open second terminal / cli window -* You will need to know - * Your Wallet private-key **DON'T EVER SHARE WITH ANYONE** for use in the .env file - * Your ETH node wss address (eg: `wss://rinkeby.infura.io/ws/v3/your_infura_project_id`) for use in the .env file (we are currently working on a default, public leverage of http providers, but wss is most reliable at this point) - * TCP port you want the proxy-router to listen on (3333 in this example) - * TCP port that you want the API to listen on (8082 in this example) - -**1. Clone repo from either the Lumerin Team fork or the Origin on Morpheus' Github** -- MorpheusAIs Team Development Github: `git clone https://github.com/MorpheusAIs/Morpheus-Lumerin-Node.git` -- Origin from Morpheus Github: (`git clone https://github.com/MorpheusAIs/Morpheus-Lumerin-Node.git`) -- **NOTE:** if you have already cloned and configured your .env, and want to update to the lastest revision, you can `git pull` from within the Morpheus-Lumerin-Node directory and then skip to step 4 below to build and run the updated proxy-router - -**2. Navigate to the proxy-router directory** `cd /Morpheus-Lumerin-Node/proxy-router` - -**3. Modify proxy-router environment variables** -- You will need WalletPrivateKey, WSS Eth Address and router and api listening ports -- Within the proxy-router directory, copy the `.env.example` to `.env` and edit to set the variables as needed (prompts are within the file) -```sh -cp .env.example .env -vi .env -``` -**4. Build and Run the proxy-router** -```sh -./build.sh -make run -``` -**- NOTE:** that when this launches, some anti-virus or network protection software may ask you to allow the ports to be open as well as MAC-OS firewall proteciton (watch for the pop-up windows and allow) - -**5. Validate that the proxy-router is running:** -- In the terminal window where you started the proxy-router the following messaging ensures that you're running and watching events on the blockchain -```sh -2024-08-07T11:35:49.116184 INFO proxy state: running -2024-08-07T11:35:49.116534 INFO Wallet address: -2024-08-07T11:35:49.116652 INFO started watching events, address 0x6aBE1d282f72B474E54527D93b979A4f64d3030a -2024-08-07T11:35:49.116924 INFO HTTP http server is listening: 0.0.0.0:8082 -2024-08-07T11:35:49.116962 INFO TCP tcp server is listening: 0.0.0.0:3333 -``` -- Navigate to `http://localhost:8082/swagger/index.html` in a browser to see the proxy-router interface and test the Swagger API - -**- NOTE** if you would like to interact directly with your proxy-router without the UI, see the instructions in [/docs/proxy-router-api-direct.md](/docs/proxy-router-api-direct.md) - -## **C. MorpheusUI** -* Open third terminal / cli window -* You will need to know - * TCP port that your proxy-router API interface is listening on (8082 in this example) - -**1. Navigate to MorpheusUI** -`cd /Morpheus-Lumerin-Node/MorpheusUI` - -**2. Check Environment Variables** -- Within the MorpheusUI directory, copy the `.env.example` to `.env` and check the variables as needed -- At the current time, the defaults in the .env file shold be sufficient to operate as long as none of the LLAMA.cpp or proxy-router variables for ports have changed. -- Double check that your PROXY_WEB_URL is set to `8082` or what you used for the ASwagger API interface on the proxy-router. -- This is what enables the UI to communicate to the proxy-router environment - -```sh -cp .env.example .env -vi .env -``` - -**3. Install dependicies, compile and Run the MorpheusUI** -```sh -yarn install -yarn dev -``` - -**4. Validate that the MorpheusUI is running:** -- At this point, the electon app should start and if this is the first time walking through, should run through onboarding -- Check the following: - - Lower left corner - is this your correct ERC20 Wallet Address? - - On the Wallet tab, do you show MOR and ETH balances? - - if not, you'll need to convert and transfer some ETH to MOR to get started - - On the Chat tab, your should see your `Provider: (local)` selected by default...use the "Ask me anything..." prompt to run inference - this verifies that all three layers have been setup correctly? - - Click the Change Model, select a remote model, click Start and now you should be able to interact with the model through the UI. - -**Cleaning & Troubleshooting** -- Sometimes, due to development changes or dependency issues, you may need to clean and start fresh. -- Make sure you know what your WalletPrivate key is and have it saved in a secure location. before cleaning up and restarting the ui or proxy-router - - `rm -rf ./node_modules` from within MorpheusUI - - `rm -rf '~/Library/Application Support/MorpheusUI'` to clean old MorpheusUI cache and start new wallet -- The proxy-router or MorpheusUI may not start cleanly because of existing processes or open files from previous runs of the software - - If you need to exit either proxy-router or MorpheusUI, you can use `ctrl-c` from the terminal window you started them to kill the processes… - - **Locked Processes** Doing this may leave "dangling" processes or open files to find them: - - Run `ps -ax | grep electron` or `ps -ax | grep proxy-router` which will show you the processes and particualrly the procexss id - - Run `kill -9 xxxxx` where `xxxxx` is the process ID of the un-cleaned process - - **Locked Files** In certain cases the proxy-router will not let go of the `./data/` logging files… to clean them: - - Run `lsof | grep /proxy-router/data/` to list the current open files in that directory, they should all have a common process ID (Second column on the screen) - - Run `kill -9 xxxxxx` the process id that matches to clean it all up - -## **D. CLI** -* Open 4th terminal / cli window -* You will need to know - * TCP port that your proxy-router API interface is listening on (8082 in this example) - -**1. Navigate to MorpheusUI** -`cd /Morpheus-Lumerin-Node/cli` - -**2. Check Environment Variables** -- Within the cli directory, copy the `.env.example` to `.env` and check the variables as needed -- At the current time, the defaults in the .env file shold be sufficient to operate as long as proxy-router variables for ports have changed. -- Double check that your API_HOST is set to `http://localhost:8082` or what you used for the proxy-router. -- This is what enables the CLI to communicate to the proxy-router environment - -```sh -cp .env.example .env -vi .env -``` - -**3. Build CLI** -```sh -make build -``` - -**4. Validate that the cli is working:** -```sh -./mor-cli -h -``` - -**5. Validate that the cli is connected to proxy-router:** -```sh -./mor-cli healthcheck -``` -```sh -{"Status":"healthy","Uptime":"18s","Version":"TO BE SET AT BUILD TIME"} -``` \ No newline at end of file diff --git a/docs/models-config.json.md b/docs/models-config.json.md deleted file mode 100644 index 327f6a0d..00000000 --- a/docs/models-config.json.md +++ /dev/null @@ -1,90 +0,0 @@ -# Example models config file. Local model configurations are stored in this file - -- `modelId` (required) is the model id -- `modelName` (required) is the name of the model -- `apiType` (required) is the type of the model api. Currently supported values are "prodia-sd", "prodia-sdxl", "prodia-v2" and "openai" -- `apiUrl` (required) is the url of the LLM server or model API. Full url including endpoint. -- `apiKey` (optional) is the api key for the model -- `concurrentSlots` (optional) are number of available distinct chats on the llm server and used for capacity policy -- `capacityPolicy` (optional) can be one of the following: "idle_timeout", "simple" -- There maybe other variables that should be included in the model configuration. Please refer to the json-schema for descriptions and list of required and optional fields. - -> **TEE models:** there is **no `isTee` field in this file**. TEE verification is enabled per-model on the blockchain by adding the `"tee"` tag when the model is registered in the Diamond contract. Any v7+ proxy-router will automatically derive the backend attestation endpoints from the model's `apiUrl` host (port `29343`) and perform full Phase 1 + Phase 2 attestation whenever a `tee`-tagged model is used. See [03-provider-offer.md](03-provider-offer.md) for how to set the tag and [02.3-proxy-router-tee.md](02.3-proxy-router-tee.md) / [proxy-router/docs/tee-backend-verification.md](../proxy-router/docs/tee-backend-verification.md) for the full verification flow. - -## Examples of models-config.json entries - -This file enables the morpheus-proxy-router to route requests to the correct model API. The model API can be hosted on the same server as the morpheus-proxy-router or on an external server. Please refer to the json-schema for descriptions and list of required and optional fields. - -```json -{ - "$schema": "./internal/config/models-config-schema.json", - "models": [ - { - "modelId": "0x0000000000000000000000000000000000000000000000000000000000000000", - "modelName": "llama2", - "apiType": "openai", - "apiUrl": "http://localhost:8080/v1/chat/completions" - }, - { - "modelId": "0x0000000000000000000000000000000000000000000000000000000000000001", - "modelName": "inference.sdxl.txt2img.v1", - "apiType": "prodia-v2", - "apiUrl": "https://inference.prodia.com/v2/job", - "apiKey": "FILL_ME_IN" - }, - { - "modelId": "0x0000000000000000000000000000000000000000000000000000000000000002", - "modelName": "SDXL1.0-base", - "apiType": "hyperbolic-sd", - "apiUrl": "https://api.hyperbolic.xyz/v1/image/generation", - "apiKey": "FILL_ME_IN" - "parameters": { - "cfg_scale": "5", - "steps": "30" - } - }, - { - "modelId": "0x0000000000000000000000000000000000000000000000000000000000000003", - "modelName": "claude-3-5-sonnet-20241022", - "apiType": "claudeai", - "apiUrl": "https://api.anthropic.com/v1/messages", - "apiKey": "FILL_ME_IN" - }, - { - "modelId": "0x0000000000000000000000000000000000000000000000000000000000000004", - "modelName": "inference.sd15.txt2img.v1", - "apiType": "prodia-v2", - "apiUrl": "https://inference.prodia.com/v2/job", - "apiKey": "FILL_ME_IN" - }, - { - "modelId": "0x0000000000000000000000000000000000000000000000000000000000000005", - "modelName": "gpt-4o-mini", - "apiType": "openai", - "apiUrl": "https://api.openai.com/v1/chat/completions", - "apiKey": "FILL_ME_IN" - }, - { - "modelId": "0x0000000000000000000000000000000000000000000000000000000000000006", - "modelName": "text-embedding-bge-m3", - "apiType": "openai", - "apiUrl": "https://api.venice.ai/api/v1/embeddings", - "apiKey": "FILL_ME_IN" - }, - { - "modelId": "0x0000000000000000000000000000000000000000000000000000000000000007", - "modelName": "tts-kokoro", - "apiType": "openai", - "apiUrl": "https://api.venice.ai/api/v1/audio/speech", - "apiKey": "FILL_ME_IN" - }, - { - "modelId": "0x0000000000000000000000000000000000000000000000000000000000000008", - "modelName": "whisper-1", - "apiType": "openai", - "apiUrl": "https://api.openai.com/v1/audio/transcriptions", - "apiKey": "FILL_ME_IN" - }, - ] -} -``` diff --git a/docs/package-lock.json b/docs/package-lock.json new file mode 100644 index 00000000..dcf1bafe --- /dev/null +++ b/docs/package-lock.json @@ -0,0 +1,13482 @@ +{ + "name": "morpheus-lumerin-node-docs", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "morpheus-lumerin-node-docs", + "dependencies": { + "mint": "^4.2.574" + }, + "devDependencies": { + "pagefind": "^1.3.0" + } + }, + "node_modules/@alcalzone/ansi-tokenize": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/@alcalzone/ansi-tokenize/-/ansi-tokenize-0.2.5.tgz", + "integrity": "sha512-3NX/MpTdroi0aKz134A6RC2Gb2iXVECN4QaAXnvCIxxIm3C3AVB1mkUe8NaaiyvOpDfsrqWhYtj+Q6a62RrTsw==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@ark/schema": { + "version": "0.55.0", + "resolved": "https://registry.npmjs.org/@ark/schema/-/schema-0.55.0.tgz", + "integrity": "sha512-IlSIc0FmLKTDGr4I/FzNHauMn0MADA6bCjT1wauu4k6MyxhC1R9gz0olNpIRvK7lGGDwtc/VO0RUDNvVQW5WFg==", + "license": "MIT", + "dependencies": { + "@ark/util": "0.55.0" + } + }, + "node_modules/@ark/util": { + "version": "0.55.0", + "resolved": "https://registry.npmjs.org/@ark/util/-/util-0.55.0.tgz", + "integrity": "sha512-aWFNK7aqSvqFtVsl1xmbTjGbg91uqtJV7Za76YGNEwIO4qLjMfyY8flmmbhooYMuqPCO2jyxu8hve943D+w3bA==", + "license": "MIT" + }, + "node_modules/@asyncapi/parser": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@asyncapi/parser/-/parser-3.4.0.tgz", + "integrity": "sha512-Sxn74oHiZSU6+cVeZy62iPZMFMvKp4jupMFHelSICCMw1qELmUHPvuZSr+ZHDmNGgHcEpzJM5HN02kR7T4g+PQ==", + "license": "Apache-2.0", + "dependencies": { + "@asyncapi/specs": "^6.8.0", + "@openapi-contrib/openapi-schema-to-json-schema": "~3.2.0", + "@stoplight/json": "3.21.0", + "@stoplight/json-ref-readers": "^1.2.2", + "@stoplight/json-ref-resolver": "^3.1.5", + "@stoplight/spectral-core": "^1.18.3", + "@stoplight/spectral-functions": "^1.7.2", + "@stoplight/spectral-parsers": "^1.0.2", + "@stoplight/spectral-ref-resolver": "^1.0.3", + "@stoplight/types": "^13.12.0", + "@types/json-schema": "^7.0.11", + "@types/urijs": "^1.19.19", + "ajv": "^8.17.1", + "ajv-errors": "^3.0.0", + "ajv-formats": "^2.1.1", + "avsc": "^5.7.5", + "js-yaml": "^4.1.0", + "jsonpath-plus": "^10.0.0", + "node-fetch": "2.6.7" + } + }, + "node_modules/@asyncapi/specs": { + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/@asyncapi/specs/-/specs-6.8.1.tgz", + "integrity": "sha512-czHoAk3PeXTLR+X8IUaD+IpT+g+zUvkcgMDJVothBsan+oHN3jfcFcFUNdOPAAFoUCQN1hXF1dWuphWy05THlA==", + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.11" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.28.5", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@canvas/image-data": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@canvas/image-data/-/image-data-1.1.0.tgz", + "integrity": "sha512-QdObRRjRbcXGmM1tmJ+MrHcaz1MftF2+W7YI+MsphnsCrmtyfS0d5qJbk0MeSbUeyM/jCb0hmnkXPsy026L7dA==", + "license": "MIT" + }, + "node_modules/@emnapi/runtime": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD", + "optional": true + }, + "node_modules/@floating-ui/core": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.5.tgz", + "integrity": "sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@floating-ui/utils": "^0.2.11" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.7.6", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.6.tgz", + "integrity": "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@floating-ui/core": "^1.7.5", + "@floating-ui/utils": "^0.2.11" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.11.tgz", + "integrity": "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==", + "license": "MIT", + "peer": true + }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz", + "integrity": "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.0.4" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz", + "integrity": "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.0.4" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz", + "integrity": "sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz", + "integrity": "sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.5.tgz", + "integrity": "sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==", + "cpu": [ + "arm" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.4.tgz", + "integrity": "sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.4.tgz", + "integrity": "sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==", + "cpu": [ + "s390x" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz", + "integrity": "sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.4.tgz", + "integrity": "sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz", + "integrity": "sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz", + "integrity": "sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==", + "cpu": [ + "arm" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.0.5" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.5.tgz", + "integrity": "sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.0.4" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.5.tgz", + "integrity": "sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==", + "cpu": [ + "s390x" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.0.4" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz", + "integrity": "sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.0.4" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.5.tgz", + "integrity": "sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.0.4" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz", + "integrity": "sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.0.4" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.5.tgz", + "integrity": "sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==", + "cpu": [ + "wasm32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.2.0" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.5.tgz", + "integrity": "sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==", + "cpu": [ + "ia32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz", + "integrity": "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "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==", + "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==", + "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==", + "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==", + "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/editor": { + "version": "4.2.23", + "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.23.tgz", + "integrity": "sha512-aLSROkEwirotxZ1pBaP8tugXRFCxW94gwrQLxXfrZsKkfjOYC1aRvAZuhpJOb5cu4IBTJdsCigUlf2iCOu4ZDQ==", + "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==", + "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==", + "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/figures": { + "version": "1.0.15", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.15.tgz", + "integrity": "sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==", + "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==", + "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==", + "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==", + "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.9.0", + "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.9.0.tgz", + "integrity": "sha512-X7/+dG9SLpSzRkwgG5/xiIzW0oMrV3C0HOa7YHG1WnrLK+vCQHfte4k/T80059YBdei29RBC3s+pSMvPJDU9/A==", + "license": "MIT", + "dependencies": { + "@inquirer/checkbox": "^4.3.0", + "@inquirer/confirm": "^5.1.19", + "@inquirer/editor": "^4.2.21", + "@inquirer/expand": "^4.0.21", + "@inquirer/input": "^4.2.5", + "@inquirer/number": "^3.0.21", + "@inquirer/password": "^4.0.21", + "@inquirer/rawlist": "^4.1.9", + "@inquirer/search": "^3.2.0", + "@inquirer/select": "^4.4.0" + }, + "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==", + "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==", + "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==", + "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==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", + "license": "ISC", + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@jsep-plugin/assignment": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@jsep-plugin/assignment/-/assignment-1.3.0.tgz", + "integrity": "sha512-VVgV+CXrhbMI3aSusQyclHkenWSAm95WaiKrMxRFam3JSUiIaQjoMIw2sEs/OX4XifnqeQUN4DYbJjlA8EfktQ==", + "license": "MIT", + "engines": { + "node": ">= 10.16.0" + }, + "peerDependencies": { + "jsep": "^0.4.0||^1.0.0" + } + }, + "node_modules/@jsep-plugin/regex": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@jsep-plugin/regex/-/regex-1.0.4.tgz", + "integrity": "sha512-q7qL4Mgjs1vByCaTnDFcBnV9HS7GVPJX5vyVoCgZHNSC9rjwIlmbXG5sUuorR5ndfHAIlJ8pVStxvjXHbNvtUg==", + "license": "MIT", + "engines": { + "node": ">= 10.16.0" + }, + "peerDependencies": { + "jsep": "^0.4.0||^1.0.0" + } + }, + "node_modules/@jsep-plugin/ternary": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@jsep-plugin/ternary/-/ternary-1.1.4.tgz", + "integrity": "sha512-ck5wiqIbqdMX6WRQztBL7ASDty9YLgJ3sSAK5ZpBzXeySvFGCzIvM6UiAI4hTZ22fEcYQVV/zhUbNscggW+Ukg==", + "license": "MIT", + "engines": { + "node": ">= 10.16.0" + }, + "peerDependencies": { + "jsep": "^0.4.0||^1.0.0" + } + }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", + "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", + "license": "MIT" + }, + "node_modules/@mdx-js/mdx": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-3.1.1.tgz", + "integrity": "sha512-f6ZO2ifpwAQIpzGWaBQT2TXxPv6z3RBzQKpVftEWN78Vl/YweF1uwussDx8ECAXVtr3Rs89fKyG9YlzUs9DyGQ==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdx": "^2.0.0", + "acorn": "^8.0.0", + "collapse-white-space": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "estree-util-scope": "^1.0.0", + "estree-walker": "^3.0.0", + "hast-util-to-jsx-runtime": "^2.0.0", + "markdown-extensions": "^2.0.0", + "recma-build-jsx": "^1.0.0", + "recma-jsx": "^1.0.0", + "recma-stringify": "^1.0.0", + "rehype-recma": "^1.0.0", + "remark-mdx": "^3.0.0", + "remark-parse": "^11.0.0", + "remark-rehype": "^11.0.0", + "source-map": "^0.7.0", + "unified": "^11.0.0", + "unist-util-position-from-estree": "^2.0.0", + "unist-util-stringify-position": "^4.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@mdx-js/react": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-3.1.1.tgz", + "integrity": "sha512-f++rKLQgUVYDAtECQ6fn/is15GkEH9+nZPM3MS0RcxVqoTfawHvDlSCH7JbMhAM6uJ32v3eXLvLmLvjGu7PTQw==", + "license": "MIT", + "dependencies": { + "@types/mdx": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "@types/react": ">=16", + "react": ">=16" + } + }, + "node_modules/@mintlify/cli": { + "version": "4.0.1177", + "resolved": "https://registry.npmjs.org/@mintlify/cli/-/cli-4.0.1177.tgz", + "integrity": "sha512-oLIDckFtQLL0nQPnIZpNEgLdTpLtCCQ16XuzR4UvhemYIbBI2OAnfCqtGD8kD0LqhKeKa9D7ymFX62r/b29GLg==", + "license": "Elastic-2.0", + "dependencies": { + "@inquirer/prompts": "7.9.0", + "@mintlify/common": "1.0.906", + "@mintlify/link-rot": "3.0.1085", + "@mintlify/models": "0.0.312", + "@mintlify/prebuild": "1.0.1050", + "@mintlify/previewing": "4.0.1111", + "@mintlify/validation": "0.1.709", + "adm-zip": "0.5.16", + "chalk": "5.2.0", + "color": "4.2.3", + "detect-port": "1.5.1", + "front-matter": "4.0.2", + "fs-extra": "11.2.0", + "ink": "6.3.0", + "inquirer": "12.3.0", + "js-yaml": "4.1.1", + "mdast-util-mdx-jsx": "3.2.0", + "open": "8.4.2", + "openid-client": "6.8.2", + "posthog-node": "5.17.2", + "react": "19.2.3", + "semver": "7.7.2", + "unist-util-visit": "5.0.0", + "yargs": "17.7.1", + "zod": "4.3.6" + }, + "bin": { + "mint": "bin/index.js", + "mintlify": "bin/index.js" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "keytar": "7.9.0" + } + }, + "node_modules/@mintlify/common": { + "version": "1.0.906", + "resolved": "https://registry.npmjs.org/@mintlify/common/-/common-1.0.906.tgz", + "integrity": "sha512-vclLFVOsLIKU5QdswrTqnjthTm2Zvv1+xTiYXeN8uKp+FQrassP9XOr2zAv9FYM1Z5Jv+XL085Mt/qgr5i8qvw==", + "license": "ISC", + "dependencies": { + "@asyncapi/parser": "3.4.0", + "@asyncapi/specs": "6.8.1", + "@mintlify/mdx": "3.0.4", + "@mintlify/models": "0.0.312", + "@mintlify/openapi-parser": "0.0.8", + "@mintlify/validation": "0.1.709", + "@sindresorhus/slugify": "2.2.0", + "@types/mdast": "4.0.4", + "acorn": "8.11.2", + "acorn-jsx": "5.3.2", + "color-blend": "4.0.0", + "estree-util-to-js": "2.0.0", + "estree-walker": "3.0.3", + "front-matter": "4.0.2", + "hast-util-from-html": "2.0.3", + "hast-util-to-html": "9.0.4", + "hast-util-to-text": "4.0.2", + "hex-rgb": "5.0.0", + "ignore": "7.0.5", + "js-yaml": "4.1.1", + "lodash": "4.18.1", + "mdast-util-from-markdown": "2.0.2", + "mdast-util-gfm": "3.0.0", + "mdast-util-mdx": "3.0.0", + "mdast-util-mdx-jsx": "3.1.3", + "micromark-extension-gfm": "3.0.0", + "micromark-extension-mdx-jsx": "3.0.1", + "micromark-extension-mdxjs": "3.0.0", + "openapi-types": "12.1.3", + "postcss": "8.5.14", + "rehype-stringify": "10.0.1", + "remark": "15.0.1", + "remark-frontmatter": "5.0.0", + "remark-gfm": "4.0.0", + "remark-math": "6.0.0", + "remark-mdx": "3.1.0", + "remark-parse": "11.0.0", + "remark-rehype": "11.1.1", + "remark-stringify": "11.0.0", + "sucrase": "3.34.0", + "tailwindcss": "3.4.17", + "unified": "11.0.5", + "unist-builder": "4.0.0", + "unist-util-map": "4.0.0", + "unist-util-remove": "4.0.0", + "unist-util-remove-position": "5.0.0", + "unist-util-visit": "5.0.0", + "unist-util-visit-parents": "6.0.1", + "vfile": "6.0.3", + "xss": "1.0.15" + } + }, + "node_modules/@mintlify/common/node_modules/@floating-ui/react-dom": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.8.tgz", + "integrity": "sha512-cC52bHwM/n/CxS87FH0yWdngEZrjdtLW/qVruo68qg+prK7ZQ4YGdut2GyDVpoGeAYe/h899rVeOVm6Oi40k2A==", + "license": "MIT", + "peer": true, + "dependencies": { + "@floating-ui/dom": "^1.7.6" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@mintlify/common/node_modules/@mintlify/mdx": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@mintlify/mdx/-/mdx-3.0.4.tgz", + "integrity": "sha512-tJhdpnM5ReJLNJ2fuDRIEr0zgVd6id7/oAIfs26V46QlygiLsc8qx4Rz3LWIX51rUXW/cfakjj0EATxIciIw+g==", + "license": "MIT", + "dependencies": { + "@shikijs/transformers": "^3.11.0", + "@shikijs/twoslash": "^3.12.2", + "arktype": "^2.1.26", + "hast-util-to-string": "^3.0.1", + "mdast-util-from-markdown": "^2.0.2", + "mdast-util-gfm": "^3.1.0", + "mdast-util-mdx-jsx": "^3.2.0", + "mdast-util-to-hast": "^13.2.0", + "next-mdx-remote-client": "^1.0.3", + "rehype-katex": "^7.0.1", + "remark-gfm": "^4.0.0", + "remark-math": "^6.0.0", + "remark-smartypants": "^3.0.2", + "shiki": "^3.11.0", + "unified": "^11.0.0", + "unist-util-visit": "^5.0.0" + }, + "peerDependencies": { + "@radix-ui/react-popover": "^1.1.15", + "react": "^18.3.1", + "react-dom": "^18.3.1" + } + }, + "node_modules/@mintlify/common/node_modules/@mintlify/mdx/node_modules/mdast-util-gfm": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz", + "integrity": "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==", + "license": "MIT", + "dependencies": { + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-gfm-autolink-literal": "^2.0.0", + "mdast-util-gfm-footnote": "^2.0.0", + "mdast-util-gfm-strikethrough": "^2.0.0", + "mdast-util-gfm-table": "^2.0.0", + "mdast-util-gfm-task-list-item": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@mintlify/common/node_modules/@mintlify/mdx/node_modules/mdast-util-mdx-jsx": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.2.0.tgz", + "integrity": "sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "parse-entities": "^4.0.0", + "stringify-entities": "^4.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@mintlify/common/node_modules/@radix-ui/react-arrow": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz", + "integrity": "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==", + "license": "MIT", + "peer": true, + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@mintlify/common/node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.11.tgz", + "integrity": "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-escape-keydown": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@mintlify/common/node_modules/@radix-ui/react-focus-scope": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz", + "integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@mintlify/common/node_modules/@radix-ui/react-popover": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.15.tgz", + "integrity": "sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@mintlify/common/node_modules/@radix-ui/react-popper": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.8.tgz", + "integrity": "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@floating-ui/react-dom": "^2.0.0", + "@radix-ui/react-arrow": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-rect": "1.1.1", + "@radix-ui/react-use-size": "1.1.1", + "@radix-ui/rect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@mintlify/common/node_modules/@radix-ui/react-portal": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz", + "integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@mintlify/common/node_modules/@radix-ui/react-presence": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.5.tgz", + "integrity": "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@mintlify/common/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@mintlify/common/node_modules/mdast-util-mdx-jsx": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.1.3.tgz", + "integrity": "sha512-bfOjvNt+1AcbPLTFMFWY149nJz0OjmewJs3LQQ5pIyVGxP4CdOqNVJL6kTaM5c68p8q82Xv3nCyFfUnuEcH3UQ==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "parse-entities": "^4.0.0", + "stringify-entities": "^4.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@mintlify/common/node_modules/next-mdx-remote-client": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/next-mdx-remote-client/-/next-mdx-remote-client-1.1.7.tgz", + "integrity": "sha512-12Ap5Z/tFIETMXFSBTH2IFEhJAso7MvOJ5ICyesA4q6FM4vtAcmb+4ZKa4tV1IVQJLBVqOhaEfIESZzdwjmrQQ==", + "license": "MPL 2.0", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@mdx-js/mdx": "^3.1.1", + "@mdx-js/react": "^3.1.1", + "remark-mdx-remove-esm": "^1.3.1", + "serialize-error": "^13.0.1", + "vfile": "^6.0.3", + "vfile-matter": "^5.0.1" + }, + "engines": { + "node": ">=20.9.0" + }, + "peerDependencies": { + "react": ">= 18.3.0 < 19.0.0", + "react-dom": ">= 18.3.0 < 19.0.0" + } + }, + "node_modules/@mintlify/common/node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@mintlify/common/node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "license": "MIT", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/@mintlify/common/node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/@mintlify/link-rot": { + "version": "3.0.1085", + "resolved": "https://registry.npmjs.org/@mintlify/link-rot/-/link-rot-3.0.1085.tgz", + "integrity": "sha512-5xwKrqy6oYHALfu9Da1B/z06jbwUd4yT1T0FybseH7RDPzPlLv9zchjzdKUCo48f6lIrBLS2N6uXKlp0HBidZg==", + "license": "Elastic-2.0", + "dependencies": { + "@mintlify/common": "1.0.906", + "@mintlify/models": "0.0.312", + "@mintlify/prebuild": "1.0.1050", + "@mintlify/previewing": "4.0.1111", + "@mintlify/scraping": "4.0.770", + "@mintlify/validation": "0.1.709", + "fs-extra": "11.1.0", + "unist-util-visit": "4.1.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@mintlify/link-rot/node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "license": "MIT" + }, + "node_modules/@mintlify/link-rot/node_modules/fs-extra": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.0.tgz", + "integrity": "sha512-0rcTq621PD5jM/e0a3EJoGC/1TC5ZBCERW82LQuwfGnCa1V8w7dpYH1yNu+SLb6E5dkeCBzKEyLGlFrnr+dUyw==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/@mintlify/link-rot/node_modules/unist-util-is": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-5.2.1.tgz", + "integrity": "sha512-u9njyyfEh43npf1M+yGKDGVPbY/JWEemg5nH05ncKPfi+kBbKBJoTdsogMu33uhytuLlv9y0O7GH7fEdwLdLQw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@mintlify/link-rot/node_modules/unist-util-visit": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-4.1.2.tgz", + "integrity": "sha512-MSd8OUGISqHdVvfY9TPhyK2VdUrPgxkUtWSuMHF6XAAFuL4LokseigBnZtPnJMu+FbynTkFNnFlyjxpVKujMRg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0", + "unist-util-visit-parents": "^5.1.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@mintlify/link-rot/node_modules/unist-util-visit-parents": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-5.1.3.tgz", + "integrity": "sha512-x6+y8g7wWMyQhL1iZfhIPhDAs7Xwbn9nRosDXl7qoPTSCy0yNxnKc+hWokFifWQIDGi154rdUqKvbCa4+1kLhg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@mintlify/models": { + "version": "0.0.312", + "resolved": "https://registry.npmjs.org/@mintlify/models/-/models-0.0.312.tgz", + "integrity": "sha512-D4LZStVxZwfQvBXorCxgYHeka58hplvUr/7a4PeT6hFmiRZqVgQb//3co1wHYLHvDA1IqGNbSY0+18NGMTacDw==", + "license": "Elastic-2.0", + "dependencies": { + "axios": "1.16.1", + "openapi-types": "12.1.3" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@mintlify/openapi-parser": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/@mintlify/openapi-parser/-/openapi-parser-0.0.8.tgz", + "integrity": "sha512-9MBRq9lS4l4HITYCrqCL7T61MOb20q9IdU7HWhqYMNMM1jGO1nHjXasFy61yZ8V6gMZyyKQARGVoZ0ZrYN48Og==", + "license": "MIT", + "dependencies": { + "ajv": "^8.17.1", + "ajv-draft-04": "^1.0.0", + "ajv-formats": "^3.0.1", + "jsonpointer": "^5.0.1", + "leven": "^4.0.0", + "yaml": "^2.4.5" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@mintlify/openapi-parser/node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/@mintlify/prebuild": { + "version": "1.0.1050", + "resolved": "https://registry.npmjs.org/@mintlify/prebuild/-/prebuild-1.0.1050.tgz", + "integrity": "sha512-eRs+cbRLG/Aj+W663hCTnfsrYipqhj7ambVqAjkPdSnOZy0ut8r+fp9yBsNzMkbQ4Mi7w9rHBECq5Y2NGV0KQQ==", + "license": "Elastic-2.0", + "dependencies": { + "@mintlify/common": "1.0.906", + "@mintlify/openapi-parser": "0.0.8", + "@mintlify/scraping": "4.0.770", + "@mintlify/validation": "0.1.709", + "chalk": "5.3.0", + "favicons": "7.2.0", + "front-matter": "4.0.2", + "fs-extra": "11.1.0", + "js-yaml": "4.1.1", + "openapi-types": "12.1.3", + "sharp": "0.33.5", + "sharp-ico": "0.1.5", + "unist-util-visit": "4.1.2", + "uuid": "11.1.1" + } + }, + "node_modules/@mintlify/prebuild/node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "license": "MIT" + }, + "node_modules/@mintlify/prebuild/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@mintlify/prebuild/node_modules/fs-extra": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.0.tgz", + "integrity": "sha512-0rcTq621PD5jM/e0a3EJoGC/1TC5ZBCERW82LQuwfGnCa1V8w7dpYH1yNu+SLb6E5dkeCBzKEyLGlFrnr+dUyw==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/@mintlify/prebuild/node_modules/unist-util-is": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-5.2.1.tgz", + "integrity": "sha512-u9njyyfEh43npf1M+yGKDGVPbY/JWEemg5nH05ncKPfi+kBbKBJoTdsogMu33uhytuLlv9y0O7GH7fEdwLdLQw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@mintlify/prebuild/node_modules/unist-util-visit": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-4.1.2.tgz", + "integrity": "sha512-MSd8OUGISqHdVvfY9TPhyK2VdUrPgxkUtWSuMHF6XAAFuL4LokseigBnZtPnJMu+FbynTkFNnFlyjxpVKujMRg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0", + "unist-util-visit-parents": "^5.1.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@mintlify/prebuild/node_modules/unist-util-visit-parents": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-5.1.3.tgz", + "integrity": "sha512-x6+y8g7wWMyQhL1iZfhIPhDAs7Xwbn9nRosDXl7qoPTSCy0yNxnKc+hWokFifWQIDGi154rdUqKvbCa4+1kLhg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@mintlify/previewing": { + "version": "4.0.1111", + "resolved": "https://registry.npmjs.org/@mintlify/previewing/-/previewing-4.0.1111.tgz", + "integrity": "sha512-SQoAOEFbq5B3wOojmmckKJ6GzqAqqaFEhUyD58f88gQczXKdbGLzAGHjFxxhCPtlbL3kGZ1Vg7lK0ie2GBM4/Q==", + "license": "Elastic-2.0", + "dependencies": { + "@mintlify/common": "1.0.906", + "@mintlify/prebuild": "1.0.1050", + "@mintlify/validation": "0.1.709", + "adm-zip": "0.5.16", + "better-opn": "3.0.2", + "chalk": "5.2.0", + "chokidar": "3.5.3", + "express": "4.22.0", + "front-matter": "4.0.2", + "fs-extra": "11.1.0", + "got": "13.0.0", + "ink": "6.3.0", + "ink-spinner": "5.0.0", + "is-online": "10.0.0", + "js-yaml": "4.1.1", + "openapi-types": "12.1.3", + "react": "19.2.3", + "socket.io": "4.8.0", + "tar": "7.5.15", + "unist-util-visit": "4.1.2", + "yargs": "17.7.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@mintlify/previewing/node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "license": "MIT" + }, + "node_modules/@mintlify/previewing/node_modules/fs-extra": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.0.tgz", + "integrity": "sha512-0rcTq621PD5jM/e0a3EJoGC/1TC5ZBCERW82LQuwfGnCa1V8w7dpYH1yNu+SLb6E5dkeCBzKEyLGlFrnr+dUyw==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/@mintlify/previewing/node_modules/unist-util-is": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-5.2.1.tgz", + "integrity": "sha512-u9njyyfEh43npf1M+yGKDGVPbY/JWEemg5nH05ncKPfi+kBbKBJoTdsogMu33uhytuLlv9y0O7GH7fEdwLdLQw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@mintlify/previewing/node_modules/unist-util-visit": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-4.1.2.tgz", + "integrity": "sha512-MSd8OUGISqHdVvfY9TPhyK2VdUrPgxkUtWSuMHF6XAAFuL4LokseigBnZtPnJMu+FbynTkFNnFlyjxpVKujMRg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0", + "unist-util-visit-parents": "^5.1.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@mintlify/previewing/node_modules/unist-util-visit-parents": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-5.1.3.tgz", + "integrity": "sha512-x6+y8g7wWMyQhL1iZfhIPhDAs7Xwbn9nRosDXl7qoPTSCy0yNxnKc+hWokFifWQIDGi154rdUqKvbCa4+1kLhg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@mintlify/scraping": { + "version": "4.0.770", + "resolved": "https://registry.npmjs.org/@mintlify/scraping/-/scraping-4.0.770.tgz", + "integrity": "sha512-9SnYEYBnUSXXVQ0sHHxaYkkl9+TA2u2V6ZzFZwfMiccq/IOSMeKs9JX7FWFcL7N3zzx2Jh1O1H3X/zLe8shk3w==", + "license": "Elastic-2.0", + "dependencies": { + "@mintlify/common": "1.0.906", + "@mintlify/openapi-parser": "0.0.8", + "fs-extra": "11.1.1", + "hast-util-to-mdast": "10.1.0", + "js-yaml": "4.1.1", + "mdast-util-mdx-jsx": "3.1.3", + "neotraverse": "0.6.18", + "puppeteer": "22.14.0", + "rehype-parse": "9.0.1", + "remark-gfm": "4.0.0", + "remark-mdx": "3.0.1", + "remark-parse": "11.0.0", + "remark-stringify": "11.0.0", + "unified": "11.0.5", + "unist-util-visit": "5.0.0", + "yargs": "17.7.1", + "zod": "3.24.0" + }, + "bin": { + "mintlify-scrape": "bin/cli.js" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@mintlify/scraping/node_modules/fs-extra": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz", + "integrity": "sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/@mintlify/scraping/node_modules/mdast-util-mdx-jsx": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.1.3.tgz", + "integrity": "sha512-bfOjvNt+1AcbPLTFMFWY149nJz0OjmewJs3LQQ5pIyVGxP4CdOqNVJL6kTaM5c68p8q82Xv3nCyFfUnuEcH3UQ==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "parse-entities": "^4.0.0", + "stringify-entities": "^4.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@mintlify/scraping/node_modules/remark-mdx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-3.0.1.tgz", + "integrity": "sha512-3Pz3yPQ5Rht2pM5R+0J2MrGoBSrzf+tJG94N+t/ilfdh8YLyyKYtidAYwTveB20BoHAcwIopOUqhcmh2F7hGYA==", + "license": "MIT", + "dependencies": { + "mdast-util-mdx": "^3.0.0", + "micromark-extension-mdxjs": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@mintlify/scraping/node_modules/zod": { + "version": "3.24.0", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.0.tgz", + "integrity": "sha512-Hz+wiY8yD0VLA2k/+nsg2Abez674dDGTai33SwNvMPuf9uIrBC9eFgIMQxBBbHFxVXi8W+5nX9DcAh9YNSQm/w==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/@mintlify/validation": { + "version": "0.1.709", + "resolved": "https://registry.npmjs.org/@mintlify/validation/-/validation-0.1.709.tgz", + "integrity": "sha512-qWQsR/S14Eij/PSQv97u9UMsQUQEy8OEIHQ/i+iwIfZphlc4keb/9+jJgEgqZ1/7U/AjOvjrWAwO4o3Z499sNA==", + "license": "Elastic-2.0", + "dependencies": { + "@mintlify/mdx": "3.0.4", + "@mintlify/models": "0.0.312", + "arktype": "2.1.27", + "js-yaml": "4.1.1", + "lcm": "0.0.3", + "lodash": "4.18.1", + "neotraverse": "0.6.18", + "object-hash": "3.0.0", + "openapi-types": "12.1.3", + "uuid": "11.1.1", + "zod": "3.24.0", + "zod-to-json-schema": "3.20.4" + } + }, + "node_modules/@mintlify/validation/node_modules/@floating-ui/react-dom": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.8.tgz", + "integrity": "sha512-cC52bHwM/n/CxS87FH0yWdngEZrjdtLW/qVruo68qg+prK7ZQ4YGdut2GyDVpoGeAYe/h899rVeOVm6Oi40k2A==", + "license": "MIT", + "peer": true, + "dependencies": { + "@floating-ui/dom": "^1.7.6" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@mintlify/validation/node_modules/@mintlify/mdx": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@mintlify/mdx/-/mdx-3.0.4.tgz", + "integrity": "sha512-tJhdpnM5ReJLNJ2fuDRIEr0zgVd6id7/oAIfs26V46QlygiLsc8qx4Rz3LWIX51rUXW/cfakjj0EATxIciIw+g==", + "license": "MIT", + "dependencies": { + "@shikijs/transformers": "^3.11.0", + "@shikijs/twoslash": "^3.12.2", + "arktype": "^2.1.26", + "hast-util-to-string": "^3.0.1", + "mdast-util-from-markdown": "^2.0.2", + "mdast-util-gfm": "^3.1.0", + "mdast-util-mdx-jsx": "^3.2.0", + "mdast-util-to-hast": "^13.2.0", + "next-mdx-remote-client": "^1.0.3", + "rehype-katex": "^7.0.1", + "remark-gfm": "^4.0.0", + "remark-math": "^6.0.0", + "remark-smartypants": "^3.0.2", + "shiki": "^3.11.0", + "unified": "^11.0.0", + "unist-util-visit": "^5.0.0" + }, + "peerDependencies": { + "@radix-ui/react-popover": "^1.1.15", + "react": "^18.3.1", + "react-dom": "^18.3.1" + } + }, + "node_modules/@mintlify/validation/node_modules/@radix-ui/react-arrow": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz", + "integrity": "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==", + "license": "MIT", + "peer": true, + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@mintlify/validation/node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.11.tgz", + "integrity": "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-escape-keydown": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@mintlify/validation/node_modules/@radix-ui/react-focus-scope": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz", + "integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@mintlify/validation/node_modules/@radix-ui/react-popover": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.15.tgz", + "integrity": "sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@mintlify/validation/node_modules/@radix-ui/react-popper": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.8.tgz", + "integrity": "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@floating-ui/react-dom": "^2.0.0", + "@radix-ui/react-arrow": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-rect": "1.1.1", + "@radix-ui/react-use-size": "1.1.1", + "@radix-ui/rect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@mintlify/validation/node_modules/@radix-ui/react-portal": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz", + "integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@mintlify/validation/node_modules/@radix-ui/react-presence": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.5.tgz", + "integrity": "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@mintlify/validation/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@mintlify/validation/node_modules/mdast-util-gfm": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz", + "integrity": "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==", + "license": "MIT", + "dependencies": { + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-gfm-autolink-literal": "^2.0.0", + "mdast-util-gfm-footnote": "^2.0.0", + "mdast-util-gfm-strikethrough": "^2.0.0", + "mdast-util-gfm-table": "^2.0.0", + "mdast-util-gfm-task-list-item": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@mintlify/validation/node_modules/next-mdx-remote-client": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/next-mdx-remote-client/-/next-mdx-remote-client-1.1.7.tgz", + "integrity": "sha512-12Ap5Z/tFIETMXFSBTH2IFEhJAso7MvOJ5ICyesA4q6FM4vtAcmb+4ZKa4tV1IVQJLBVqOhaEfIESZzdwjmrQQ==", + "license": "MPL 2.0", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@mdx-js/mdx": "^3.1.1", + "@mdx-js/react": "^3.1.1", + "remark-mdx-remove-esm": "^1.3.1", + "serialize-error": "^13.0.1", + "vfile": "^6.0.3", + "vfile-matter": "^5.0.1" + }, + "engines": { + "node": ">=20.9.0" + }, + "peerDependencies": { + "react": ">= 18.3.0 < 19.0.0", + "react-dom": ">= 18.3.0 < 19.0.0" + } + }, + "node_modules/@mintlify/validation/node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@mintlify/validation/node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "license": "MIT", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/@mintlify/validation/node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/@mintlify/validation/node_modules/zod": { + "version": "3.24.0", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.0.tgz", + "integrity": "sha512-Hz+wiY8yD0VLA2k/+nsg2Abez674dDGTai33SwNvMPuf9uIrBC9eFgIMQxBBbHFxVXi8W+5nX9DcAh9YNSQm/w==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/@mintlify/validation/node_modules/zod-to-json-schema": { + "version": "3.20.4", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.20.4.tgz", + "integrity": "sha512-Un9+kInJ2Zt63n6Z7mLqBifzzPcOyX+b+Exuzf7L1+xqck9Q2EPByyTRduV3kmSPaXaRer1JCsucubpgL1fipg==", + "license": "ISC", + "peerDependencies": { + "zod": "^3.20.0" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@openapi-contrib/openapi-schema-to-json-schema": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@openapi-contrib/openapi-schema-to-json-schema/-/openapi-schema-to-json-schema-3.2.0.tgz", + "integrity": "sha512-Gj6C0JwCr8arj0sYuslWXUBSP/KnUlEGnPW4qxlXvAl543oaNQgMgIgkQUA6vs5BCCvwTEiL8m/wdWzfl4UvSw==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3" + } + }, + "node_modules/@pagefind/darwin-arm64": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@pagefind/darwin-arm64/-/darwin-arm64-1.5.2.tgz", + "integrity": "sha512-MXpI+7HsAdPkvJ0gk9xj9g541BCqBZOBbdwj9g6lB5LCj6kSV6nqDSjzcAJwvOsfu0fjwvC8hQU+ecfhp+MpiQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@pagefind/darwin-x64": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@pagefind/darwin-x64/-/darwin-x64-1.5.2.tgz", + "integrity": "sha512-IojxFWMEJe0RQ7PQ3KXQsPIImNsbpPYpoZ+QUDrL8fAl/O27IX+LVLs74/UzEZy5uA2LD8Nz1AiwKr72vrkZQw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@pagefind/freebsd-x64": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@pagefind/freebsd-x64/-/freebsd-x64-1.5.2.tgz", + "integrity": "sha512-7EVzo9+0w+2cbe671BtMj10UlNo83I+HrLVLfRxO731svHRJKUfJ/mo05gU14pe9PCfpKNQT8FS3Xc/oDN6pOA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@pagefind/linux-arm64": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@pagefind/linux-arm64/-/linux-arm64-1.5.2.tgz", + "integrity": "sha512-Ovt9+K35sqzn8H3ZMXGwls4TD/wMJuvRtShHIsmUQREmaxjrDEX7gHckRCrwYJ4XE1H1p6HkLz3wukrAnsfXQw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@pagefind/linux-x64": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@pagefind/linux-x64/-/linux-x64-1.5.2.tgz", + "integrity": "sha512-V+tFqHKXhQKq/WqPBD67AFy7scn1/aZID00ws4fSDd+1daSi5UHR9VVlRrOUYKxn3VuFQYRD7lYXdZK1WED1YA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@pagefind/windows-arm64": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@pagefind/windows-arm64/-/windows-arm64-1.5.2.tgz", + "integrity": "sha512-hN9Nh90fNW61nNRCW9ZyQrAj/mD0eRvmJ8NlTUzkbuW8kIzGJUi3cxjFkEcMZ5h/8FsKWD/VcouZl4yo1F7B6g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@pagefind/windows-x64": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@pagefind/windows-x64/-/windows-x64-1.5.2.tgz", + "integrity": "sha512-Fa2Iyw7kaDRzGMfNYNUXNW2zbL5FQVDgSOcbDHdzBrDEdpqOqg8TcZ68F22ol6NJ9IGzvUdmeyZypLW5dyhqsg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@posthog/core": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@posthog/core/-/core-1.7.1.tgz", + "integrity": "sha512-kjK0eFMIpKo9GXIbts8VtAknsoZ18oZorANdtuTj1CbgS28t4ZVq//HAWhnxEuXRTrtkd+SUJ6Ux3j2Af8NCuA==", + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.6" + } + }, + "node_modules/@puppeteer/browsers": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.3.0.tgz", + "integrity": "sha512-ioXoq9gPxkss4MYhD+SFaU9p1IHFUX0ILAWFPyjGaBdjLsYAlZw6j1iLA0N/m12uVHLFDfSYNF7EQccjinIMDA==", + "license": "Apache-2.0", + "dependencies": { + "debug": "^4.3.5", + "extract-zip": "^2.0.1", + "progress": "^2.0.3", + "proxy-agent": "^6.4.0", + "semver": "^7.6.3", + "tar-fs": "^3.0.6", + "unbzip2-stream": "^1.4.3", + "yargs": "^17.7.2" + }, + "bin": { + "browsers": "lib/cjs/main-cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@puppeteer/browsers/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@puppeteer/browsers/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/@puppeteer/browsers/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@puppeteer/browsers/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@puppeteer/browsers/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@puppeteer/browsers/node_modules/tar-fs": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.1.2.tgz", + "integrity": "sha512-QGxxTxxyleAdyM3kpFs14ymbYmNFrfY+pHj7Z8FgtbZ7w2//VAgLMac7sT6nRpIHjppXO2AwwEOg0bPFVRcmXw==", + "license": "MIT", + "dependencies": { + "pump": "^3.0.0", + "tar-stream": "^3.1.5" + }, + "optionalDependencies": { + "bare-fs": "^4.0.1", + "bare-path": "^3.0.0" + } + }, + "node_modules/@puppeteer/browsers/node_modules/tar-stream": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.2.0.tgz", + "integrity": "sha512-ojzvCvVaNp6aOTFmG7jaRD0meowIAuPc3cMMhSgKiVWws1GyHbGd/xvnyuRKcKlMpt3qvxx6r0hreCNITP9hIg==", + "license": "MIT", + "dependencies": { + "b4a": "^1.6.4", + "bare-fs": "^4.5.5", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + }, + "node_modules/@puppeteer/browsers/node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@radix-ui/primitive": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz", + "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==", + "license": "MIT", + "peer": true + }, + "node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", + "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==", + "license": "MIT", + "peer": true, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", + "license": "MIT", + "peer": true, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-guards": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.3.tgz", + "integrity": "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==", + "license": "MIT", + "peer": true, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-id": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz", + "integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "peer": true, + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz", + "integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==", + "license": "MIT", + "peer": true, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz", + "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@radix-ui/react-use-effect-event": "0.0.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-effect-event": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz", + "integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-escape-keydown": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz", + "integrity": "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==", + "license": "MIT", + "peer": true, + "dependencies": { + "@radix-ui/react-use-callback-ref": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", + "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==", + "license": "MIT", + "peer": true, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-rect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.1.tgz", + "integrity": "sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==", + "license": "MIT", + "peer": true, + "dependencies": { + "@radix-ui/rect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-size": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.1.tgz", + "integrity": "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/rect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.1.tgz", + "integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==", + "license": "MIT", + "peer": true + }, + "node_modules/@shikijs/core": { + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-3.23.0.tgz", + "integrity": "sha512-NSWQz0riNb67xthdm5br6lAkvpDJRTgB36fxlo37ZzM2yq0PQFFzbd8psqC2XMPgCzo1fW6cVi18+ArJ44wqgA==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "3.23.0", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4", + "hast-util-to-html": "^9.0.5" + } + }, + "node_modules/@shikijs/core/node_modules/hast-util-to-html": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-9.0.5.tgz", + "integrity": "sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-whitespace": "^3.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "stringify-entities": "^4.0.0", + "zwitch": "^2.0.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@shikijs/engine-javascript": { + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-3.23.0.tgz", + "integrity": "sha512-aHt9eiGFobmWR5uqJUViySI1bHMqrAgamWE1TYSUoftkAeCCAiGawPMwM+VCadylQtF4V3VNOZ5LmfItH5f3yA==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "3.23.0", + "@shikijs/vscode-textmate": "^10.0.2", + "oniguruma-to-es": "^4.3.4" + } + }, + "node_modules/@shikijs/engine-oniguruma": { + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-3.23.0.tgz", + "integrity": "sha512-1nWINwKXxKKLqPibT5f4pAFLej9oZzQTsby8942OTlsJzOBZ0MWKiwzMsd+jhzu8YPCHAswGnnN1YtQfirL35g==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "3.23.0", + "@shikijs/vscode-textmate": "^10.0.2" + } + }, + "node_modules/@shikijs/langs": { + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-3.23.0.tgz", + "integrity": "sha512-2Ep4W3Re5aB1/62RSYQInK9mM3HsLeB91cHqznAJMuylqjzNVAVCMnNWRHFtcNHXsoNRayP9z1qj4Sq3nMqYXg==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "3.23.0" + } + }, + "node_modules/@shikijs/themes": { + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-3.23.0.tgz", + "integrity": "sha512-5qySYa1ZgAT18HR/ypENL9cUSGOeI2x+4IvYJu4JgVJdizn6kG4ia5Q1jDEOi7gTbN4RbuYtmHh0W3eccOrjMA==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "3.23.0" + } + }, + "node_modules/@shikijs/transformers": { + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/@shikijs/transformers/-/transformers-3.23.0.tgz", + "integrity": "sha512-F9msZVxdF+krQNSdQ4V+Ja5QemeAoTQ2jxt7nJCwhDsdF1JWS3KxIQXA3lQbyKwS3J61oHRUSv4jYWv3CkaKTQ==", + "license": "MIT", + "dependencies": { + "@shikijs/core": "3.23.0", + "@shikijs/types": "3.23.0" + } + }, + "node_modules/@shikijs/twoslash": { + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/@shikijs/twoslash/-/twoslash-3.23.0.tgz", + "integrity": "sha512-pNaLJWMA3LU7PhT8tm9OQBZ1epy0jmdgeJzntBtr1EVXLbHxGzTj3mnf9vOdcl84l96qnlJXkJ/NGXZYBpXl5g==", + "license": "MIT", + "dependencies": { + "@shikijs/core": "3.23.0", + "@shikijs/types": "3.23.0", + "twoslash": "^0.3.6" + }, + "peerDependencies": { + "typescript": ">=5.5.0" + } + }, + "node_modules/@shikijs/types": { + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.23.0.tgz", + "integrity": "sha512-3JZ5HXOZfYjsYSk0yPwBrkupyYSLpAE26Qc0HLghhZNGTZg/SKxXIIgoxOpmmeQP0RRSDJTk1/vPfw9tbw+jSQ==", + "license": "MIT", + "dependencies": { + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + } + }, + "node_modules/@shikijs/vscode-textmate": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-10.0.2.tgz", + "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==", + "license": "MIT" + }, + "node_modules/@sindresorhus/is": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.6.0.tgz", + "integrity": "sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==", + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@sindresorhus/slugify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/slugify/-/slugify-2.2.0.tgz", + "integrity": "sha512-9Vybc/qX8Kj6pxJaapjkFbiUJPk7MAkCh/GFCxIBnnsuYCFPIXKvnLidG8xlepht3i24L5XemUmGtrJ3UWrl6w==", + "license": "MIT", + "dependencies": { + "@sindresorhus/transliterate": "^1.0.0", + "escape-string-regexp": "^5.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@sindresorhus/transliterate": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/transliterate/-/transliterate-1.6.0.tgz", + "integrity": "sha512-doH1gimEu3A46VX6aVxpHTeHrytJAG6HgdxntYnCFiIFHEM/ZGpG8KiZGBChchjQmG0XFIBL552kBTjVcMZXwQ==", + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^5.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", + "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", + "license": "MIT" + }, + "node_modules/@stoplight/better-ajv-errors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@stoplight/better-ajv-errors/-/better-ajv-errors-1.0.3.tgz", + "integrity": "sha512-0p9uXkuB22qGdNfy3VeEhxkU5uwvp/KrBTAbrLBURv6ilxIVwanKwjMc41lQfIVgPGcOkmLbTolfFrSsueu7zA==", + "license": "Apache-2.0", + "dependencies": { + "jsonpointer": "^5.0.0", + "leven": "^3.1.0" + }, + "engines": { + "node": "^12.20 || >= 14.13" + }, + "peerDependencies": { + "ajv": ">=8" + } + }, + "node_modules/@stoplight/better-ajv-errors/node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/@stoplight/json": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/@stoplight/json/-/json-3.21.0.tgz", + "integrity": "sha512-5O0apqJ/t4sIevXCO3SBN9AHCEKKR/Zb4gaj7wYe5863jme9g02Q0n/GhM7ZCALkL+vGPTe4ZzTETP8TFtsw3g==", + "license": "Apache-2.0", + "dependencies": { + "@stoplight/ordered-object-literal": "^1.0.3", + "@stoplight/path": "^1.3.2", + "@stoplight/types": "^13.6.0", + "jsonc-parser": "~2.2.1", + "lodash": "^4.17.21", + "safe-stable-stringify": "^1.1" + }, + "engines": { + "node": ">=8.3.0" + } + }, + "node_modules/@stoplight/json-ref-readers": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@stoplight/json-ref-readers/-/json-ref-readers-1.2.2.tgz", + "integrity": "sha512-nty0tHUq2f1IKuFYsLM4CXLZGHdMn+X/IwEUIpeSOXt0QjMUbL0Em57iJUDzz+2MkWG83smIigNZ3fauGjqgdQ==", + "license": "Apache-2.0", + "dependencies": { + "node-fetch": "^2.6.0", + "tslib": "^1.14.1" + }, + "engines": { + "node": ">=8.3.0" + } + }, + "node_modules/@stoplight/json-ref-resolver": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/@stoplight/json-ref-resolver/-/json-ref-resolver-3.1.6.tgz", + "integrity": "sha512-YNcWv3R3n3U6iQYBsFOiWSuRGE5su1tJSiX6pAPRVk7dP0L7lqCteXGzuVRQ0gMZqUl8v1P0+fAKxF6PLo9B5A==", + "license": "Apache-2.0", + "dependencies": { + "@stoplight/json": "^3.21.0", + "@stoplight/path": "^1.3.2", + "@stoplight/types": "^12.3.0 || ^13.0.0", + "@types/urijs": "^1.19.19", + "dependency-graph": "~0.11.0", + "fast-memoize": "^2.5.2", + "immer": "^9.0.6", + "lodash": "^4.17.21", + "tslib": "^2.6.0", + "urijs": "^1.19.11" + }, + "engines": { + "node": ">=8.3.0" + } + }, + "node_modules/@stoplight/json-ref-resolver/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/@stoplight/ordered-object-literal": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@stoplight/ordered-object-literal/-/ordered-object-literal-1.0.5.tgz", + "integrity": "sha512-COTiuCU5bgMUtbIFBuyyh2/yVVzlr5Om0v5utQDgBCuQUOPgU1DwoffkTfg4UBQOvByi5foF4w4T+H9CoRe5wg==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/@stoplight/path": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@stoplight/path/-/path-1.3.2.tgz", + "integrity": "sha512-lyIc6JUlUA8Ve5ELywPC8I2Sdnh1zc1zmbYgVarhXIp9YeAB0ReeqmGEOWNtlHkbP2DAA1AL65Wfn2ncjK/jtQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/@stoplight/spectral-core": { + "version": "1.23.0", + "resolved": "https://registry.npmjs.org/@stoplight/spectral-core/-/spectral-core-1.23.0.tgz", + "integrity": "sha512-WvdgmiiJrjiMrcw7ByxfcYtUvAXNp2MhAfcEIXP3Mn8ZOVwyAWIsFjLlsE5zRqj0LuN8+7OQM/L+BMcHj6x/BQ==", + "license": "Apache-2.0", + "dependencies": { + "@stoplight/better-ajv-errors": "1.0.3", + "@stoplight/json": "~3.21.0", + "@stoplight/path": "1.3.2", + "@stoplight/spectral-parsers": "^1.0.0", + "@stoplight/spectral-ref-resolver": "^1.0.4", + "@stoplight/spectral-runtime": "^1.1.2", + "@stoplight/types": "~13.6.0", + "@types/es-aggregate-error": "^1.0.2", + "@types/json-schema": "^7.0.11", + "ajv": "^8.18.0", + "ajv-errors": "~3.0.0", + "ajv-formats": "~2.1.1", + "es-aggregate-error": "^1.0.7", + "expr-eval-fork": "^3.0.1", + "jsonpath-plus": "^10.3.0", + "lodash": "^4.18.1", + "lodash.topath": "^4.5.2", + "minimatch": "^3.1.4", + "nimma": "0.2.3", + "pony-cause": "^1.1.1", + "tslib": "^2.8.1" + }, + "engines": { + "node": "^16.20 || ^18.18 || >= 20.17" + } + }, + "node_modules/@stoplight/spectral-core/node_modules/@stoplight/types": { + "version": "13.6.0", + "resolved": "https://registry.npmjs.org/@stoplight/types/-/types-13.6.0.tgz", + "integrity": "sha512-dzyuzvUjv3m1wmhPfq82lCVYGcXG0xUYgqnWfCq3PCVR4BKFhjdkHrnJ+jIDoMKvXb05AZP/ObQF6+NpDo29IQ==", + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.4", + "utility-types": "^3.10.0" + }, + "engines": { + "node": "^12.20 || >=14.13" + } + }, + "node_modules/@stoplight/spectral-core/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/@stoplight/spectral-formats": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/@stoplight/spectral-formats/-/spectral-formats-1.8.2.tgz", + "integrity": "sha512-c06HB+rOKfe7tuxg0IdKDEA5XnjL2vrn/m/OVIIxtINtBzphZrOgtRn7epQ5bQF5SWp84Ue7UJWaGgDwVngMFw==", + "license": "Apache-2.0", + "dependencies": { + "@stoplight/json": "^3.17.0", + "@stoplight/spectral-core": "^1.19.2", + "@types/json-schema": "^7.0.7", + "tslib": "^2.8.1" + }, + "engines": { + "node": "^16.20 || ^18.18 || >= 20.17" + } + }, + "node_modules/@stoplight/spectral-formats/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/@stoplight/spectral-functions": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/@stoplight/spectral-functions/-/spectral-functions-1.10.2.tgz", + "integrity": "sha512-PIfPUgTRo8EtAnL1MIrzhHoUuojSaE8shGSMaHS3BxGyc8d079BE5+TqJa1/WLUb9YT9JQnZ0Aj4xfi8NcJOIw==", + "license": "Apache-2.0", + "dependencies": { + "@stoplight/better-ajv-errors": "1.0.3", + "@stoplight/json": "^3.17.1", + "@stoplight/spectral-core": "^1.19.4", + "@stoplight/spectral-formats": "^1.8.1", + "@stoplight/spectral-runtime": "^1.1.2", + "ajv": "^8.18.0", + "ajv-draft-04": "~1.0.0", + "ajv-errors": "~3.0.0", + "ajv-formats": "~2.1.1", + "lodash": "^4.18.1", + "tslib": "^2.8.1" + }, + "engines": { + "node": "^16.20 || ^18.18 || >= 20.17" + } + }, + "node_modules/@stoplight/spectral-functions/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/@stoplight/spectral-parsers": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@stoplight/spectral-parsers/-/spectral-parsers-1.0.5.tgz", + "integrity": "sha512-ANDTp2IHWGvsQDAY85/jQi9ZrF4mRrA5bciNHX+PUxPr4DwS6iv4h+FVWJMVwcEYdpyoIdyL+SRmHdJfQEPmwQ==", + "license": "Apache-2.0", + "dependencies": { + "@stoplight/json": "~3.21.0", + "@stoplight/types": "^14.1.1", + "@stoplight/yaml": "~4.3.0", + "tslib": "^2.8.1" + }, + "engines": { + "node": "^16.20 || ^18.18 || >= 20.17" + } + }, + "node_modules/@stoplight/spectral-parsers/node_modules/@stoplight/types": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/@stoplight/types/-/types-14.1.1.tgz", + "integrity": "sha512-/kjtr+0t0tjKr+heVfviO9FrU/uGLc+QNX3fHJc19xsCNYqU7lVhaXxDmEID9BZTjG+/r9pK9xP/xU02XGg65g==", + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.4", + "utility-types": "^3.10.0" + }, + "engines": { + "node": "^12.20 || >=14.13" + } + }, + "node_modules/@stoplight/spectral-parsers/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/@stoplight/spectral-ref-resolver": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@stoplight/spectral-ref-resolver/-/spectral-ref-resolver-1.0.5.tgz", + "integrity": "sha512-gj3TieX5a9zMW29z3mBlAtDOCgN3GEc1VgZnCVlr5irmR4Qi5LuECuFItAq4pTn5Zu+sW5bqutsCH7D4PkpyAA==", + "license": "Apache-2.0", + "dependencies": { + "@stoplight/json-ref-readers": "1.2.2", + "@stoplight/json-ref-resolver": "~3.1.6", + "@stoplight/spectral-runtime": "^1.1.2", + "dependency-graph": "0.11.0", + "tslib": "^2.8.1" + }, + "engines": { + "node": "^16.20 || ^18.18 || >= 20.17" + } + }, + "node_modules/@stoplight/spectral-ref-resolver/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/@stoplight/spectral-runtime": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@stoplight/spectral-runtime/-/spectral-runtime-1.1.5.tgz", + "integrity": "sha512-6/HSCQBKnI4M5qonCKos2W7oggXv+U/ml+m/cAd4eJAYfIVEmaLUo03qSWIIl4cBc5ujJPmn2WnCiRrz1++P7Q==", + "license": "Apache-2.0", + "dependencies": { + "@stoplight/json": "^3.20.1", + "@stoplight/path": "^1.3.2", + "@stoplight/types": "^13.6.0", + "abort-controller": "^3.0.0", + "lodash": "^4.18.1", + "node-fetch": "^2.7.0", + "tslib": "^2.8.1" + }, + "engines": { + "node": "^16.20 || ^18.18 || >= 20.17" + } + }, + "node_modules/@stoplight/spectral-runtime/node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/@stoplight/spectral-runtime/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/@stoplight/types": { + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/@stoplight/types/-/types-13.20.0.tgz", + "integrity": "sha512-2FNTv05If7ib79VPDA/r9eUet76jewXFH2y2K5vuge6SXbRHtWBhcaRmu+6QpF4/WRNoJj5XYRSwLGXDxysBGA==", + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.4", + "utility-types": "^3.10.0" + }, + "engines": { + "node": "^12.20 || >=14.13" + } + }, + "node_modules/@stoplight/yaml": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@stoplight/yaml/-/yaml-4.3.0.tgz", + "integrity": "sha512-JZlVFE6/dYpP9tQmV0/ADfn32L9uFarHWxfcRhReKUnljz1ZiUM5zpX+PH8h5CJs6lao3TuFqnPm9IJJCEkE2w==", + "license": "Apache-2.0", + "dependencies": { + "@stoplight/ordered-object-literal": "^1.0.5", + "@stoplight/types": "^14.1.1", + "@stoplight/yaml-ast-parser": "0.0.50", + "tslib": "^2.2.0" + }, + "engines": { + "node": ">=10.8" + } + }, + "node_modules/@stoplight/yaml-ast-parser": { + "version": "0.0.50", + "resolved": "https://registry.npmjs.org/@stoplight/yaml-ast-parser/-/yaml-ast-parser-0.0.50.tgz", + "integrity": "sha512-Pb6M8TDO9DtSVla9yXSTAxmo9GVEouq5P40DWXdOie69bXogZTkgvopCq+yEvTMA0F6PEvdJmbtTV3ccIp11VQ==", + "license": "Apache-2.0" + }, + "node_modules/@stoplight/yaml/node_modules/@stoplight/types": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/@stoplight/types/-/types-14.1.1.tgz", + "integrity": "sha512-/kjtr+0t0tjKr+heVfviO9FrU/uGLc+QNX3fHJc19xsCNYqU7lVhaXxDmEID9BZTjG+/r9pK9xP/xU02XGg65g==", + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.4", + "utility-types": "^3.10.0" + }, + "engines": { + "node": "^12.20 || >=14.13" + } + }, + "node_modules/@stoplight/yaml/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/@szmarczak/http-timer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz", + "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==", + "license": "MIT", + "dependencies": { + "defer-to-connect": "^2.0.1" + }, + "engines": { + "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==", + "license": "MIT" + }, + "node_modules/@types/acorn": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@types/acorn/-/acorn-4.0.6.tgz", + "integrity": "sha512-veQTnWP+1D/xbxVrPC3zHnCZRjSrKfhbMUlEA43iMZLu7EsnTtkJklIuwrCPbOi8YkvDQAiW05VQQFvvz9oieQ==", + "license": "MIT", + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/@types/cors": { + "version": "2.8.19", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz", + "integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/debug": { + "version": "4.1.13", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.13.tgz", + "integrity": "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==", + "license": "MIT", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/es-aggregate-error": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/es-aggregate-error/-/es-aggregate-error-1.0.6.tgz", + "integrity": "sha512-qJ7LIFp06h1QE1aVxbVd+zJP2wdaugYXYfd6JxsyRMrYHaxb6itXPogW2tz+ylUJ1n1b+JF1PHyYCfYHm0dvUg==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "license": "MIT" + }, + "node_modules/@types/estree-jsx": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.5.tgz", + "integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==", + "license": "MIT", + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/http-cache-semantics": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", + "integrity": "sha512-L3LgimLHXtGkWikKnsPg0/VFx9OGZaC+eN1u4r+OB1XRqH3meBIAVC2zr1WdMH+RHmnRkqliQAOHNJ/E0j/e0Q==", + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "license": "MIT" + }, + "node_modules/@types/katex": { + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@types/katex/-/katex-0.16.8.tgz", + "integrity": "sha512-trgaNyfU+Xh2Tc+ABIb44a5AYUpicB3uwirOioeOkNPPbmgRNtcWyDeeFRzjPZENO9Vq8gvVqfhaaXWLlevVwg==", + "license": "MIT" + }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/mdx": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@types/mdx/-/mdx-2.0.13.tgz", + "integrity": "sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw==", + "license": "MIT" + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "license": "MIT" + }, + "node_modules/@types/nlcst": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/nlcst/-/nlcst-2.0.3.tgz", + "integrity": "sha512-vSYNSDe6Ix3q+6Z7ri9lyWqgGhJTmzRjZRqyq15N0Z/1/UnVsno9G/N40NBijoYx2seFDIl0+B2mgAb9mezUCA==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/node": { + "version": "25.9.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.1.tgz", + "integrity": "sha512-xfrlY7UD5rMJk3ZVJP8BNzS28J36YJg+xp+LPXV1TdWxr8uMH5A860QNxYDGQe/ylDSgjxE52Q9VnO7p75tJxg==", + "license": "MIT", + "dependencies": { + "undici-types": ">=7.24.0 <7.24.7" + } + }, + "node_modules/@types/react": { + "version": "19.2.15", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.15.tgz", + "integrity": "sha512-eRwcGNHve+E8qtEQSSRl6urh+rFop4v8gm6O8rGv25CodbvFdLjA1vVQ1KkiFE0w0UPOnb8tDiFKL5lp0rtY5Q==", + "license": "MIT", + "peer": true, + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "license": "MIT" + }, + "node_modules/@types/urijs": { + "version": "1.19.26", + "resolved": "https://registry.npmjs.org/@types/urijs/-/urijs-1.19.26.tgz", + "integrity": "sha512-wkXrVzX5yoqLnndOwFsieJA7oKM8cNkOKJtf/3vVGSUFkWDKZvFHpIl9Pvqb/T9UsawBBFMTTD8xu7sK5MWuvg==", + "license": "MIT" + }, + "node_modules/@types/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/yauzl": { + "version": "2.10.3", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", + "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", + "license": "MIT", + "optional": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@typescript/vfs": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/@typescript/vfs/-/vfs-1.6.4.tgz", + "integrity": "sha512-PJFXFS4ZJKiJ9Qiuix6Dz/OwEIqHD7Dme1UwZhTK11vR+5dqW2ACbdndWQexBzCx+CPuMe5WBYQWCsFyGlQLlQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.3" + }, + "peerDependencies": { + "typescript": "*" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.1.tgz", + "integrity": "sha512-mUFwbeTqrVgDQxFveS+df2yfap6iuP20NAKAsBt5jDEoOTDew+zwLAOilHCeQJOVSvmgCX4ogqIrA0mnyr08yQ==", + "license": "ISC" + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", + "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/address": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/address/-/address-1.2.2.tgz", + "integrity": "sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==", + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/adm-zip": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.16.tgz", + "integrity": "sha512-TGw5yVi4saajsSEgz25grObGHEUaDrniwvA2qwSC060KfqGPdglhvPMA2lPIoxs3PQIItj2iag35fONcQqgUaQ==", + "license": "MIT", + "engines": { + "node": ">=12.0" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/aggregate-error": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-4.0.1.tgz", + "integrity": "sha512-0poP0T7el6Vq3rstR8Mn4V/IQrpBLO6POkUSrN7RhyY+GF/InCFShQzsQ39T25gkHhLgSLByyAz+Kjb+c2L98w==", + "license": "MIT", + "dependencies": { + "clean-stack": "^4.0.0", + "indent-string": "^5.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-draft-04": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz", + "integrity": "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==", + "license": "MIT", + "peerDependencies": { + "ajv": "^8.5.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-errors": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-3.0.0.tgz", + "integrity": "sha512-V3wD15YHfHz6y0KdhYFjyy9vWtEVALT9UrxfN3zqlI6dMioHnJrqOYfyPKol3oqrnCM9uwkcdCwkJ0WUcbLMTQ==", + "license": "MIT", + "peerDependencies": { + "ajv": "^8.0.1" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ansi-escapes": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.3.0.tgz", + "integrity": "sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==", + "license": "MIT", + "dependencies": { + "environment": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "license": "MIT" + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "license": "MIT" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0" + }, + "node_modules/aria-hidden": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz", + "integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==", + "license": "MIT", + "peer": true, + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/aria-hidden/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD", + "peer": true + }, + "node_modules/arkregex": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/arkregex/-/arkregex-0.0.3.tgz", + "integrity": "sha512-bU21QJOJEFJK+BPNgv+5bVXkvRxyAvgnon75D92newgHxkBJTgiFwQxusyViYyJkETsddPlHyspshDQcCzmkNg==", + "license": "MIT", + "dependencies": { + "@ark/util": "0.55.0" + } + }, + "node_modules/arktype": { + "version": "2.1.27", + "resolved": "https://registry.npmjs.org/arktype/-/arktype-2.1.27.tgz", + "integrity": "sha512-enctOHxI4SULBv/TDtCVi5M8oLd4J5SVlPUblXDzSsOYQNMzmVbUosGBnJuZDKmFlN5Ie0/QVEuTE+Z5X1UhsQ==", + "license": "MIT", + "dependencies": { + "@ark/schema": "0.55.0", + "@ark/util": "0.55.0", + "arkregex": "0.0.3" + } + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "license": "MIT" + }, + "node_modules/array-iterate": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/array-iterate/-/array-iterate-2.0.1.tgz", + "integrity": "sha512-I1jXZMjAgCMmxT4qxXfPXa6SthSoE8h6gkSI9BGGNv8mP8G/v0blc+qFnZu6K42vTOiuME596QaLO0TP3Lk0xg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", + "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/ast-types/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/astring": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/astring/-/astring-1.9.0.tgz", + "integrity": "sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==", + "license": "MIT", + "bin": { + "astring": "bin/astring" + } + }, + "node_modules/async-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/auto-bind": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/auto-bind/-/auto-bind-5.0.1.tgz", + "integrity": "sha512-ooviqdwwgfIfNmDwo94wlshcdzfO64XV0Cg6oDsDYBJfITDz1EngD2z7DkbvCWn+XIMsIqW27sEVF6qcpJrRcg==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/avsc": { + "version": "5.7.9", + "resolved": "https://registry.npmjs.org/avsc/-/avsc-5.7.9.tgz", + "integrity": "sha512-yOA4wFeI7ET3v32Di/sUybQ+ttP20JHSW3mxLuNGeO0uD6PPcvLrIQXSvy/rhJOWU5JrYh7U4OHplWMmtAtjMg==", + "license": "MIT", + "engines": { + "node": ">=0.11" + } + }, + "node_modules/axios": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.16.1.tgz", + "integrity": "sha512-caYkukvroVPO8KrzuJEb50Hm07KwfBZPEC3VeFHTsqWHvKTsy54hjJz9BS/cdaypROE2rH6xvm9mHX4fgWkr3A==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.16.0", + "form-data": "^4.0.5", + "https-proxy-agent": "^5.0.1", + "proxy-from-env": "^2.1.0" + } + }, + "node_modules/b4a": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.8.1.tgz", + "integrity": "sha512-aiqre1Nr0B/6DgE2N5vwTc+2/oQZ4Wh1t4NznYY4E00y8LCt6NqdRv81so00oo27D8MVKTpUa/MwUUtBLXCoDw==", + "license": "Apache-2.0", + "peerDependencies": { + "react-native-b4a": "*" + }, + "peerDependenciesMeta": { + "react-native-b4a": { + "optional": true + } + } + }, + "node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/bare-events": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.8.3.tgz", + "integrity": "sha512-HdUm8EMQBLaJvGUdidNNbqpA1kYkwNcb+MYxkxCLAPJGQzlv9J0C24h8V65Z4c5GLd/JEALDvpFCQgpLJqc0zw==", + "license": "Apache-2.0", + "peerDependencies": { + "bare-abort-controller": "*" + }, + "peerDependenciesMeta": { + "bare-abort-controller": { + "optional": true + } + } + }, + "node_modules/bare-fs": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.7.1.tgz", + "integrity": "sha512-WDRsyVN52eAx/lBamKD6uyw8H4228h/x0sGGGegOamM2cd7Pag88GfMQalobXI+HaEUxpCkbKQUDOQqt9wawRw==", + "license": "Apache-2.0", + "dependencies": { + "bare-events": "^2.5.4", + "bare-path": "^3.0.0", + "bare-stream": "^2.6.4", + "bare-url": "^2.2.2", + "fast-fifo": "^1.3.2" + }, + "engines": { + "bare": ">=1.16.0" + }, + "peerDependencies": { + "bare-buffer": "*" + }, + "peerDependenciesMeta": { + "bare-buffer": { + "optional": true + } + } + }, + "node_modules/bare-os": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.9.1.tgz", + "integrity": "sha512-6M5XjcnsygQNPMCMPXSK379xrJFiZ/AEMNBmFEmQW8d/789VQATvriyi5r0HYTL9TkQ26rn3kgdTG3aisbrXkQ==", + "license": "Apache-2.0", + "engines": { + "bare": ">=1.14.0" + } + }, + "node_modules/bare-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-3.0.0.tgz", + "integrity": "sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==", + "license": "Apache-2.0", + "dependencies": { + "bare-os": "^3.0.1" + } + }, + "node_modules/bare-stream": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.13.1.tgz", + "integrity": "sha512-Vp0cnjYyrEC4whYTymQ+YZi6pBpfiICZO3cfRG8sy67ZNWe951urv1x4eW1BKNngw3U+3fPYb5JQvHbCtxH7Ow==", + "license": "Apache-2.0", + "dependencies": { + "streamx": "^2.25.0", + "teex": "^1.0.1" + }, + "peerDependencies": { + "bare-abort-controller": "*", + "bare-buffer": "*", + "bare-events": "*" + }, + "peerDependenciesMeta": { + "bare-abort-controller": { + "optional": true + }, + "bare-buffer": { + "optional": true + }, + "bare-events": { + "optional": true + } + } + }, + "node_modules/bare-url": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.4.3.tgz", + "integrity": "sha512-Kccpc7ACfXaxfeInfqKcZtW4pT5YBn1mesc4sCsun6sRwtbJ4h+sNOaksUpYEJUKfN65YWC6Bw2OJEFiKxq8nQ==", + "license": "Apache-2.0", + "dependencies": { + "bare-path": "^3.0.0" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "license": "MIT", + "engines": { + "node": "^4.5.0 || >= 5.9" + } + }, + "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==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/better-opn": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/better-opn/-/better-opn-3.0.2.tgz", + "integrity": "sha512-aVNobHnJqLiUelTaHat9DZ1qM2w0C0Eym4LPI/3JxOnSokGVdsl1T1kN7TFvsEAD8G47A6VKQ0TVHqbBnYMJlQ==", + "license": "MIT", + "dependencies": { + "open": "^8.0.4" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "license": "MIT", + "optional": true, + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/body-parser": { + "version": "1.20.5", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.5.tgz", + "integrity": "sha512-3grm+/2tUOvu2cjJkvsIxrv/wVpfXQW4PsQHYm7yk4vfpu7Ekl6nEsYBoJUL6qDwZUx8wUhQ8tR2qz+ad9c9OA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "~1.2.0", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "on-finished": "~2.4.1", + "qs": "~6.15.1", + "raw-body": "~2.5.3", + "type-is": "~1.6.18", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/body-parser/node_modules/qs": { + "version": "6.15.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.2.tgz", + "integrity": "sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cacheable-lookup": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", + "integrity": "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==", + "license": "MIT", + "engines": { + "node": ">=14.16" + } + }, + "node_modules/cacheable-request": { + "version": "10.2.14", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.14.tgz", + "integrity": "sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==", + "license": "MIT", + "dependencies": { + "@types/http-cache-semantics": "^4.0.2", + "get-stream": "^6.0.1", + "http-cache-semantics": "^4.1.1", + "keyv": "^4.5.3", + "mimic-response": "^4.0.0", + "normalize-url": "^8.0.0", + "responselike": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + } + }, + "node_modules/call-bind": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.9.tgz", + "integrity": "sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "get-intrinsic": "^1.3.0", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chalk": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.2.0.tgz", + "integrity": "sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-reference-invalid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", + "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chardet": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.1.1.tgz", + "integrity": "sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==", + "license": "MIT" + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chownr": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/chromium-bidi": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.6.2.tgz", + "integrity": "sha512-4WVBa6ijmUTVr9cZD4eicQD8Mdy/HCX3bzEIYYpmk0glqYLoWH+LqQEvV9RpDRzoQSbY1KJHloYXbDMXMbDPhg==", + "license": "Apache-2.0", + "dependencies": { + "mitt": "3.0.1", + "urlpattern-polyfill": "10.0.0", + "zod": "3.23.8" + }, + "peerDependencies": { + "devtools-protocol": "*" + } + }, + "node_modules/chromium-bidi/node_modules/zod": { + "version": "3.23.8", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz", + "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/clean-stack": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-4.2.0.tgz", + "integrity": "sha512-LYv6XPxoyODi36Dp976riBtSY27VmFo+MKqEU9QCCWyTrdEPDog+RWA7xQWHi6Vbp61j5c4cdzzX1NidnwtUWg==", + "license": "MIT", + "dependencies": { + "escape-string-regexp": "5.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-boxes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz", + "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-cursor": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz", + "integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==", + "license": "MIT", + "dependencies": { + "restore-cursor": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz", + "integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==", + "license": "MIT", + "dependencies": { + "slice-ansi": "^5.0.0", + "string-width": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate/node_modules/is-fullwidth-code-point": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate/node_modules/slice-ansi": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", + "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "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==", + "license": "ISC", + "engines": { + "node": ">= 12" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/cliui/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/code-excerpt": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/code-excerpt/-/code-excerpt-4.0.0.tgz", + "integrity": "sha512-xxodCmBen3iy2i0WtAK8FlFNrRzjUqjRsMfho58xT/wvZU1YTM3fCnRjcy1gJPMepaRlgm/0e6w8SpWHpn3/cA==", + "license": "MIT", + "dependencies": { + "convert-to-spaces": "^2.0.1" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/collapse-white-space": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-2.1.0.tgz", + "integrity": "sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + }, + "engines": { + "node": ">=12.5.0" + } + }, + "node_modules/color-blend": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/color-blend/-/color-blend-4.0.0.tgz", + "integrity": "sha512-fYODTHhI/NG+B5GnzvuL3kiFrK/UnkUezWFTgEPBTY5V+kpyfAn95Vn9sJeeCX6omrCOdxnqCL3CvH+6sXtIbw==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "license": "MIT", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "license": "MIT" + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-to-spaces": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/convert-to-spaces/-/convert-to-spaces-2.0.1.tgz", + "integrity": "sha512-rcQ1bsQO9799wq24uE5AM2tAILy4gXGIK/njFWcVQkGNZ96edlpY+A7bjwvzjYvLDyzmG1MmMLZhpcsb+klNMQ==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", + "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==", + "license": "MIT" + }, + "node_modules/cors": { + "version": "2.8.6", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz", + "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/cosmiconfig": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.1.tgz", + "integrity": "sha512-hr4ihw+DBqcvrsEDioRO31Z17x71pUYoNe/4h6Z0wB72p7MU7/9gH8Q3s12NFhHPfYBBOV3qyfUxmr/Yn3shnQ==", + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cssfilter": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/cssfilter/-/cssfilter-0.0.10.tgz", + "integrity": "sha512-FAaLDaplstoRsDR8XGYH51znUN0UY7nMc6Z9/fvE8EXGwvJE9hu7W2vHwx1+bd6gCYnln9nLbzxFTrcO9YQDZw==", + "license": "MIT" + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "license": "MIT", + "peer": true + }, + "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==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/data-view-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", + "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", + "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/inspect-js" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", + "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decode-bmp": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/decode-bmp/-/decode-bmp-0.2.1.tgz", + "integrity": "sha512-NiOaGe+GN0KJqi2STf24hfMkFitDUaIoUU3eKvP/wAbLe8o6FuW5n/x7MHPR0HKvBokp6MQY/j7w8lewEeVCIA==", + "license": "MIT", + "dependencies": { + "@canvas/image-data": "^1.0.0", + "to-data-view": "^1.1.0" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/decode-ico": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/decode-ico/-/decode-ico-0.4.1.tgz", + "integrity": "sha512-69NZfbKIzux1vBOd31al3XnMnH+2mqDhEgLdpygErm4d60N+UwA5Sq5WFjmEDQzumgB9fElojGwWG0vybVfFmA==", + "license": "MIT", + "dependencies": { + "@canvas/image-data": "^1.0.0", + "decode-bmp": "^0.2.0", + "to-data-view": "^1.1.0" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/decode-named-character-reference": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.3.0.tgz", + "integrity": "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==", + "license": "MIT", + "dependencies": { + "character-entities": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "license": "MIT", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decompress-response/node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "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", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/dependency-graph": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.11.0.tgz", + "integrity": "sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg==", + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/detect-node-es": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", + "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==", + "license": "MIT", + "peer": true + }, + "node_modules/detect-port": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/detect-port/-/detect-port-1.5.1.tgz", + "integrity": "sha512-aBzdj76lueB6uUst5iAs7+0H/oOjqI5D16XUWxlWMIMROhcM0rfsNVk93zTngq1dDNpoXRr++Sus7ETAExppAQ==", + "license": "MIT", + "dependencies": { + "address": "^1.0.1", + "debug": "4" + }, + "bin": { + "detect": "bin/detect-port.js", + "detect-port": "bin/detect-port.js" + } + }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/devtools-protocol": { + "version": "0.0.1312386", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1312386.tgz", + "integrity": "sha512-DPnhUXvmvKT2dFA/j7B+riVLUt9Q6RKJlcppojL5CoRywJJKLDYnRlw0gTFKfgDPHP5E04UoB71SxoJlVZy8FA==", + "license": "BSD-3-Clause" + }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "license": "Apache-2.0" + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "license": "MIT" + }, + "node_modules/dns-packet": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", + "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", + "license": "MIT", + "dependencies": { + "@leichtgewicht/ip-codec": "^2.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/dns-socket": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/dns-socket/-/dns-socket-4.2.2.tgz", + "integrity": "sha512-BDeBd8najI4/lS00HSKpdFia+OvUMytaVjfzR9n5Lq8MlZRSvtbI+uLtx1+XmQFls5wFU9dssccTmQQ6nfpjdg==", + "license": "MIT", + "dependencies": { + "dns-packet": "^5.2.4" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/engine.io": { + "version": "6.6.8", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.8.tgz", + "integrity": "sha512-2agL3ueZhqxoVrfmntO8yuVj+uNSlIOnhykYHk3Cq0ShYPdUjjUiSJrQvXjq01I9jAuI0Zl2YO8Evv5Mqytm5g==", + "license": "MIT", + "dependencies": { + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "@types/ws": "^8.5.12", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.7.2", + "cors": "~2.8.5", + "debug": "~4.4.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.20.1" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/engine.io-parser": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", + "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/engine.io/node_modules/ws": { + "version": "8.20.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.1.tgz", + "integrity": "sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/environment": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.24.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.2.tgz", + "integrity": "sha512-2FpH9Q5i2RRwyEP1AylXe6nYLR5OhaJTZwmlcP0dL/+JCbgg7yyEo/sEK6HeGZRf3dFpWwThaRHVApXSkW3xeg==", + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-set-tostringtag": "^2.1.0", + "es-to-primitive": "^1.3.0", + "function.prototype.name": "^1.1.8", + "get-intrinsic": "^1.3.0", + "get-proto": "^1.0.1", + "get-symbol-description": "^1.1.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.2", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.2.1", + "is-set": "^2.0.3", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakref": "^1.1.1", + "math-intrinsics": "^1.1.0", + "object-inspect": "^1.13.4", + "object-keys": "^1.1.1", + "object.assign": "^4.1.7", + "own-keys": "^1.0.1", + "regexp.prototype.flags": "^1.5.4", + "safe-array-concat": "^1.1.3", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "set-proto": "^1.0.0", + "stop-iteration-iterator": "^1.1.0", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-typed-array": "^1.1.19" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-aggregate-error": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/es-aggregate-error/-/es-aggregate-error-1.0.14.tgz", + "integrity": "sha512-3YxX6rVb07B5TV11AV5wsL7nQCHXNwoHPsQC8S4AmBiqYhyNCJ5BRKXkXyDJvs8QzXN20NgRtxe3dEEQD9NLHA==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "globalthis": "^1.0.4", + "has-property-descriptors": "^1.0.2", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-to-primitive": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", + "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7", + "is-date-object": "^1.0.5", + "is-symbol": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-toolkit": { + "version": "1.46.1", + "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.46.1.tgz", + "integrity": "sha512-5eNtXOs3tbfxXOj04tjjseeWkRWaoCjdEI+96DgwzZoe6c9juL49pXlzAFTI72aWC9Y8p7168g6XIKjh7k6pyQ==", + "license": "MIT", + "workspaces": [ + "docs", + "benchmarks" + ] + }, + "node_modules/esast-util-from-estree": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/esast-util-from-estree/-/esast-util-from-estree-2.0.0.tgz", + "integrity": "sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-visit": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/esast-util-from-js": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/esast-util-from-js/-/esast-util-from-js-2.0.1.tgz", + "integrity": "sha512-8Ja+rNJ0Lt56Pcf3TAmpBZjmx8ZcK5Ts4cAzIOjsjevg9oSXJnl6SUQ2EevU8tv3h6ZLWmoKL5H4fgWvdvfETw==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "acorn": "^8.0.0", + "esast-util-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "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==", + "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/escodegen/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "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==", + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-util-attach-comments": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-util-attach-comments/-/estree-util-attach-comments-3.0.0.tgz", + "integrity": "sha512-cKUwm/HUcTDsYh/9FgnuFqpfquUbwIqwKM26BVCGDPVgvaCl/nDCCjUfiLlx6lsEZ3Z4RFxNbOQ60pkaEwFxGw==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-build-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/estree-util-build-jsx/-/estree-util-build-jsx-3.0.1.tgz", + "integrity": "sha512-8U5eiL6BTrPxp/CHbs2yMgP8ftMhR5ww1eIKoWRMlqvltHF8fZn5LRDvTKuxD3DUn+shRbLGqXemcP51oFCsGQ==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "estree-walker": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-is-identifier-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz", + "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-scope": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/estree-util-scope/-/estree-util-scope-1.0.0.tgz", + "integrity": "sha512-2CAASclonf+JFWBNJPndcOpA8EMJwa0Q8LUFJEKqXLW6+qBvbFZuF5gItbQOs/umBUkjviCSDCbBwU2cXbmrhQ==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-to-js": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/estree-util-to-js/-/estree-util-to-js-2.0.0.tgz", + "integrity": "sha512-WDF+xj5rRWmD5tj6bIqRi6CkLIXbbNQUcxQHzGysQzvHmdYG2G7p/Tf0J0gpxGgkeMZNTIjT/AoSvC9Xehcgdg==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "astring": "^1.8.0", + "source-map": "^0.7.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-visit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/estree-util-visit/-/estree-util-visit-2.0.0.tgz", + "integrity": "sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/events-universal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/events-universal/-/events-universal-1.0.1.tgz", + "integrity": "sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==", + "license": "Apache-2.0", + "dependencies": { + "bare-events": "^2.7.0" + } + }, + "node_modules/expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "license": "(MIT OR WTFPL)", + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/expr-eval-fork": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/expr-eval-fork/-/expr-eval-fork-3.0.3.tgz", + "integrity": "sha512-BhC+hbc5lIVjygr840n5DEkW3MQq7H9o+mc1/N7Z5uIiCFVyESLL5DIE7LNq4CYUNxy+XjA+3jRrL/h0Kt2xcg==", + "license": "MIT", + "engines": { + "node": ">=16.9.0" + } + }, + "node_modules/express": { + "version": "4.22.0", + "resolved": "https://registry.npmjs.org/express/-/express-4.22.0.tgz", + "integrity": "sha512-c2iPh3xp5vvCLgaHK03+mWLFPhox7j1LwyxcZwFVApEv5i0X+IjPpbT50SJJwwLpdBVfp45AkK/v+AFgv/XlfQ==", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "~1.20.3", + "content-disposition": "~0.5.4", + "content-type": "~1.0.4", + "cookie": "~0.7.1", + "cookie-signature": "~1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.3.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "~2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "~0.1.12", + "proxy-addr": "~2.0.7", + "qs": "~6.14.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "~0.19.0", + "serve-static": "~1.16.2", + "setprototypeof": "1.2.0", + "statuses": "~2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "license": "MIT" + }, + "node_modules/extract-zip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", + "license": "BSD-2-Clause", + "dependencies": { + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + }, + "bin": { + "extract-zip": "cli.js" + }, + "engines": { + "node": ">= 10.17.0" + }, + "optionalDependencies": { + "@types/yauzl": "^2.9.1" + } + }, + "node_modules/extract-zip/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "license": "MIT", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" + }, + "node_modules/fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-memoize": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/fast-memoize/-/fast-memoize-2.5.2.tgz", + "integrity": "sha512-Ue0LwpDYErFbmNnZSF0UH6eImUwDmogUO1jyE+JbN2gsQz/jICm1Ve7t9QT0rNSsfJt+Hs4/S3GnsDVjL4HVrw==", + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.2.tgz", + "integrity": "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fault": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fault/-/fault-2.0.1.tgz", + "integrity": "sha512-WtySTkS4OKev5JtpHXnib4Gxiurzh5NCGvWrFaZ34m6JehfTUhKZvn9njTfw48t6JumVQOmrKqpmGcdwxnhqBQ==", + "license": "MIT", + "dependencies": { + "format": "^0.2.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/favicons": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/favicons/-/favicons-7.2.0.tgz", + "integrity": "sha512-k/2rVBRIRzOeom3wI9jBPaSEvoTSQEW4iM0EveBmBBKFxO8mSyyRWtDlfC3VnEfu0avmjrMzy8/ZFPSe6F71Hw==", + "license": "MIT", + "dependencies": { + "escape-html": "^1.0.3", + "sharp": "^0.33.1", + "xml2js": "^0.6.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "license": "MIT", + "dependencies": { + "pend": "~1.2.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz", + "integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "~2.4.1", + "parseurl": "~1.3.3", + "statuses": "~2.0.2", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/follow-redirects": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz", + "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/form-data": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/form-data-encoder": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.4.tgz", + "integrity": "sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==", + "license": "MIT", + "engines": { + "node": ">= 14.17" + } + }, + "node_modules/format": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz", + "integrity": "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==", + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/front-matter": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/front-matter/-/front-matter-4.0.2.tgz", + "integrity": "sha512-I8ZuJ/qG92NWX8i5x1Y8qyj3vizhXS31OxjKDu3LKP+7/qBgfIKValiZIEwoVoJKUHlhWtYrktkxV1XsX+pPlg==", + "license": "MIT", + "dependencies": { + "js-yaml": "^3.13.1" + } + }, + "node_modules/front-matter/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/front-matter/node_modules/js-yaml": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "license": "MIT", + "optional": true + }, + "node_modules/fs-extra": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", + "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "functions-have-names": "^1.2.3", + "hasown": "^2.0.2", + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gcd": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/gcd/-/gcd-0.0.1.tgz", + "integrity": "sha512-VNx3UEGr+ILJTiMs1+xc5SX1cMgJCrXezKPa003APUWNqQqaF6n25W8VcR7nHN6yRWbvvUTwCpZCFJeWC2kXlw==", + "license": "MIT" + }, + "node_modules/generator-function": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", + "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", + "engines": { + "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==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-nonce": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", + "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "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", + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-uri": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.5.tgz", + "integrity": "sha512-b1O07XYq8eRuVzBNgJLstU6FYc1tS6wnMtF1I1D9lE8LxZSOGZ7LhxN54yPP6mGw5f2CkXY2BQUL9Fx41qvcIg==", + "license": "MIT", + "dependencies": { + "basic-ftp": "^5.0.2", + "data-uri-to-buffer": "^6.0.2", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", + "license": "MIT", + "optional": true + }, + "node_modules/glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "license": "MIT", + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/got": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/got/-/got-13.0.0.tgz", + "integrity": "sha512-XfBk1CxOOScDcMr9O1yKkNaQyy865NbYs+F7dr4H0LZMVgCj2Le59k6PqbNHoL5ToeaEQUYh6c6yMfVcc6SJxA==", + "license": "MIT", + "dependencies": { + "@sindresorhus/is": "^5.2.0", + "@szmarczak/http-timer": "^5.0.1", + "cacheable-lookup": "^7.0.0", + "cacheable-request": "^10.2.8", + "decompress-response": "^6.0.0", + "form-data-encoder": "^2.1.2", + "get-stream": "^6.0.1", + "http2-wrapper": "^2.1.10", + "lowercase-keys": "^3.0.0", + "p-cancelable": "^3.0.0", + "responselike": "^3.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/has-bigints": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", + "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.3.tgz", + "integrity": "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hast-util-embedded": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-embedded/-/hast-util-embedded-3.0.0.tgz", + "integrity": "sha512-naH8sld4Pe2ep03qqULEtvYr7EjrLK2QHY8KJR6RJkTUjPGObe1vnx585uzem2hGra+s1q08DZZpfgDVYRbaXA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-is-element": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-from-dom": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/hast-util-from-dom/-/hast-util-from-dom-5.0.1.tgz", + "integrity": "sha512-N+LqofjR2zuzTjCPzyDUdSshy4Ma6li7p/c3pA78uTwzFgENbgbUrm2ugwsOdcjI1muO+o6Dgzp9p8WHtn/39Q==", + "license": "ISC", + "dependencies": { + "@types/hast": "^3.0.0", + "hastscript": "^9.0.0", + "web-namespaces": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-from-html": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hast-util-from-html/-/hast-util-from-html-2.0.3.tgz", + "integrity": "sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "devlop": "^1.1.0", + "hast-util-from-parse5": "^8.0.0", + "parse5": "^7.0.0", + "vfile": "^6.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-from-html-isomorphic": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hast-util-from-html-isomorphic/-/hast-util-from-html-isomorphic-2.0.0.tgz", + "integrity": "sha512-zJfpXq44yff2hmE0XmwEOzdWin5xwH+QIhMLOScpX91e/NSGPsAzNCvLQDIEPyO2TXi+lBmU6hjLIhV8MwP2kw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-from-dom": "^5.0.0", + "hast-util-from-html": "^2.0.0", + "unist-util-remove-position": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-from-parse5": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-8.0.3.tgz", + "integrity": "sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "hastscript": "^9.0.0", + "property-information": "^7.0.0", + "vfile": "^6.0.0", + "vfile-location": "^5.0.0", + "web-namespaces": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-has-property": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-has-property/-/hast-util-has-property-3.0.0.tgz", + "integrity": "sha512-MNilsvEKLFpV604hwfhVStK0usFY/QmM5zX16bo7EjnAEGofr5YyI37kzopBlZJkHD4t887i+q/C8/tr5Q94cA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-is-body-ok-link": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/hast-util-is-body-ok-link/-/hast-util-is-body-ok-link-3.0.1.tgz", + "integrity": "sha512-0qpnzOBLztXHbHQenVB8uNuxTnm/QBFUOmdOSsEn7GnBtyY07+ENTWVFBAnXd/zEgd9/SUG3lRY7hSIBWRgGpQ==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-is-element": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-3.0.0.tgz", + "integrity": "sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-minify-whitespace": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hast-util-minify-whitespace/-/hast-util-minify-whitespace-1.0.1.tgz", + "integrity": "sha512-L96fPOVpnclQE0xzdWb/D12VT5FabA7SnZOUMtL1DbXmYiHJMXZvFkIZfiMmTCNJHUeO2K9UYNXoVyfz+QHuOw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-embedded": "^3.0.0", + "hast-util-is-element": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-parse-selector": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz", + "integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-phrasing": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/hast-util-phrasing/-/hast-util-phrasing-3.0.1.tgz", + "integrity": "sha512-6h60VfI3uBQUxHqTyMymMZnEbNl1XmEGtOxxKYL7stY2o601COo62AWAYBQR9lZbYXYSBoxag8UpPRXK+9fqSQ==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-embedded": "^3.0.0", + "hast-util-has-property": "^3.0.0", + "hast-util-is-body-ok-link": "^3.0.0", + "hast-util-is-element": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-estree": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/hast-util-to-estree/-/hast-util-to-estree-3.1.3.tgz", + "integrity": "sha512-48+B/rJWAp0jamNbAAf9M7Uf//UVqAoMmgXhBdxTDJLGKY+LRnZ99qcG+Qjl5HfMpYNzS5v4EAwVEF34LeAj7w==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-attach-comments": "^3.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-js": "^1.0.0", + "unist-util-position": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-html": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-9.0.4.tgz", + "integrity": "sha512-wxQzXtdbhiwGAUKrnQJXlOPmHnEehzphwkK7aluUPQ+lEc1xefC8pblMgpp2w5ldBTEfveRIrADcrhGIWrlTDA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-whitespace": "^3.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0", + "stringify-entities": "^4.0.0", + "zwitch": "^2.0.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-html/node_modules/property-information": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.5.0.tgz", + "integrity": "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/hast-util-to-jsx-runtime": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.6.tgz", + "integrity": "sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-js": "^1.0.0", + "unist-util-position": "^5.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-mdast": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/hast-util-to-mdast/-/hast-util-to-mdast-10.1.0.tgz", + "integrity": "sha512-DsL/SvCK9V7+vfc6SLQ+vKIyBDXTk2KLSbfBYkH4zeF/uR1yBajHRhkzuaUSGOB1WJSTieJBdHwxlC+HLKvZZw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "hast-util-phrasing": "^3.0.0", + "hast-util-to-html": "^9.0.0", + "hast-util-to-text": "^4.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-phrasing": "^4.0.0", + "mdast-util-to-hast": "^13.0.0", + "mdast-util-to-string": "^4.0.0", + "rehype-minify-whitespace": "^6.0.0", + "trim-trailing-lines": "^2.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-string": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/hast-util-to-string/-/hast-util-to-string-3.0.1.tgz", + "integrity": "sha512-XelQVTDWvqcl3axRfI0xSeoVKzyIFPwsAGSLIsKdJKQMXDYJS4WYrBNF/8J7RdhIcFI2BOHgAifggsvsxp/3+A==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-text": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/hast-util-to-text/-/hast-util-to-text-4.0.2.tgz", + "integrity": "sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "hast-util-is-element": "^3.0.0", + "unist-util-find-after": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-whitespace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hastscript": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-9.0.1.tgz", + "integrity": "sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-parse-selector": "^4.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hex-rgb": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/hex-rgb/-/hex-rgb-5.0.0.tgz", + "integrity": "sha512-NQO+lgVUCtHxZ792FodgW0zflK+ozS9X9dwGp9XvvmPlH7pyxd588cn24TD3rmPm/N0AIRXF10Otah8yKqGw4w==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/html-void-elements": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz", + "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", + "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", + "license": "BSD-2-Clause" + }, + "node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "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==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/http-proxy-agent/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==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/http2-wrapper": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.1.tgz", + "integrity": "sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==", + "license": "MIT", + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.2.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/ico-endec": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/ico-endec/-/ico-endec-0.1.6.tgz", + "integrity": "sha512-ZdLU38ZoED3g1j3iEyzcQj+wAkY2xfWNkymszfJPoxucIUhK7NayQ+/C4Kv0nDFMIsbtbEHldv3V8PU494/ueQ==", + "license": "MPL-2.0" + }, + "node_modules/iconv-lite": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", + "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", + "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/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/immer": { + "version": "9.0.21", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz", + "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/indent-string": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", + "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "license": "ISC", + "optional": true + }, + "node_modules/ink": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/ink/-/ink-6.3.0.tgz", + "integrity": "sha512-2CbJAa7XeziZYe6pDS5RVLirRY28iSGMQuEV8jRU5NQsONQNfcR/BZHHc9vkMg2lGYTHTM2pskxC1YmY28p6bQ==", + "license": "MIT", + "dependencies": { + "@alcalzone/ansi-tokenize": "^0.2.0", + "ansi-escapes": "^7.0.0", + "ansi-styles": "^6.2.1", + "auto-bind": "^5.0.1", + "chalk": "^5.6.0", + "cli-boxes": "^3.0.0", + "cli-cursor": "^4.0.0", + "cli-truncate": "^4.0.0", + "code-excerpt": "^4.0.0", + "es-toolkit": "^1.39.10", + "indent-string": "^5.0.0", + "is-in-ci": "^2.0.0", + "patch-console": "^2.0.0", + "react-reconciler": "^0.32.0", + "signal-exit": "^3.0.7", + "slice-ansi": "^7.1.0", + "stack-utils": "^2.0.6", + "string-width": "^7.2.0", + "type-fest": "^4.27.0", + "widest-line": "^5.0.0", + "wrap-ansi": "^9.0.0", + "ws": "^8.18.0", + "yoga-layout": "~3.2.1" + }, + "engines": { + "node": ">=20" + }, + "peerDependencies": { + "@types/react": ">=19.0.0", + "react": ">=19.0.0", + "react-devtools-core": "^4.19.1" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "react-devtools-core": { + "optional": true + } + } + }, + "node_modules/ink-spinner": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ink-spinner/-/ink-spinner-5.0.0.tgz", + "integrity": "sha512-EYEasbEjkqLGyPOUc8hBJZNuC5GvXGMLu0w5gdTNskPc7Izc5vO3tdQEYnzvshucyGCBXc86ig0ujXPMWaQCdA==", + "license": "MIT", + "dependencies": { + "cli-spinners": "^2.7.0" + }, + "engines": { + "node": ">=14.16" + }, + "peerDependencies": { + "ink": ">=4.0.0", + "react": ">=18.0.0" + } + }, + "node_modules/ink/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==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/ink/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "license": "ISC" + }, + "node_modules/ink/node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/inline-style-parser": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.7.tgz", + "integrity": "sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==", + "license": "MIT" + }, + "node_modules/inquirer": { + "version": "12.3.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-12.3.0.tgz", + "integrity": "sha512-3NixUXq+hM8ezj2wc7wC37b32/rHq1MwNZDYdvx+d6jokOD+r+i8Q4Pkylh9tISYP114A128LCX8RKhopC5RfQ==", + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.1.2", + "@inquirer/prompts": "^7.2.1", + "@inquirer/type": "^3.0.2", + "ansi-escapes": "^4.3.2", + "mute-stream": "^2.0.0", + "run-async": "^3.0.0", + "rxjs": "^7.8.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + } + }, + "node_modules/inquirer/node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/inquirer/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/internal-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "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==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/ip-regex": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-4.3.0.tgz", + "integrity": "sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-alphabetical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", + "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-alphanumerical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", + "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", + "license": "MIT", + "dependencies": { + "is-alphabetical": "^2.0.0", + "is-decimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", + "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "license": "MIT" + }, + "node_modules/is-async-function": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", + "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", + "license": "MIT", + "dependencies": { + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", + "license": "MIT", + "dependencies": { + "has-bigints": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", + "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz", + "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-decimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", + "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-finalizationregistry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", + "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", + "integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==", + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.3.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-generator-function": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", + "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.4", + "generator-function": "^2.0.0", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-hexadecimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", + "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-in-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-in-ci/-/is-in-ci-2.0.0.tgz", + "integrity": "sha512-cFeerHriAnhrQSbpAxL37W1wcJKUUX07HyLWZCW1URJT/ra3GyUTzBgUnh24TMVfNTV2Hij2HLxkPHFZfOZy5w==", + "license": "MIT", + "bin": { + "is-in-ci": "cli.js" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-ip": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-ip/-/is-ip-3.1.0.tgz", + "integrity": "sha512-35vd5necO7IitFPjd/YBeqwWnyDWbuLH9ZXQdMfDA8TEo7pv5X8yfrvVO3xbJbLUlERCMvf6X0hTUamQxCYJ9Q==", + "license": "MIT", + "dependencies": { + "ip-regex": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", + "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-online": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/is-online/-/is-online-10.0.0.tgz", + "integrity": "sha512-WCPdKwNDjXJJmUubf2VHLMDBkUZEtuOvpXUfUnUFbEnM6In9ByiScL4f4jKACz/fsb2qDkesFerW3snf/AYz3A==", + "license": "MIT", + "dependencies": { + "got": "^12.1.0", + "p-any": "^4.0.0", + "p-timeout": "^5.1.0", + "public-ip": "^5.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-online/node_modules/got": { + "version": "12.6.1", + "resolved": "https://registry.npmjs.org/got/-/got-12.6.1.tgz", + "integrity": "sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ==", + "license": "MIT", + "dependencies": { + "@sindresorhus/is": "^5.2.0", + "@szmarczak/http-timer": "^5.0.1", + "cacheable-lookup": "^7.0.0", + "cacheable-request": "^10.2.8", + "decompress-response": "^6.0.0", + "form-data-encoder": "^2.1.2", + "get-stream": "^6.0.1", + "http2-wrapper": "^2.1.10", + "lowercase-keys": "^3.0.0", + "p-cancelable": "^3.0.0", + "responselike": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", + "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", + "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", + "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", + "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", + "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/jiti": { + "version": "1.21.7", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", + "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", + "license": "MIT", + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/jose": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/jose/-/jose-6.2.3.tgz", + "integrity": "sha512-YYVDInQKFJfR/xa3ojUTl8c2KoTwiL1R5Wg9YCydwH0x0B9grbzlg5HC7mMjCtUJjbQ/YnGEZIhI5tCgfTb4Hw==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsep": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jsep/-/jsep-1.4.0.tgz", + "integrity": "sha512-B7qPcEVE3NVkmSJbaYxvv4cHkVW7DQsZz13pUMrfS8z8Q/BuShN+gcTXrUlPiGqM2/t/EEaI030bpxMqY8gMlw==", + "license": "MIT", + "engines": { + "node": ">= 10.16.0" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "license": "MIT" + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" + }, + "node_modules/jsonc-parser": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-2.2.1.tgz", + "integrity": "sha512-o6/yDBYccGvTz1+QFevz6l6OBZ2+fMVu2JZ9CIhzsYRX4mjaK5IyX9eldUdCmga16zlgQxyrj5pt9kzuj2C02w==", + "license": "MIT" + }, + "node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonpath-plus": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/jsonpath-plus/-/jsonpath-plus-10.4.0.tgz", + "integrity": "sha512-T92WWatJXmhBbKsgH/0hl+jxjdXrifi5IKeMY02DWggRxX0UElcbVzPlmgLTbvsPeW1PasQ6xE2Q75stkhGbsA==", + "license": "MIT", + "dependencies": { + "@jsep-plugin/assignment": "^1.3.0", + "@jsep-plugin/regex": "^1.0.4", + "jsep": "^1.4.0" + }, + "bin": { + "jsonpath": "bin/jsonpath-cli.js", + "jsonpath-plus": "bin/jsonpath-cli.js" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/jsonpointer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", + "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/katex": { + "version": "0.16.47", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.47.tgz", + "integrity": "sha512-Eeo8Ys1doU1z+x8AZsPpQu+p/QcZBI5PeOo7QGQdy2x2m0MU/hYagBbGOmXwr5KVbEfVuWv9LpnQWeehogurjg==", + "funding": [ + "https://opencollective.com/katex", + "https://github.com/sponsors/katex" + ], + "license": "MIT", + "dependencies": { + "commander": "^8.3.0" + }, + "bin": { + "katex": "cli.js" + } + }, + "node_modules/keytar": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/keytar/-/keytar-7.9.0.tgz", + "integrity": "sha512-VPD8mtVtm5JNtA2AErl6Chp06JBfy7diFQ7TQQhdpWOl6MrCRB+eRbvAZUsbGQS9kiMq0coJsy0W0vHpDCkWsQ==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "node-addon-api": "^4.3.0", + "prebuild-install": "^7.0.1" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/lcm": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/lcm/-/lcm-0.0.3.tgz", + "integrity": "sha512-TB+ZjoillV6B26Vspf9l2L/vKaRY/4ep3hahcyVkCGFgsTNRUQdc24bQeNFiZeoxH0vr5+7SfNRMQuPHv/1IrQ==", + "license": "MIT", + "dependencies": { + "gcd": "^0.0.1" + } + }, + "node_modules/leven": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-4.1.0.tgz", + "integrity": "sha512-KZ9W9nWDT7rF7Dazg8xyLHGLrmpgq2nVNFUckhqdW3szVP6YhCpp/RAnpmVExA9JvrMynjwSLVrEj3AepHR6ew==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "license": "MIT" + }, + "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==", + "license": "MIT" + }, + "node_modules/lodash.topath": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/lodash.topath/-/lodash.topath-4.5.2.tgz", + "integrity": "sha512-1/W4dM+35DwvE/iEd1M9ekewOSTlpFekhw9mhAtrwjVqUr83/ilQiyAvmg4tVX7Unkcfl1KC+i9WdaT4B6aQcg==", + "license": "MIT" + }, + "node_modules/longest-streak": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", + "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "peer": true, + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lowercase-keys": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", + "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/markdown-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/markdown-extensions/-/markdown-extensions-2.0.0.tgz", + "integrity": "sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q==", + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/markdown-table": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz", + "integrity": "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mdast-util-find-and-replace": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz", + "integrity": "sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "escape-string-regexp": "^5.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-from-markdown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.2.tgz", + "integrity": "sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark": "^4.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-frontmatter": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-frontmatter/-/mdast-util-frontmatter-2.0.1.tgz", + "integrity": "sha512-LRqI9+wdgC25P0URIJY9vwocIzCcksduHQ9OF2joxQoyTNVduwLAFUzjoopuRJbJAReaKrNQKAZKL3uCMugWJA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "escape-string-regexp": "^5.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "micromark-extension-frontmatter": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.0.0.tgz", + "integrity": "sha512-dgQEX5Amaq+DuUqf26jJqSK9qgixgd6rYDHAv4aTBuA92cTknZlKpPfa86Z/s8Dj8xsAQpFfBmPUHWJBWqS4Bw==", + "license": "MIT", + "dependencies": { + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-gfm-autolink-literal": "^2.0.0", + "mdast-util-gfm-footnote": "^2.0.0", + "mdast-util-gfm-strikethrough": "^2.0.0", + "mdast-util-gfm-table": "^2.0.0", + "mdast-util-gfm-task-list-item": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-autolink-literal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.1.tgz", + "integrity": "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "ccount": "^2.0.0", + "devlop": "^1.0.0", + "mdast-util-find-and-replace": "^3.0.0", + "micromark-util-character": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-strikethrough": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz", + "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-table": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz", + "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "markdown-table": "^3.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-task-list-item": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz", + "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-math": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-math/-/mdast-util-math-3.0.0.tgz", + "integrity": "sha512-Tl9GBNeG/AhJnQM221bJR2HPvLOSnLE/T9cJI9tlc6zwQk2nPk/4f0cHkOdEixQPC/j8UtKDdITswvLAy1OZ1w==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "longest-streak": "^3.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.1.0", + "unist-util-remove-position": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx/-/mdast-util-mdx-3.0.0.tgz", + "integrity": "sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w==", + "license": "MIT", + "dependencies": { + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-expression": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz", + "integrity": "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-jsx": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.2.0.tgz", + "integrity": "sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "parse-entities": "^4.0.0", + "stringify-entities": "^4.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdxjs-esm": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz", + "integrity": "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-phrasing": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", + "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-hast": { + "version": "13.2.1", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz", + "integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-markdown": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz", + "integrity": "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "longest-streak": "^3.0.0", + "mdast-util-phrasing": "^4.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "unist-util-visit": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", + "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromark": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", + "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz", + "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-destination": "^2.0.0", + "micromark-factory-label": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-title": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-html-tag-name": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-frontmatter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-frontmatter/-/micromark-extension-frontmatter-2.0.0.tgz", + "integrity": "sha512-C4AkuM3dA58cgZha7zVnuVxBhDsbttIMiytjgsM2XbHAB2faRVaHRle40558FBN+DJcrLNCoqG5mlrpdU4cRtg==", + "license": "MIT", + "dependencies": { + "fault": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz", + "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==", + "license": "MIT", + "dependencies": { + "micromark-extension-gfm-autolink-literal": "^2.0.0", + "micromark-extension-gfm-footnote": "^2.0.0", + "micromark-extension-gfm-strikethrough": "^2.0.0", + "micromark-extension-gfm-table": "^2.0.0", + "micromark-extension-gfm-tagfilter": "^2.0.0", + "micromark-extension-gfm-task-list-item": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-autolink-literal": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz", + "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==", + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-strikethrough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz", + "integrity": "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-table": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.1.tgz", + "integrity": "sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-tagfilter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz", + "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==", + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-task-list-item": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz", + "integrity": "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-math": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-math/-/micromark-extension-math-3.1.0.tgz", + "integrity": "sha512-lvEqd+fHjATVs+2v/8kg9i5Q0AP2k85H0WUOwpIVvUML8BapsMvh1XAogmQjOCsLpoKRCVQqEkQBB3NhVBcsOg==", + "license": "MIT", + "dependencies": { + "@types/katex": "^0.16.0", + "devlop": "^1.0.0", + "katex": "^0.16.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdx-expression": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-expression/-/micromark-extension-mdx-expression-3.0.1.tgz", + "integrity": "sha512-dD/ADLJ1AeMvSAKBwO22zG22N4ybhe7kFIZ3LsDI0GlsNr2A3KYxb0LdC1u5rj4Nw+CHKY0RVdnHX8vj8ejm4Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-mdx-expression": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-mdx-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-jsx/-/micromark-extension-mdx-jsx-3.0.1.tgz", + "integrity": "sha512-vNuFb9czP8QCtAQcEJn0UJQJZA8Dk6DXKBqx+bg/w0WGuSxDxNr7hErW89tHUY31dUW4NqEOWwmEUNhjTFmHkg==", + "license": "MIT", + "dependencies": { + "@types/acorn": "^4.0.0", + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "micromark-factory-mdx-expression": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdx-md": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-md/-/micromark-extension-mdx-md-2.0.0.tgz", + "integrity": "sha512-EpAiszsB3blw4Rpba7xTOUptcFeBFi+6PY8VnJ2hhimH+vCQDirWgsMpz7w1XcZE7LVrSAUGb9VJpG9ghlYvYQ==", + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdxjs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs/-/micromark-extension-mdxjs-3.0.0.tgz", + "integrity": "sha512-A873fJfhnJ2siZyUrJ31l34Uqwy4xIFmvPY1oj+Ean5PHcPBYzEsvqvWGaWcfEIr11O5Dlw3p2y0tZWpKHDejQ==", + "license": "MIT", + "dependencies": { + "acorn": "^8.0.0", + "acorn-jsx": "^5.0.0", + "micromark-extension-mdx-expression": "^3.0.0", + "micromark-extension-mdx-jsx": "^3.0.0", + "micromark-extension-mdx-md": "^2.0.0", + "micromark-extension-mdxjs-esm": "^3.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdxjs-esm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs-esm/-/micromark-extension-mdxjs-esm-3.0.0.tgz", + "integrity": "sha512-DJFl4ZqkErRpq/dAPyeWp15tGrcrrJho1hKK5uBS70BCtfrIFg81sqcTVu3Ta+KD1Tk5vAtBNElWxtAa+m8K9A==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-factory-destination": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", + "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-label": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz", + "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-mdx-expression": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-factory-mdx-expression/-/micromark-factory-mdx-expression-2.0.3.tgz", + "integrity": "sha512-kQnEtA3vzucU2BkrIa8/VaSAsP+EJ3CKOvhMuJgOEGg9KDC6OAY6nSnNDVRiVNRqj7Y4SlSzcStaH/5jge8JdQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" + } + }, + "node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-title": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz", + "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-whitespace": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz", + "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-chunked": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz", + "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-classify-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz", + "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-combine-extensions": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz", + "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-chunked": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz", + "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-string": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz", + "integrity": "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-events-to-acorn": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-util-events-to-acorn/-/micromark-util-events-to-acorn-2.0.3.tgz", + "integrity": "sha512-jmsiEIiZ1n7X1Rr5k8wVExBQCg5jy4UXVADItHmNk1zkwEVhBuIUKRu3fqv+hs4nxLISi2DQGlqIOGiFxgbfHg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "estree-util-visit": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "vfile-message": "^4.0.0" + } + }, + "node_modules/micromark-util-html-tag-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", + "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-normalize-identifier": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz", + "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-resolve-all": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz", + "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-subtokenize": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz", + "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-types": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", + "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/mimic-response": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz", + "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "optional": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minizlib": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz", + "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==", + "license": "MIT", + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/mint": { + "version": "4.2.574", + "resolved": "https://registry.npmjs.org/mint/-/mint-4.2.574.tgz", + "integrity": "sha512-nBKqwacZExzPTrg7SQHZZxqzc3cwYzUsplJgwkc/DFQJ8BJyeL1n266rS8jAFxDHKEjQUdwOa/d9hyB8wsN+3Q==", + "license": "Elastic-2.0", + "dependencies": { + "@mintlify/cli": "4.0.1177" + }, + "bin": { + "mint": "index.js" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/mitt": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", + "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", + "license": "MIT" + }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "license": "MIT", + "optional": true + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "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==", + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.12", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", + "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/napi-build-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz", + "integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==", + "license": "MIT", + "optional": true + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neotraverse": { + "version": "0.6.18", + "resolved": "https://registry.npmjs.org/neotraverse/-/neotraverse-0.6.18.tgz", + "integrity": "sha512-Z4SmBUweYa09+o6pG+eASabEpP6QkQ70yHj351pQoEXIs8uHbaU2DWVmzBANKgflPa47A50PtB2+NgRpQvr7vA==", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/netmask": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.1.1.tgz", + "integrity": "sha512-eonl3sLUha+S1GzTPxychyhnUzKyeQkZ7jLjKrBagJgPla13F+uQ71HgpFefyHgqrjEbCPkDArxYsjY8/+gLKA==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/nimma": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/nimma/-/nimma-0.2.3.tgz", + "integrity": "sha512-1ZOI8J+1PKKGceo/5CT5GfQOG6H8I2BencSK06YarZ2wXwH37BSSUWldqJmMJYA5JfqDqffxDXynt6f11AyKcA==", + "license": "Apache-2.0", + "dependencies": { + "@jsep-plugin/regex": "^1.0.1", + "@jsep-plugin/ternary": "^1.0.2", + "astring": "^1.8.1", + "jsep": "^1.2.0" + }, + "engines": { + "node": "^12.20 || >=14.13" + }, + "optionalDependencies": { + "jsonpath-plus": "^6.0.1 || ^10.1.0", + "lodash.topath": "^4.5.2" + } + }, + "node_modules/nlcst-to-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/nlcst-to-string/-/nlcst-to-string-4.0.0.tgz", + "integrity": "sha512-YKLBCcUYKAg0FNlOBT6aI91qFmSiFKiluk655WzPF+DDMA02qIyy8uiRqI8QXtcFpEvll12LpL5MXqEmAZ+dcA==", + "license": "MIT", + "dependencies": { + "@types/nlcst": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/node-abi": { + "version": "3.92.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.92.0.tgz", + "integrity": "sha512-KdHvFWZjEKDf0cakgFjebl371GPsISX2oZHcuyKqM7DtogIsHrqKeLTo8wBHxaXRAQlY2PsPlZmfo+9ZCxEREQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-addon-api": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz", + "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==", + "license": "MIT", + "optional": true + }, + "node_modules/node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/non-error": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/non-error/-/non-error-0.1.0.tgz", + "integrity": "sha512-TMB1uHiGsHRGv1uYclfhivcnf0/PdFp2pNqRxXjncaAsjYMoisaQJI+SSZCqRq+VliwRTC8tsMQfmrWjDMhkPQ==", + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-url": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.1.1.tgz", + "integrity": "sha512-JYc0DPlpGWB40kH5g07gGTrYuMqV653k3uBKY6uITPWds3M0ov3GaWGp9lbE3Bzngx8+XkfzgvASb9vk9JDFXQ==", + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/oauth4webapi": { + "version": "3.8.6", + "resolved": "https://registry.npmjs.org/oauth4webapi/-/oauth4webapi-3.8.6.tgz", + "integrity": "sha512-iwemM91xz8nryHti2yTmg5fhyEMVOkOXwHNqbvcATjyajb5oQxCQzrNOA6uElRHuMhQQTKUyFKV9y/CNyg25BQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/oniguruma-parser": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/oniguruma-parser/-/oniguruma-parser-0.12.2.tgz", + "integrity": "sha512-6HVa5oIrgMC6aA6WF6XyyqbhRPJrKR02L20+2+zpDtO5QAzGHAUGw5TKQvwi5vctNnRHkJYmjAhRVQF2EKdTQw==", + "license": "MIT" + }, + "node_modules/oniguruma-to-es": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/oniguruma-to-es/-/oniguruma-to-es-4.3.6.tgz", + "integrity": "sha512-csuQ9x3Yr0cEIs/Zgx/OEt9iBw9vqIunAPQkx19R/fiMq2oGVTgcMqO/V3Ybqefr1TBvosI6jU539ksaBULJyA==", + "license": "MIT", + "dependencies": { + "oniguruma-parser": "^0.12.2", + "regex": "^6.1.0", + "regex-recursion": "^6.0.2" + } + }, + "node_modules/open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "license": "MIT", + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/openapi-types": { + "version": "12.1.3", + "resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-12.1.3.tgz", + "integrity": "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==", + "license": "MIT" + }, + "node_modules/openid-client": { + "version": "6.8.2", + "resolved": "https://registry.npmjs.org/openid-client/-/openid-client-6.8.2.tgz", + "integrity": "sha512-uOvTCndr4udZsKihJ68H9bUICrriHdUVJ6Az+4Ns6cW55rwM5h0bjVIzDz2SxgOI84LKjFyjOFvERLzdTUROGA==", + "license": "MIT", + "dependencies": { + "jose": "^6.1.3", + "oauth4webapi": "^3.8.4" + }, + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/own-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", + "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.6", + "object-keys": "^1.1.1", + "safe-push-apply": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/p-any": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-any/-/p-any-4.0.0.tgz", + "integrity": "sha512-S/B50s+pAVe0wmEZHmBs/9yJXeZ5KhHzOsgKzt0hRdgkoR3DxW9ts46fcsWi/r3VnzsnkKS7q4uimze+zjdryw==", + "license": "MIT", + "dependencies": { + "p-cancelable": "^3.0.0", + "p-some": "^6.0.0" + }, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-cancelable": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz", + "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==", + "license": "MIT", + "engines": { + "node": ">=12.20" + } + }, + "node_modules/p-some": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-some/-/p-some-6.0.0.tgz", + "integrity": "sha512-CJbQCKdfSX3fIh8/QKgS+9rjm7OBNUTmwWswAFQAhc8j1NR1dsEDETUEuVUtQHZpV+J03LqWBEwvu0g1Yn+TYg==", + "license": "MIT", + "dependencies": { + "aggregate-error": "^4.0.0", + "p-cancelable": "^3.0.0" + }, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-timeout": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-5.1.0.tgz", + "integrity": "sha512-auFDyzzzGZZZdHz3BtET9VEz0SE/uMEAx7uWfGPucfzEwwe/xH0iVeZibQmANYE/hp9T2+UUZT5m+BKyrDp3Ew==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "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-proxy-agent/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==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/pac-proxy-agent/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==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "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==", + "license": "MIT", + "dependencies": { + "degenerator": "^5.0.0", + "netmask": "^2.0.2" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/pagefind": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/pagefind/-/pagefind-1.5.2.tgz", + "integrity": "sha512-XTUaK0hXMCu2jszWE584JGQT7y284TmMV9l/HX3rnG5uo3rHI/uHU56XTyyyPFjeWEBxECbAi0CaFDJOONtG0Q==", + "dev": true, + "license": "MIT", + "bin": { + "pagefind": "lib/runner/bin.cjs" + }, + "optionalDependencies": { + "@pagefind/darwin-arm64": "1.5.2", + "@pagefind/darwin-x64": "1.5.2", + "@pagefind/freebsd-x64": "1.5.2", + "@pagefind/linux-arm64": "1.5.2", + "@pagefind/linux-x64": "1.5.2", + "@pagefind/windows-arm64": "1.5.2", + "@pagefind/windows-x64": "1.5.2" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-entities": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz", + "integrity": "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "character-entities-legacy": "^3.0.0", + "character-reference-invalid": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "is-alphanumerical": "^2.0.0", + "is-decimal": "^2.0.0", + "is-hexadecimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/parse-entities/node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "license": "MIT" + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse-latin": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse-latin/-/parse-latin-7.0.0.tgz", + "integrity": "sha512-mhHgobPPua5kZ98EF4HWiH167JWBfl4pvAIXXdbaVohtK7a6YBOy56kvhCqduqyo/f3yrHFWmqmiMg/BkBkYYQ==", + "license": "MIT", + "dependencies": { + "@types/nlcst": "^2.0.0", + "@types/unist": "^3.0.0", + "nlcst-to-string": "^4.0.0", + "unist-util-modify-children": "^4.0.0", + "unist-util-visit-children": "^3.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/parse5": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", + "license": "MIT", + "dependencies": { + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/patch-console": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/patch-console/-/patch-console-2.0.0.tgz", + "integrity": "sha512-0YNdUceMdaQwoKce1gatDScmMo5pu/tfABfnzEqeG0gtTmd7mh/WcwgUjtAeOU7N8nFFlbQBnFK2gXW5fGvmMA==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "license": "MIT" + }, + "node_modules/path-to-regexp": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.13.tgz", + "integrity": "sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==", + "license": "MIT" + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/pony-cause": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pony-cause/-/pony-cause-1.1.1.tgz", + "integrity": "sha512-PxkIc/2ZpLiEzQXu5YRDOUgBlfGYBY8156HY5ZcRAwwonMk5W/MrJP2LLkG/hF7GEQzaHo2aS7ho6ZLCOvf+6g==", + "license": "0BSD", + "engines": { + "node": ">=12.0.0" + } + }, + "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", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/postcss": { + "version": "8.5.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.14.tgz", + "integrity": "sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-js": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.1.0.tgz", + "integrity": "sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "peerDependencies": { + "postcss": "^8.4.21" + } + }, + "node_modules/postcss-load-config": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", + "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "lilconfig": "^3.0.0", + "yaml": "^2.3.4" + }, + "engines": { + "node": ">= 14" + }, + "peerDependencies": { + "postcss": ">=8.0.9", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/postcss-nested": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", + "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.1.1" + }, + "engines": { + "node": ">=12.0" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "license": "MIT" + }, + "node_modules/posthog-node": { + "version": "5.17.2", + "resolved": "https://registry.npmjs.org/posthog-node/-/posthog-node-5.17.2.tgz", + "integrity": "sha512-lz3YJOr0Nmiz0yHASaINEDHqoV+0bC3eD8aZAG+Ky292dAnVYul+ga/dMX8KCBXg8hHfKdxw0SztYD5j6dgUqQ==", + "license": "MIT", + "dependencies": { + "@posthog/core": "1.7.1" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/prebuild-install": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz", + "integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==", + "deprecated": "No longer maintained. Please contact the author of the relevant native addon; alternatives are available.", + "license": "MIT", + "optional": true, + "dependencies": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^2.0.0", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/property-information": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz", + "integrity": "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "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==", + "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/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==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/proxy-agent/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==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "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==", + "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", + "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/public-ip": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/public-ip/-/public-ip-5.0.0.tgz", + "integrity": "sha512-xaH3pZMni/R2BG7ZXXaWS9Wc9wFlhyDVJF47IJ+3ali0TGv+2PsckKxbmo+rnx3ZxiV2wblVhtdS3bohAP6GGw==", + "license": "MIT", + "dependencies": { + "dns-socket": "^4.2.2", + "got": "^12.0.0", + "is-ip": "^3.1.0" + }, + "engines": { + "node": "^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/public-ip/node_modules/got": { + "version": "12.6.1", + "resolved": "https://registry.npmjs.org/got/-/got-12.6.1.tgz", + "integrity": "sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ==", + "license": "MIT", + "dependencies": { + "@sindresorhus/is": "^5.2.0", + "@szmarczak/http-timer": "^5.0.1", + "cacheable-lookup": "^7.0.0", + "cacheable-request": "^10.2.8", + "decompress-response": "^6.0.0", + "form-data-encoder": "^2.1.2", + "get-stream": "^6.0.1", + "http2-wrapper": "^2.1.10", + "lowercase-keys": "^3.0.0", + "p-cancelable": "^3.0.0", + "responselike": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/pump": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", + "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/puppeteer": { + "version": "22.14.0", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-22.14.0.tgz", + "integrity": "sha512-MGTR6/pM8zmWbTdazb6FKnwIihzsSEXBPH49mFFU96DNZpQOevCAZMnjBZGlZRGRzRK6aADCavR6SQtrbv5dQw==", + "deprecated": "< 24.15.0 is no longer supported", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@puppeteer/browsers": "2.3.0", + "cosmiconfig": "^9.0.0", + "devtools-protocol": "0.0.1312386", + "puppeteer-core": "22.14.0" + }, + "bin": { + "puppeteer": "lib/esm/puppeteer/node/cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/puppeteer-core": { + "version": "22.14.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-22.14.0.tgz", + "integrity": "sha512-rl4tOY5LcA3e374GAlsGGHc05HL3eGNf5rZ+uxkl6id9zVZKcwcp1Z+Nd6byb6WPiPeecT/dwz8f/iUm+AZQSw==", + "license": "Apache-2.0", + "dependencies": { + "@puppeteer/browsers": "2.3.0", + "chromium-bidi": "0.6.2", + "debug": "^4.3.5", + "devtools-protocol": "0.0.1312386", + "ws": "^8.18.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/qs": { + "version": "6.14.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz", + "integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", + "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/raw-body/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "optional": true, + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/react": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz", + "integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-reconciler": { + "version": "0.32.0", + "resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.32.0.tgz", + "integrity": "sha512-2NPMOzgTlG0ZWdIf3qG+dcbLSoAc/uLfOwckc3ofy5sSK0pLJqnQLpUFxvGcN2rlXSjnVtGeeFLNimCQEj5gOQ==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.26.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "peerDependencies": { + "react": "^19.1.0" + } + }, + "node_modules/react-remove-scroll": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.2.tgz", + "integrity": "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==", + "license": "MIT", + "peer": true, + "dependencies": { + "react-remove-scroll-bar": "^2.3.7", + "react-style-singleton": "^2.2.3", + "tslib": "^2.1.0", + "use-callback-ref": "^1.3.3", + "use-sidecar": "^1.1.3" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-remove-scroll-bar": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz", + "integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==", + "license": "MIT", + "peer": true, + "dependencies": { + "react-style-singleton": "^2.2.2", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-remove-scroll-bar/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD", + "peer": true + }, + "node_modules/react-remove-scroll/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD", + "peer": true + }, + "node_modules/react-style-singleton": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz", + "integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "get-nonce": "^1.0.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-style-singleton/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD", + "peer": true + }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "license": "MIT", + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "optional": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/recma-build-jsx": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/recma-build-jsx/-/recma-build-jsx-1.0.0.tgz", + "integrity": "sha512-8GtdyqaBcDfva+GUKDr3nev3VpKAhup1+RvkMvUxURHpW7QyIvk9F5wz7Vzo06CEMSilw6uArgRqhpiUcWp8ew==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-util-build-jsx": "^3.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/recma-jsx": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/recma-jsx/-/recma-jsx-1.0.1.tgz", + "integrity": "sha512-huSIy7VU2Z5OLv6oFLosQGGDqPqdO1iq6bWNAdhzMxSJP7RAso4fCZ1cKu8j9YHCZf3TPrq4dw3okhrylgcd7w==", + "license": "MIT", + "dependencies": { + "acorn-jsx": "^5.0.0", + "estree-util-to-js": "^2.0.0", + "recma-parse": "^1.0.0", + "recma-stringify": "^1.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/recma-parse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/recma-parse/-/recma-parse-1.0.0.tgz", + "integrity": "sha512-OYLsIGBB5Y5wjnSnQW6t3Xg7q3fQ7FWbw/vcXtORTnyaSFscOtABg+7Pnz6YZ6c27fG1/aN8CjfwoUEUIdwqWQ==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "esast-util-from-js": "^2.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/recma-stringify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/recma-stringify/-/recma-stringify-1.0.0.tgz", + "integrity": "sha512-cjwII1MdIIVloKvC9ErQ+OgAtwHBmcZ0Bg4ciz78FtbT8In39aAYbaA7zvxQ61xVMSPE8WxhLwLbhif4Js2C+g==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-util-to-js": "^2.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", + "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.1", + "which-builtin-type": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/regex/-/regex-6.1.0.tgz", + "integrity": "sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==", + "license": "MIT", + "dependencies": { + "regex-utilities": "^2.3.0" + } + }, + "node_modules/regex-recursion": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/regex-recursion/-/regex-recursion-6.0.2.tgz", + "integrity": "sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==", + "license": "MIT", + "dependencies": { + "regex-utilities": "^2.3.0" + } + }, + "node_modules/regex-utilities": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/regex-utilities/-/regex-utilities-2.3.0.tgz", + "integrity": "sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==", + "license": "MIT" + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", + "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/rehype-katex": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/rehype-katex/-/rehype-katex-7.0.1.tgz", + "integrity": "sha512-OiM2wrZ/wuhKkigASodFoo8wimG3H12LWQaH8qSPVJn9apWKFSH3YOCtbKpBorTVw/eI7cuT21XBbvwEswbIOA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/katex": "^0.16.0", + "hast-util-from-html-isomorphic": "^2.0.0", + "hast-util-to-text": "^4.0.0", + "katex": "^0.16.0", + "unist-util-visit-parents": "^6.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-minify-whitespace": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/rehype-minify-whitespace/-/rehype-minify-whitespace-6.0.2.tgz", + "integrity": "sha512-Zk0pyQ06A3Lyxhe9vGtOtzz3Z0+qZ5+7icZ/PL/2x1SHPbKao5oB/g/rlc6BCTajqBb33JcOe71Ye1oFsuYbnw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-minify-whitespace": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-parse": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/rehype-parse/-/rehype-parse-9.0.1.tgz", + "integrity": "sha512-ksCzCD0Fgfh7trPDxr2rSylbwq9iYDkSn8TCDmEJ49ljEUBxDVCzCHv7QNzZOfODanX4+bWQ4WZqLCRWYLfhag==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-from-html": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-recma": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/rehype-recma/-/rehype-recma-1.0.0.tgz", + "integrity": "sha512-lqA4rGUf1JmacCNWWZx0Wv1dHqMwxzsDWYMTowuplHF3xH0N/MmrZ/G3BDZnzAkRmxDadujCjaKM2hqYdCBOGw==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/hast": "^3.0.0", + "hast-util-to-estree": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-stringify": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/rehype-stringify/-/rehype-stringify-10.0.1.tgz", + "integrity": "sha512-k9ecfXHmIPuFVI61B9DeLPN0qFHfawM6RsuX48hoqlaKSF61RskNjSm1lI8PhBEM0MRdLxVVm4WmTqJQccH9mA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-to-html": "^9.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark": { + "version": "15.0.1", + "resolved": "https://registry.npmjs.org/remark/-/remark-15.0.1.tgz", + "integrity": "sha512-Eht5w30ruCXgFmxVUSlNWQ9iiimq07URKeFS3hNc8cUWy1llX4KDWfyEDZRycMc+znsN9Ux5/tJ/BFdgdOwA3A==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "remark-parse": "^11.0.0", + "remark-stringify": "^11.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-frontmatter": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/remark-frontmatter/-/remark-frontmatter-5.0.0.tgz", + "integrity": "sha512-XTFYvNASMe5iPN0719nPrdItC9aU0ssC4v14mH1BCi1u0n1gAocqcujWUrByftZTbLhRtiKRyjYTSIOcr69UVQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-frontmatter": "^2.0.0", + "micromark-extension-frontmatter": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-gfm": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.0.tgz", + "integrity": "sha512-U92vJgBPkbw4Zfu/IiW2oTZLSL3Zpv+uI7My2eq8JxKgqraFdU8YUGicEJCEgSbeaG+QDFqIcwwfMTOEelPxuA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-gfm": "^3.0.0", + "micromark-extension-gfm": "^3.0.0", + "remark-parse": "^11.0.0", + "remark-stringify": "^11.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-math": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/remark-math/-/remark-math-6.0.0.tgz", + "integrity": "sha512-MMqgnP74Igy+S3WwnhQ7kqGlEerTETXMvJhrUzDikVZ2/uogJCb+WHUg97hK9/jcfc0dkD73s3LN8zU49cTEtA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-math": "^3.0.0", + "micromark-extension-math": "^3.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-mdx": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-3.1.0.tgz", + "integrity": "sha512-Ngl/H3YXyBV9RcRNdlYsZujAmhsxwzxpDzpDEhFBVAGthS4GDgnctpDjgFl/ULx5UEDzqtW1cyBSNKqYYrqLBA==", + "license": "MIT", + "dependencies": { + "mdast-util-mdx": "^3.0.0", + "micromark-extension-mdxjs": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-mdx-remove-esm": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/remark-mdx-remove-esm/-/remark-mdx-remove-esm-1.3.1.tgz", + "integrity": "sha512-POa8abdiuicD2e+zQkclxzJa5JEGLtV8XIOFVvisnGuw4l4xd6dfQozedwqR8JTeXQmxLebvYhlbwHoQP9RWkw==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.4", + "mdast-util-mdxjs-esm": "^2.0.1", + "unist-util-remove": "^4.0.0" + }, + "peerDependencies": { + "unified": "^11" + } + }, + "node_modules/remark-parse": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", + "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-rehype": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.1.tgz", + "integrity": "sha512-g/osARvjkBXb6Wo0XvAeXQohVta8i84ACbenPpoSsxTOQH/Ae0/RGP4WZgnMH5pMLpsj4FG7OHmcIcXxpza8eQ==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "mdast-util-to-hast": "^13.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-smartypants": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/remark-smartypants/-/remark-smartypants-3.0.2.tgz", + "integrity": "sha512-ILTWeOriIluwEvPjv67v7Blgrcx+LZOkAUVtKI3putuhlZm84FnqDORNXPPm+HY3NdZOMhyDwZ1E+eZB/Df5dA==", + "license": "MIT", + "dependencies": { + "retext": "^9.0.0", + "retext-smartypants": "^6.0.0", + "unified": "^11.0.4", + "unist-util-visit": "^5.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/remark-stringify": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz", + "integrity": "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-to-markdown": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", + "license": "MIT" + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/responselike": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz", + "integrity": "sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==", + "license": "MIT", + "dependencies": { + "lowercase-keys": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/restore-cursor": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz", + "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==", + "license": "MIT", + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/restore-cursor/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "license": "ISC" + }, + "node_modules/retext": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/retext/-/retext-9.0.0.tgz", + "integrity": "sha512-sbMDcpHCNjvlheSgMfEcVrZko3cDzdbe1x/e7G66dFp0Ff7Mldvi2uv6JkJQzdRcvLYE8CA8Oe8siQx8ZOgTcA==", + "license": "MIT", + "dependencies": { + "@types/nlcst": "^2.0.0", + "retext-latin": "^4.0.0", + "retext-stringify": "^4.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/retext-latin": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/retext-latin/-/retext-latin-4.0.0.tgz", + "integrity": "sha512-hv9woG7Fy0M9IlRQloq/N6atV82NxLGveq+3H2WOi79dtIYWN8OaxogDm77f8YnVXJL2VD3bbqowu5E3EMhBYA==", + "license": "MIT", + "dependencies": { + "@types/nlcst": "^2.0.0", + "parse-latin": "^7.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/retext-smartypants": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/retext-smartypants/-/retext-smartypants-6.2.0.tgz", + "integrity": "sha512-kk0jOU7+zGv//kfjXEBjdIryL1Acl4i9XNkHxtM7Tm5lFiCog576fjNC9hjoR7LTKQ0DsPWy09JummSsH1uqfQ==", + "license": "MIT", + "dependencies": { + "@types/nlcst": "^2.0.0", + "nlcst-to-string": "^4.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/retext-stringify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/retext-stringify/-/retext-stringify-4.0.0.tgz", + "integrity": "sha512-rtfN/0o8kL1e+78+uxPTqu1Klt0yPzKuQ2BfWwwfgIUSayyzxpM1PJzkKt4V8803uB9qSy32MvI7Xep9khTpiA==", + "license": "MIT", + "dependencies": { + "@types/nlcst": "^2.0.0", + "nlcst-to-string": "^4.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/run-async": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-3.0.0.tgz", + "integrity": "sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q==", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "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==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/rxjs/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/safe-array-concat": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.4.tgz", + "integrity": "sha512-wtZlHyOje6OZTGqAoaDKxFkgRtkF9CnHAVnCHKfuj200wAgL+bSJhdsCD2l0Qx/2ekEXjPWcyKkfGb5CPboslg==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "get-intrinsic": "^1.3.0", + "has-symbols": "^1.1.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safe-push-apply": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", + "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-stable-stringify": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-1.1.1.tgz", + "integrity": "sha512-ERq4hUjKDbJfE4+XtZLFPCDi8Vb1JqaxAPTxWFLBx8XcAlf9Bda/ZJdVezs/NAfsMQScyIlUMx+Yeu7P7rx5jw==", + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/sax": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.0.tgz", + "integrity": "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=11.0.0" + } + }, + "node_modules/scheduler": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz", + "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==", + "license": "MIT" + }, + "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==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz", + "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.1", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "~2.4.1", + "range-parser": "~1.2.1", + "statuses": "~2.0.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/serialize-error": { + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-13.0.1.tgz", + "integrity": "sha512-bBZaRwLH9PN5HbLCjPId4dP5bNGEtumcErgOX952IsvOhVPrm3/AeK1y0UHA/QaPG701eg0yEnOKsCOC6X/kaA==", + "license": "MIT", + "dependencies": { + "non-error": "^0.1.0", + "type-fest": "^5.4.1" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/serialize-error/node_modules/type-fest": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-5.6.0.tgz", + "integrity": "sha512-8ZiHFm91orbSAe2PSAiSVBVko18pbhbiB3U9GglSzF/zCGkR+rxpHx6sEMCUm4kxY4LjDIUGgCfUMtwfZfjfUA==", + "license": "(MIT OR CC0-1.0)", + "dependencies": { + "tagged-tag": "^1.0.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/serve-static": { + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz", + "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==", + "license": "MIT", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "~0.19.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", + "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/sharp": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.5.tgz", + "integrity": "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "color": "^4.2.3", + "detect-libc": "^2.0.3", + "semver": "^7.6.3" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.33.5", + "@img/sharp-darwin-x64": "0.33.5", + "@img/sharp-libvips-darwin-arm64": "1.0.4", + "@img/sharp-libvips-darwin-x64": "1.0.4", + "@img/sharp-libvips-linux-arm": "1.0.5", + "@img/sharp-libvips-linux-arm64": "1.0.4", + "@img/sharp-libvips-linux-s390x": "1.0.4", + "@img/sharp-libvips-linux-x64": "1.0.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.0.4", + "@img/sharp-libvips-linuxmusl-x64": "1.0.4", + "@img/sharp-linux-arm": "0.33.5", + "@img/sharp-linux-arm64": "0.33.5", + "@img/sharp-linux-s390x": "0.33.5", + "@img/sharp-linux-x64": "0.33.5", + "@img/sharp-linuxmusl-arm64": "0.33.5", + "@img/sharp-linuxmusl-x64": "0.33.5", + "@img/sharp-wasm32": "0.33.5", + "@img/sharp-win32-ia32": "0.33.5", + "@img/sharp-win32-x64": "0.33.5" + } + }, + "node_modules/sharp-ico": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/sharp-ico/-/sharp-ico-0.1.5.tgz", + "integrity": "sha512-a3jODQl82NPp1d5OYb0wY+oFaPk7AvyxipIowCHk7pBsZCWgbe0yAkU2OOXdoH0ENyANhyOQbs9xkAiRHcF02Q==", + "license": "MIT", + "dependencies": { + "decode-ico": "*", + "ico-endec": "*", + "sharp": "*" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/shiki": { + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-3.23.0.tgz", + "integrity": "sha512-55Dj73uq9ZXL5zyeRPzHQsK7Nbyt6Y10k5s7OjuFZGMhpp4r/rsLBH0o/0fstIzX1Lep9VxefWljK/SKCzygIA==", + "license": "MIT", + "dependencies": { + "@shikijs/core": "3.23.0", + "@shikijs/engine-javascript": "3.23.0", + "@shikijs/engine-oniguruma": "3.23.0", + "@shikijs/langs": "3.23.0", + "@shikijs/themes": "3.23.0", + "@shikijs/types": "3.23.0", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "optional": true + }, + "node_modules/simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "optional": true, + "dependencies": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/simple-swizzle": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.4.tgz", + "integrity": "sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==", + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/simple-swizzle/node_modules/is-arrayish": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.4.tgz", + "integrity": "sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==", + "license": "MIT" + }, + "node_modules/slice-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz", + "integrity": "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "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==", + "license": "MIT", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socket.io": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.0.tgz", + "integrity": "sha512-8U6BEgGjQOfGz3HHTYaC/L1GaxDCJ/KM0XTkJly0EhZ5U/du9uNEZy4ZgYzEzIqlx2CMm25CrCqr1ck899eLNA==", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "cors": "~2.8.5", + "debug": "~4.3.2", + "engine.io": "~6.6.0", + "socket.io-adapter": "~2.5.2", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/socket.io-adapter": { + "version": "2.5.7", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.7.tgz", + "integrity": "sha512-e0LyK91f3cUxTmv95/KzoLg47+zF+s/sbxRGDNsyG4dmIP8ZSX8ax6byOxfJXeNNtS/8AZlfD+uP7gBeR7DLlg==", + "license": "MIT", + "dependencies": { + "debug": "~4.4.1", + "ws": "~8.20.1" + } + }, + "node_modules/socket.io-adapter/node_modules/ws": { + "version": "8.20.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.1.tgz", + "integrity": "sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/socket.io-parser": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.6.tgz", + "integrity": "sha512-asJqbVBDsBCJx0pTqw3WfesSY0iRX+2xzWEWzrpcH7L6fLzrhyF8WPI8UaeM4YCuDfpwA/cgsdugMsmtz8EJeg==", + "license": "MIT", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.4.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socks": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.9.tgz", + "integrity": "sha512-LJhUYUvItdQ0LkJTmPeaEObWXAqFyfmP85x0tch/ez9cahmhlBBLbIqDFnvBnUJGagb0JbIQrkBs1wJ+yRYpEw==", + "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==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "socks": "^2.8.3" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/socks-proxy-agent/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==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/source-map": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">= 12" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "license": "BSD-3-Clause" + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/stop-iteration-iterator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", + "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "internal-slot": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/streamx": { + "version": "2.25.0", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.25.0.tgz", + "integrity": "sha512-0nQuG6jf1w+wddNEEXCF4nTg3LtufWINB5eFEN+5TNZW7KWJp6x87+JFL43vaAUPyCfH1wID+mNVyW6OHtFamg==", + "license": "MIT", + "dependencies": { + "events-universal": "^1.0.0", + "fast-fifo": "^1.3.2", + "text-decoder": "^1.1.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "optional": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", + "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-data-property": "^1.1.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-object-atoms": "^1.0.0", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", + "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/stringify-entities": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", + "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", + "license": "MIT", + "dependencies": { + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "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==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/style-to-js": { + "version": "1.1.21", + "resolved": "https://registry.npmjs.org/style-to-js/-/style-to-js-1.1.21.tgz", + "integrity": "sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==", + "license": "MIT", + "dependencies": { + "style-to-object": "1.0.14" + } + }, + "node_modules/style-to-object": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.14.tgz", + "integrity": "sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==", + "license": "MIT", + "dependencies": { + "inline-style-parser": "0.2.7" + } + }, + "node_modules/sucrase": { + "version": "3.34.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.34.0.tgz", + "integrity": "sha512-70/LQEZ07TEcxiU2dz51FKaE6hCTWC6vr7FOk3Gr0U60C3shtAN+H+BFr9XlYe5xqf3RA8nrc+VIwzCfnxuXJw==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "glob": "7.1.6", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/sucrase/node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tagged-tag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/tagged-tag/-/tagged-tag-1.0.0.tgz", + "integrity": "sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==", + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tailwindcss": { + "version": "3.4.17", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.17.tgz", + "integrity": "sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==", + "license": "MIT", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.6.0", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.2", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.21.6", + "lilconfig": "^3.1.3", + "micromatch": "^4.0.8", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.1.1", + "postcss": "^8.4.47", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.2", + "postcss-nested": "^6.2.0", + "postcss-selector-parser": "^6.1.2", + "resolve": "^1.22.8", + "sucrase": "^3.35.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tailwindcss/node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/tailwindcss/node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/tailwindcss/node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/tailwindcss/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/tailwindcss/node_modules/sucrase": { + "version": "3.35.1", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz", + "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "tinyglobby": "^0.2.11", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/tar": { + "version": "7.5.15", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.15.tgz", + "integrity": "sha512-dzGK0boVlC4W5QFuQN1EFSl3bIDYsk7Tj40U6eIBnK2k/8ml7TZ5agbI5j5+qnoVcAA+rNtBml8SEiLxZpNqRQ==", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.1.0", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/tar-fs": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz", + "integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/tar-fs/node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "license": "ISC", + "optional": true + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/teex": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/teex/-/teex-1.0.1.tgz", + "integrity": "sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==", + "license": "MIT", + "dependencies": { + "streamx": "^2.12.5" + } + }, + "node_modules/text-decoder": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.7.tgz", + "integrity": "sha512-vlLytXkeP4xvEq2otHeJfSQIRyWxo/oZGEbXrtEEF9Hnmrdly59sUbzZ/QgyWuLYHctCHxFF4tRQZNQ9k60ExQ==", + "license": "Apache-2.0", + "dependencies": { + "b4a": "^1.6.4" + } + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "license": "MIT", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "license": "MIT" + }, + "node_modules/tinyglobby": { + "version": "0.2.16", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", + "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "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==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/to-data-view": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/to-data-view/-/to-data-view-1.1.0.tgz", + "integrity": "sha512-1eAdufMg6mwgmlojAx3QeMnzB/BTVp7Tbndi3U7ftcT2zCZadjxkkmLmd97zmaxWi+sgGcgWrokmpEoy0Dn0vQ==", + "license": "MIT" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, + "node_modules/trim-lines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/trim-trailing-lines": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/trim-trailing-lines/-/trim-trailing-lines-2.1.0.tgz", + "integrity": "sha512-5UR5Biq4VlVOtzqkm2AZlgvSlDJtME46uV0br0gENbwN4l5+mMKT4b9gJKqWtuL2zAIqajGJGuvbCbcAJUZqBg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/trough": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", + "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "license": "Apache-2.0" + }, + "node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "license": "0BSD" + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/twoslash": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/twoslash/-/twoslash-0.3.8.tgz", + "integrity": "sha512-OeDz0kDl8sqPUN3nr7gqcvOs70f5lZsdhKYTX3/SgB9OvdadzzoYJI/4SBXhXV1HG8E9fLc+e17itoRYTxmoig==", + "license": "MIT", + "dependencies": { + "@typescript/vfs": "^1.6.4", + "twoslash-protocol": "0.3.8" + }, + "peerDependencies": { + "typescript": "^5.5.0 || ^6.0.0" + } + }, + "node_modules/twoslash-protocol": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/twoslash-protocol/-/twoslash-protocol-0.3.8.tgz", + "integrity": "sha512-HmvAHoiEviK8LqvAQyc9/irkdvwTUiR1fHmNwH/0gq8EHxyBt4PWVPixjEXg6wJu1u6yBrILEWXGK9Kw58/8yQ==", + "license": "MIT" + }, + "node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", + "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", + "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.15", + "reflect.getprototypeof": "^1.0.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", + "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0", + "reflect.getprototypeof": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typescript": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", + "license": "Apache-2.0", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/unbox-primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", + "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-bigints": "^1.0.2", + "has-symbols": "^1.1.0", + "which-boxed-primitive": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/unbzip2-stream": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", + "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", + "license": "MIT", + "dependencies": { + "buffer": "^5.2.1", + "through": "^2.3.8" + } + }, + "node_modules/undici-types": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.24.6.tgz", + "integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==", + "license": "MIT" + }, + "node_modules/unified": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", + "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-builder": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-builder/-/unist-builder-4.0.0.tgz", + "integrity": "sha512-wmRFnH+BLpZnTKpc5L7O67Kac89s9HMrtELpnNaE6TAobq5DTZZs5YaTQfAZBA9bFPECx2uVAPO31c+GVug8mg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-find-after": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-find-after/-/unist-util-find-after-5.0.0.tgz", + "integrity": "sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-is": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.1.tgz", + "integrity": "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-map/-/unist-util-map-4.0.0.tgz", + "integrity": "sha512-HJs1tpkSmRJUzj6fskQrS5oYhBYlmtcvy4SepdDEEsL04FjBrgF0Mgggvxc1/qGBGgW7hRh9+UBK1aqTEnBpIA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-modify-children": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-modify-children/-/unist-util-modify-children-4.0.0.tgz", + "integrity": "sha512-+tdN5fGNddvsQdIzUF3Xx82CU9sMM+fA0dLgR9vOmT0oPT2jH+P1nd5lSqfCfXAw+93NhcXNY2qqvTUtE4cQkw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "array-iterate": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position-from-estree": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position-from-estree/-/unist-util-position-from-estree-2.0.0.tgz", + "integrity": "sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-remove": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-remove/-/unist-util-remove-4.0.0.tgz", + "integrity": "sha512-b4gokeGId57UVRX/eVKej5gXqGlc9+trkORhFJpu9raqZkZhU0zm8Doi05+HaiBsMEIJowL+2WtQ5ItjsngPXg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-remove-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-5.0.0.tgz", + "integrity": "sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", + "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-children": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit-children/-/unist-util-visit-children-3.0.0.tgz", + "integrity": "sha512-RgmdTfSBOg04sdPcpTSD1jzoNBjt9a80/ZCzp5cI9n1qPzLZWF9YdvWGN2zmTumP1HWhXKdUWexjy/Wy/lJ7tA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", + "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/urijs": { + "version": "1.19.11", + "resolved": "https://registry.npmjs.org/urijs/-/urijs-1.19.11.tgz", + "integrity": "sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ==", + "license": "MIT" + }, + "node_modules/urlpattern-polyfill": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/urlpattern-polyfill/-/urlpattern-polyfill-10.0.0.tgz", + "integrity": "sha512-H/A06tKD7sS1O1X2SshBVeA5FLycRpjqiBeqGKmBwBDBy28EnRjORxTNe269KSSr5un5qyWi1iL61wLxpd+ZOg==", + "license": "MIT" + }, + "node_modules/use-callback-ref": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz", + "integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==", + "license": "MIT", + "peer": true, + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-callback-ref/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD", + "peer": true + }, + "node_modules/use-sidecar": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz", + "integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "detect-node-es": "^1.1.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-sidecar/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD", + "peer": true + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/utility-types": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.11.0.tgz", + "integrity": "sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.1.tgz", + "integrity": "sha512-vIYxrBCC/N/K+Js3qSN88go7kIfNPssr/hHCesKCQNAjmgvYS2oqr69kIufEG+O4+PfezOH4EbIeHCfFov8ZgQ==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/esm/bin/uuid" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vfile": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-location": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-5.0.3.tgz", + "integrity": "sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-matter": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/vfile-matter/-/vfile-matter-5.0.1.tgz", + "integrity": "sha512-o6roP82AiX0XfkyTHyRCMXgHfltUNlXSEqCIS80f+mbAyiQBE2fxtDVMtseyytGx75sihiJFo/zR6r/4LTs2Cw==", + "license": "MIT", + "dependencies": { + "vfile": "^6.0.0", + "yaml": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz", + "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/web-namespaces": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz", + "integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", + "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", + "license": "MIT", + "dependencies": { + "is-bigint": "^1.1.0", + "is-boolean-object": "^1.2.1", + "is-number-object": "^1.1.1", + "is-string": "^1.1.1", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", + "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", + "is-async-function": "^2.0.0", + "is-date-object": "^1.1.0", + "is-finalizationregistry": "^1.1.0", + "is-generator-function": "^1.0.10", + "is-regex": "^1.2.1", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.1.0", + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "license": "MIT", + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.20", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.20.tgz", + "integrity": "sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==", + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/widest-line": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-5.0.0.tgz", + "integrity": "sha512-c9bZp7b5YtRj2wOe6dlj32MK+Bx/M/d+9VB2SHM1OtsUHR0aV0tdP6DWh/iMt0kWi1t5g1Iudu6hQRNd1A4PVA==", + "license": "MIT", + "dependencies": { + "string-width": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/ws": { + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", + "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xml2js": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz", + "integrity": "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==", + "license": "MIT", + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "license": "MIT", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/xss": { + "version": "1.0.15", + "resolved": "https://registry.npmjs.org/xss/-/xss-1.0.15.tgz", + "integrity": "sha512-FVdlVVC67WOIPvfOwhoMETV72f6GbW7aOabBC3WxN/oUdoEMDyLz4OgRv5/gck2ZeNqEQu+Tb0kloovXOfpYVg==", + "license": "MIT", + "dependencies": { + "commander": "^2.20.3", + "cssfilter": "0.0.10" + }, + "bin": { + "xss": "bin/xss" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/xss/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "license": "MIT" + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/yaml": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", + "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, + "node_modules/yargs": { + "version": "17.7.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", + "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "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==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/yargs/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "license": "MIT", + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "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==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yoga-layout": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/yoga-layout/-/yoga-layout-3.2.1.tgz", + "integrity": "sha512-0LPOt3AxKqMdFBZA3HBAt/t/8vIKq7VaQYbuA8WxCgung+p9TVyKRYdpvCb80HcdTN2NkbIKbhNwKUfm3tQywQ==", + "license": "MIT" + }, + "node_modules/zod": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", + "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + } + } +} diff --git a/docs/package.json b/docs/package.json new file mode 100644 index 00000000..e7ddc6c8 --- /dev/null +++ b/docs/package.json @@ -0,0 +1,17 @@ +{ + "name": "morpheus-lumerin-node-docs", + "private": true, + "type": "module", + "scripts": { + "dev": "mint dev", + "validate": "mint broken-links", + "build:site": "node scripts/build-site.mjs", + "export:site": "node scripts/build-site.mjs" + }, + "dependencies": { + "mint": "^4.2.574" + }, + "devDependencies": { + "pagefind": "^1.3.0" + } +} diff --git a/docs/prosumers/c-node-setup.mdx b/docs/prosumers/c-node-setup.mdx new file mode 100644 index 00000000..85912201 --- /dev/null +++ b/docs/prosumers/c-node-setup.mdx @@ -0,0 +1,81 @@ +--- +title: "C-Node setup" +description: "Run the proxy-router as a long-lived consumer-side daemon (C-Node) for your prosumer environment." +audience: ["prosumer", "developer"] +product: ["proxy-router"] +last_verified: "v7.0.0" +--- + +A C-Node is the proxy-router running in the **consumer role**: it holds your wallet key, talks to BASE, and exposes a local `:8082` HTTP API for your tools (UI, CLI, agents, bots). It does **not** need to expose `:3333` to the internet — that port is only for *providers*. + +## Install path + +Pick the most appropriate install for your environment: + + + + Recommended for headless prosumer setups. + + + Build, run, and update via `git pull`. + + + Easiest if you also want the desktop UI. + + + Same headless patterns as a provider. + + + +## Minimal `.env` (consumer role) + +```bash +# BASE Mainnet +ETH_NODE_CHAIN_ID=8453 +BLOCKSCOUT_API_URL=https://base.blockscout.com/api/v2 +DIAMOND_CONTRACT_ADDRESS=0x6aBE1d282f72B474E54527D93b979A4f64d3030a +MOR_TOKEN_ADDRESS=0x7431aDa8a591C955a994a21710752EF9b882b8e3 + +ETH_NODE_ADDRESS=https://base-mainnet.g.alchemy.com/v2/ +ETH_NODE_USE_SUBSCRIPTIONS=false # https-only is more reliable for consumers + +WALLET_PRIVATE_KEY= + +WEB_ADDRESS=127.0.0.1:8082 # bind loopback only +WEB_PUBLIC_URL=http://127.0.0.1:8082 +PROXY_ADDRESS=127.0.0.1:3333 # not exposing to internet +``` + +Full reference: [Env: proxy-router](/reference/env-proxy-router). + +## Auth and `proxy.conf` + +On first start the proxy-router creates a `.cookie` with a random `admin:`. Use that for tooling (UI, CLI). To add lower-permission users (for agents or third-party tools), see [API auth](/reference/api-auth) and [Running local agents](/prosumers/running-local-agents). + +## Wallet hygiene + +- Use a **dedicated** wallet for your C-Node, not your personal MetaMask. +- Keep balances modest. Refill on a schedule rather than parking large amounts in the C-Node wallet. +- The wallet is **not** retrievable from the proxy-router state — the private key is what the proxy-router holds. + +## Approve once + +Approve the Diamond contract for some MOR allowance so opening sessions doesn't require an interactive approval each time: + +```bash +curl -X POST \ + 'http://127.0.0.1:8082/blockchain/approve?spender=0x6aBE1d282f72B474E54527D93b979A4f64d3030a&amount=20' \ + -H 'Authorization: Basic ' -d '' +``` + +This authorizes 20 MOR. Set higher if you expect heavy use; lower if you want tighter risk control. + +## Health and metrics + +- `GET /healthcheck` — JSON status / version / uptime. +- `GET /v1/models/attestation` — TEE per-model attestation state (only meaningful when using `tee`-tagged models). +- Logs — see `./data/` (or `docker logs`). + +## Updating + +For Docker: `docker pull ghcr.io/morpheusais/morpheus-lumerin-node:latest && docker restart …`. For source: `git pull && ./build.sh && systemctl restart …`. The on-disk Badger state in `./data/` is forward-compatible across patch and minor versions. diff --git a/docs/prosumers/gateway-for-everclaw.mdx b/docs/prosumers/gateway-for-everclaw.mdx new file mode 100644 index 00000000..5deb1dad --- /dev/null +++ b/docs/prosumers/gateway-for-everclaw.mdx @@ -0,0 +1,76 @@ +--- +title: "Gateway for Everclaw" +description: "Wire Everclaw / OpenClaw skills to your local C-Node so agent tools can use Morpheus inference." +audience: ["prosumer", "developer"] +product: ["proxy-router"] +last_verified: "v7.0.0" +source_url: "https://everclaw.xyz" +--- + +[Everclaw](https://everclaw.xyz) is an agent-focused project; David's "Morpheus skill" for OpenClaw lets agents call Morpheus inference via a local HTTP endpoint. You provide the endpoint by running a [C-Node](/prosumers/c-node-setup) on the same machine. + + +This page is a **mirror summary**, last verified for v7.0.0. For canonical Everclaw guidance, see [everclaw.xyz](https://everclaw.xyz). + + +## Pattern + +```mermaid +flowchart LR + EverclawSkill[Everclaw / OpenClaw skill] --> Gateway["http://127.0.0.1:8082"] + Gateway --> CRouter[C-Node proxy-router] + CRouter --> Morpheus[Morpheus providers on BASE] +``` + +The skill thinks it's calling a local OpenAI-compatible API. The C-Node handles wallets, sessions, and routing on the back end. + +## Setup steps + + + + Follow [C-Node setup](/prosumers/c-node-setup). Bind `:8082` to loopback only. + + + See "Approve once" in [C-Node setup](/prosumers/c-node-setup#approve-once). + + + Some agent skills want a stable session for the run. Open one and pass the `sessionId` to the skill via env var. + ```bash + SESSION=$(curl -s -X POST \ + 'http://127.0.0.1:8082/blockchain/models//session' \ + -H 'Authorization: Basic ' \ + -H 'Content-Type: application/json' \ + -d '{"sessionDuration": 3600}' | jq -r .sessionId) + echo $SESSION + ``` + + + Set the skill's OpenAI-base-URL to `http://127.0.0.1:8082` and inject `Authorization: Basic ` and `session_id: ` headers per request. See your skill's docs for the exact env names. + + + Run a sample task in the skill and watch the C-Node logs. You should see prompts being forwarded and the session metering correctly. + + + +## Permissions + +Run agents under a **separate `proxy.conf` user** with a method whitelist. For an Everclaw skill that only needs chat completions plus session lifecycle: + +``` +rpcauth=agent:$ +rpcwhitelist=agent:chat,open_session,close_session,get_balance +rpcwhitelistdefault=0 +``` + +See [API auth](/reference/api-auth) for the full method list. + +## Failure modes to plan for + +- **Provider unreachable** — agent should retry, then the C-Node closes the stuck session and returns the unused MOR. +- **Session expired mid-task** — agent should detect 401/403/429 from the C-Node and re-open a session. +- **Allowance exhausted** — `approve` more MOR (see C-Node setup) or set up a top-up cron. + +## Related + +- [Everclaw ecosystem mirror](/ecosystem/everclaw) — broader context, links. +- [Running local agents](/prosumers/running-local-agents) — generalized agent patterns. diff --git a/docs/prosumers/overview.mdx b/docs/prosumers/overview.mdx new file mode 100644 index 00000000..c2038341 --- /dev/null +++ b/docs/prosumers/overview.mdx @@ -0,0 +1,42 @@ +--- +title: "Prosumer overview" +description: "Run your own Consumer node (C-Node) plus a local AI gateway for agents like Everclaw, NodeNeo, or your own bots." +audience: ["prosumer"] +product: ["proxy-router", "ui-desktop", "cli"] +last_verified: "v7.0.0" +--- + +A **prosumer** sits between a casual consumer (using `app.mor.org` or MorpheusUI) and a full provider. You run your own **C-Node** (consumer-side proxy-router) and you typically host a small **AI gateway** so other tools — Everclaw skills, local agents, automation — can hit Morpheus through a single local endpoint with predictable auth. + +## Topology + +```mermaid +flowchart LR + YourBot[Your local agent / bot] --> Gateway[AI gateway 8082] + Gateway --> CRouter[Your proxy-router C-Node] + CRouter --> Network[BASE + Morpheus providers] +``` + +## Why prosumer? + +- **One stable endpoint** for all your local agents to point at — no per-tool wallet juggling. +- **Bring your own wallet** with a real budget; agents can't drain it without your permission (see [API auth](/reference/api-auth) per-user whitelists). +- **Mix local + remote** — fall back to bundled `llama.cpp` for free smoke tests; switch to remote Morpheus models for production tasks. +- **TEE on demand** — when an agent needs higher trust, route through a `tee`-tagged model. + +## What's on this path + + + + Consumer-side proxy-router with persistent local API. + + + Wire Everclaw / OpenClaw skills to your local C-Node. + + + BasicAuth + per-agent permission whitelists for safe automation. + + + `proxy.conf`, rpcauth/rpcwhitelist, multi-user setup. + + diff --git a/docs/prosumers/running-local-agents.mdx b/docs/prosumers/running-local-agents.mdx new file mode 100644 index 00000000..68de6e76 --- /dev/null +++ b/docs/prosumers/running-local-agents.mdx @@ -0,0 +1,61 @@ +--- +title: "Running local agents" +description: "Generalized patterns for running automated agents against your C-Node: per-agent users, scoped permissions, session policies." +audience: ["prosumer", "developer"] +product: ["proxy-router"] +last_verified: "v7.0.0" +--- + +The C-Node is intentionally a thin OpenAI-shaped HTTP layer over Morpheus. That makes it a clean target for any agent framework — LangChain, LlamaIndex, custom tools, OpenClaw, etc. + +## Per-agent users + +Don't share the `admin` user with agents. Add a per-agent user with a method whitelist: + +```bash +curl -X POST 'http://127.0.0.1:8082/auth/users' \ + -H 'Authorization: Basic ' \ + -H 'Content-Type: application/json' \ + -d '{ + "username": "research-agent", + "password": "rotate-me", + "methods": ["chat", "open_session", "close_session", "get_balance"] + }' +``` + +This writes a new `rpcauth=` and `rpcwhitelist=` line to `proxy.conf`. Full method list and semantics: [API auth](/reference/api-auth). + +## Session policies + +| Pattern | When to use | Notes | +|---------|-------------|-------| +| Pre-open one long session per agent run | Repeated short prompts | Lower per-prompt latency; one cleanup at end | +| Open per task | Bursty, infrequent tasks | Higher gas overhead, simpler state | +| Pool of pre-opened sessions | High-throughput multi-agent | Fan agents across sessions; close idle ones | + +Always **close sessions explicitly** when work is done. On natural expiration the consumer node submits the close itself and your full share comes back in one transaction. On manual / early close, an immediate partial refund hits your wallet plus a timelocked slice in `userStakesOnHold` (claimable via `withdrawUserStakes` after ~1 UTC day). See [Sessions: stake, close, claim](/concepts/sessions-stake-close-recover). + +## Streaming vs non-streaming + +Agents that need full deterministic JSON should use `stream: false`. Tool-calling chains that benefit from token streaming (e.g. user-facing typing UX) should set `stream: true`. The proxy-router supports both transparently — see [Chat](/consumers/chat). + +## Rate limiting + +The proxy-router does not currently expose per-user rate limits. If you need hard limits, terminate agent traffic at a reverse proxy (nginx `limit_req`, Caddy rate limiter, etc.) in front of `:8082`. + +## Observability + +- Tag each agent with its own `User-Agent` header for log filtering. +- Run a small log shipper to capture `./data/proxy-router.log` lines. +- Use `GET /v1/models/attestation` if your agents target `tee`-tagged models — surface attestation state in your dashboards. + +## Failure recovery + +| Symptom | Recovery | +|---------|----------| +| 401 / 403 from C-Node | Re-auth or rotate password | +| 429 from C-Node | Back off; check provider/model concurrency | +| Empty response stream | Provider may be down — close session, retry on a different model | +| `session not found` | Session expired or closed; open a new one | + +For a more concrete worked example, see [Gateway for Everclaw](/prosumers/gateway-for-everclaw). diff --git a/docs/providers/full/aws.mdx b/docs/providers/full/aws.mdx new file mode 100644 index 00000000..811eee0b --- /dev/null +++ b/docs/providers/full/aws.mdx @@ -0,0 +1,167 @@ +--- +title: "Provider on AWS EC2" +description: "Stand up a Morpheus provider on AWS EC2: one EC2 instance for your LLM, a second for the proxy-router." +audience: ["provider-full"] +product: ["proxy-router"] +last_verified: "v7.0.0" +source: "docs/User Compute Note Setup via AWS.md" +--- + +This guide walks through running a Morpheus provider entirely on AWS — one EC2 instance hosting an LLM via `llama.cpp`, a second EC2 instance running the proxy-router. The two-instance split is recommended for separation of concerns; you can also collapse them onto one instance for cost. + + +The original draft of this guide was written when Morpheus was testnet-only. The instructions still work; updated cross-references in this page reflect the current mainnet-default release. + + +For non-AWS alternatives, see [Docker](/providers/full/proxy-router-docker), [Akash](/providers/full/proxy-router-akash), or [SecretVM (TEE)](/providers/full/secretvm-quickstart). + +## Architecture + +```mermaid +flowchart LR + Consumer[Morpheus consumer] -->|"3333 TCP, public"| ProxyEC2[EC2 #2 proxy-router] + ProxyEC2 -->|"8080, private SG-to-SG"| ModelEC2[EC2 #1 llama.cpp] + ProxyEC2 -->|"BASE RPC"| Chain[BASE Diamond contract] +``` + +## Part 1 — LLM EC2 instance + + + + 1. Sign in to AWS and open the EC2 dashboard. + 2. **Launch instances**. + 3. Name it (e.g. `morpheus-llm`) and choose **Amazon Linux**. + 4. **Instance type — this directly determines which model you can run.** TinyLlama works on `m5.xlarge`; production models need GPU instances (`g5.xlarge`+ for 7-13B; `g5.12xlarge`+ for 70B). + 5. Pick or create a **key pair**. + 6. **Security group** — open inbound TCP `8080` (the model HTTP port) **only from the proxy-router instance's security group**, plus port `22` from your IP for SSH. Don't expose `8080` to the world. + 7. Configure **storage** generously — model weights are large (a 7B Q4_K_M GGUF is ~4 GB; a 70B model is ~40 GB). + 8. **Launch**, then **Connect → EC2 Instance Connect**. + + + ```bash + sudo yum install git -y + sudo yum install golang-go -y + sudo yum groupinstall "Development Tools" -y + ``` + + + ```bash + git clone https://github.com/ggerganov/llama.cpp.git + cd llama.cpp + make -j 8 + ``` + + + Use the EC2 instance's **public IPv4 DNS** as `model_host`. Pick a GGUF model from HuggingFace (TinyLlama is the smallest, used here for smoke-testing only — it's not a real production model). + + ```bash + model_host= + model_port=8080 + model_url=https://huggingface.co/TheBloke + model_collection=TinyLlama-1.1B-Chat-v1.0-GGUF + model_file_name=tinyllama-1.1b-chat-v1.0.Q4_K_M.gguf + + wget -O models/${model_file_name} \ + ${model_url}/${model_collection}/resolve/main/${model_file_name} + + ./llama-server -m models/${model_file_name} \ + --host 0.0.0.0 \ + --port ${model_port} \ + --n-gpu-layers 4096 + ``` + + For a real production deployment use a properly sized model and consider [vLLM](https://github.com/vllm-project/vllm) or another GPU-optimized server. See [Model setup](/providers/full/model-setup) for backend options. + + + From a browser: `http://:` should show the llama.cpp UI. From the proxy-router instance: `curl http://:/v1/chat/completions ...` should respond. + + + +## Part 2 — Proxy-router EC2 instance + + + + Same steps as above, but a small instance type is fine (`t3.small` works for the proxy-router itself). Name it (e.g. `morpheus-proxy-router`). + + **Security group** — inbound: + - TCP `3333` from `0.0.0.0/0` (this is the public consumer endpoint). + - TCP `8082` from your operator IPs only (admin/Swagger). + - TCP `22` from your IP (SSH). + + Allow this instance's SG to reach the LLM instance's SG on port `8080`. + + + ```bash + sudo yum install git -y + sudo yum install golang-go -y + sudo yum groupinstall "Development Tools" -y + ``` + + + ```bash + git clone https://github.com/MorpheusAIs/Morpheus-Lumerin-Node.git + cd Morpheus-Lumerin-Node/proxy-router + cp .env.example .env + vi .env + ``` + Set: + - `WALLET_PRIVATE_KEY` — your provider wallet's private key. + - `ETH_NODE_ADDRESS` — your BASE RPC URL (e.g. Alchemy `wss://base-mainnet.g.alchemy.com/v2/` or HTTPS). + - `WEB_ADDRESS=0.0.0.0:8082` + - `WEB_PUBLIC_URL=http://:8082` + - `PROXY_ADDRESS=0.0.0.0:3333` + + Then update [`models-config.json`](/reference/models-config) so the proxy-router routes to your LLM instance: + ```json + { + "models": [{ + "modelId": "0x", + "modelName": "tinyllama", + "apiType": "openai", + "apiUrl": "http://:8080/v1/chat/completions" + }] + } + ``` + + Full env reference: [Env: proxy-router](/reference/env-proxy-router). + + + ```bash + ./build.sh + make run + ``` + Logs should show: + ``` + INFO proxy state: running + INFO HTTP http server is listening: 0.0.0.0:8082 + INFO TCP tcp server is listening: 0.0.0.0:3333 + ``` + For long-lived operation, run it under `systemd` — see [Headless operation](/providers/full/headless). + + + Open `http:///swagger/index.html` to confirm the API is up. + + + +## Part 3 — Register on chain + +Now register your provider, model, and bid following [Register on chain](/providers/full/register-onchain). The provider `endpoint` you set there must be reachable from the public internet on `:3333` — i.e. `:3333`. + +## Operational notes + +- **Costs.** Production providers usually pair a GPU instance (`g5.*`, `g6.*`) for the LLM with a small `t3.*` for the proxy-router. Watch egress charges — heavy session traffic adds up. +- **Public IP stability.** EC2 public DNS changes when an instance stops/starts. Use an **Elastic IP** on the proxy-router instance, or a stable DNS name (Route 53), so your registered provider `endpoint` keeps working across reboots. +- **Security groups.** Never expose port `8080` (LLM) or `8082` (admin API) to `0.0.0.0/0`. Only `3333` is meant to be public. +- **TLS for `:8082`.** Put a reverse proxy (nginx, Caddy, ALB) in front of `:8082` if operators need to reach it from outside the VPC. See [Headless operation](/providers/full/headless). + +## TEE (optional) + +For a TEE-attested provider, AWS EC2 alone is not enough — you need a confidential VM (Intel TDX or AMD SEV-SNP) and a hardened image. Use [SecretVM](/providers/full/secretvm-quickstart) instead of bare EC2. + +## Related + +- [Docker provider](/providers/full/proxy-router-docker) +- [Akash provider](/providers/full/proxy-router-akash) +- [SecretVM TEE provider](/providers/full/secretvm-quickstart) +- [Headless operation](/providers/full/headless) +- [Register on chain](/providers/full/register-onchain) diff --git a/docs/providers/full/headless.mdx b/docs/providers/full/headless.mdx new file mode 100644 index 00000000..2255fc50 --- /dev/null +++ b/docs/providers/full/headless.mdx @@ -0,0 +1,84 @@ +--- +title: "Headless provider operation" +description: "Run a Morpheus provider with no GUI: just the proxy-router binary plus its API." +audience: ["provider-full", "developer"] +product: ["proxy-router"] +last_verified: "v7.0.0" +--- + +A "headless" provider is the proxy-router binary running as a long-lived service — no MorpheusUI, no human at a keyboard. This is the typical production deployment. + +## Topology + +```mermaid +flowchart LR + Internet[Consumers on Internet] -->|"3333 TCP"| Provider[Provider proxy-router] + Provider -->|"private"| Model[Backend LLM] + Admin[Operator host] -->|"8082 HTTPS, BasicAuth"| Provider +``` + +- **`:3333` (TCP)** — public. Consumers connect here. +- **`:8082` (HTTP)** — should be **firewalled to operator IPs only**, ideally behind a reverse proxy with TLS. Used for Swagger, blockchain admin, and the auth APIs. +- **Backend LLM** — private network only. + +## Service supervision + + + + Create `/etc/systemd/system/morpheus-proxy-router.service`: + ```ini + [Unit] + Description=Morpheus Lumerin proxy-router + After=network-online.target + Wants=network-online.target + + [Service] + User=morpheus + WorkingDirectory=/opt/morpheus + EnvironmentFile=/opt/morpheus/.env + ExecStart=/opt/morpheus/proxy-router + Restart=on-failure + RestartSec=5 + LimitNOFILE=65536 + + [Install] + WantedBy=multi-user.target + ``` + ```bash + sudo systemctl enable --now morpheus-proxy-router + sudo journalctl -u morpheus-proxy-router -f + ``` + + + See [Docker provider](/providers/full/proxy-router-docker) and use the published `ghcr.io/morpheusais/morpheus-lumerin-node:latest` image with `restart: unless-stopped`. + + + For TEE-hardened headless operation, use SecretVM — see [SecretVM quickstart](/providers/full/secretvm-quickstart). The container is automatically supervised by the VM. + + + +## API auth + +Set strong credentials in the `.cookie` file (or `COOKIE_CONTENT` env in TEE/Akash deployments). For multi-user access (e.g. `agent` accounts with restricted whitelists), see [API auth](/reference/api-auth). + +## Logging & observability + +- Container logs (`docker logs`) or `journalctl` for systemd. Set `ENVIRONMENT=production` and `LOG_JSON=true` for structured logs in production. +- The `./data/` directory persists Badger state and runtime files — back this up. +- `GET /healthcheck` for liveness; `GET /v1/models/attestation` for TEE per-model state. + +## Wallet hygiene + +- Use a **dedicated provider wallet**, never the same key as your personal MetaMask. +- Rotate periodically: register a new provider record with the new key and decommission the old one. +- For TEE deployments the key is encrypted into the enclave secrets; for non-TEE keep the key inside `.env` with strict file permissions (`chmod 600`). + +## Updating + +When a new release ships: + +1. Stop the service. +2. Replace the binary or image tag. +3. Start the service. +4. Confirm `/healthcheck` and Swagger respond. Confirm the proxy-router log shows the expected version. +5. (TEE) Update the deployed compose with the new digest and re-verify attestation. diff --git a/docs/providers/full/model-setup.mdx b/docs/providers/full/model-setup.mdx new file mode 100644 index 00000000..d908ea5e --- /dev/null +++ b/docs/providers/full/model-setup.mdx @@ -0,0 +1,52 @@ +--- +title: "Model setup (backend LLM)" +description: "Stand up the actual AI model that your provider proxy-router will route prompts to." +audience: ["provider-full", "developer"] +product: ["proxy-router"] +last_verified: "v7.0.0" +source: "docs/01-model-setup.md" +--- + +The Morpheus proxy-router does **not** run inference itself. It forwards prompts to whatever OpenAI-compatible HTTP endpoint you point it at via [`models-config.json`](/reference/models-config). That endpoint is your "backend LLM" or "model server." + + +This page is intentionally short. Picking, sizing, and operating an inference engine is its own discipline; we link to the canonical references rather than maintaining our own. + + +## Common backends + + + + Single-binary CPU/GPU inference. Bundled in our local-only demo. + + + Production-grade GPU serving with continuous batching. + + + Easy local model server, `OpenAI`-compatible. + + + Front Venice / OpenAI / Anthropic via `apiUrl` + `apiKey` in `models-config.json`. See [Resale provider](/providers/resale/overview). + + + +## What the proxy-router needs from your backend + +- **OpenAI-compatible** route appropriate for the model type: + - LLM: `/v1/chat/completions` + - Embeddings: `/v1/embeddings` + - STT: `/v1/audio/transcriptions` + - TTS: `/v1/audio/speech` +- A **stable, private URL** the proxy-router can reach (e.g. `http://10.0.0.5:8080/v1/chat/completions`). +- Enough **concurrency** to satisfy the `concurrentSlots` you advertise in `models-config.json`. + +## Capacity recommendations + +There is no one-size-fits-all sizing — start by measuring on your own hardware. The [`tech.mor.org` calculators](https://tech.mor.org) help estimate revenue and tokens-per-second across hardware tiers; mirror summary at [tech.mor.org (mirror)](/ecosystem/tech-mor-org). + +## TEE backends + +For full Phase 2 attestation, the backend itself must run inside a SecretVM-style TEE that exposes attestation endpoints on `:29343` (`/cpu`, `/gpu`, `/docker-compose`). See: +- [TEE overview](/concepts/tee-overview) +- [TEE reference](/providers/full/tee-reference) +- Backend-side developer notes: [`proxy-router/docs/tee-backend-verification.md`](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/blob/main/proxy-router/docs/tee-backend-verification.md) diff --git a/docs/providers/full/myprovider-gui.mdx b/docs/providers/full/myprovider-gui.mdx new file mode 100644 index 00000000..01283979 --- /dev/null +++ b/docs/providers/full/myprovider-gui.mdx @@ -0,0 +1,41 @@ +--- +title: "MyProvider GUI" +description: "Use myprovider.mor.org's hosted operator dashboard to manage a Morpheus provider node." +audience: ["provider-full", "provider-resale"] +product: ["proxy-router"] +last_verified: "v7.0.0" +source_url: "https://myprovider.mor.org" +--- + +[MyProvider](https://myprovider.mor.org) is a hosted operator GUI maintained by the Morpheus ecosystem. It lets you manage providers, models, bids, and sessions without scripting against the API directly. + + +This page is a **mirror summary** of public information about MyProvider, last verified for v7.0.0. For canonical, current behavior, always defer to [myprovider.mor.org](https://myprovider.mor.org). + + +## What it gives you + +- **Provider dashboard** — register/update your provider record, view stake, status, and earnings. +- **Model management** — register, tag (including `tee`), and update models. +- **Bid management** — post, edit, and retire bids. +- **Session monitoring** — see active and historical sessions, pending claims, and earnings. +- **Health pings** — quick visibility into whether your `:3333` and `/healthcheck` are reachable. + +## When to use it vs the Swagger / API + +| Task | Best surface | +|------|--------------| +| First-time provider registration | MyProvider GUI or Swagger | +| Update bids in bulk | API/script | +| TEE attestation inspection | [SecretVM portal](https://secretai.scrtlabs.com/attestation) + cosign | +| Day-to-day operator monitoring | MyProvider GUI | +| Programmatic automation | API ([endpoints reference](/reference/api-endpoints)) | + +## Authentication + +MyProvider authenticates against your provider's wallet — connect a wallet that owns the provider record on chain. Read the privacy and TOS on the site directly before connecting any wallet you care about. + +## Related + +- [Register on chain](/providers/full/register-onchain) — the underlying contract calls MyProvider wraps. +- [API endpoints](/reference/api-endpoints) — direct API equivalents. diff --git a/docs/providers/full/pricing.mdx b/docs/providers/full/pricing.mdx new file mode 100644 index 00000000..773e215e --- /dev/null +++ b/docs/providers/full/pricing.mdx @@ -0,0 +1,102 @@ +--- +title: "Pricing your bid" +description: "How to set pricePerSecond for a Morpheus provider bid: there is no marketplace 'helper' or order book — you estimate cost, set a competitive rate, and adjust." +audience: ["provider-full", "provider-resale"] +product: ["proxy-router"] +last_verified: "v7.0.0" +--- + +There is **no built-in pricing helper, no order book, and no "always use market price" toggle** for provider bids today. You set `pricePerSecond` (in **wei/sec** of MOR) when you call `postModelBid`, and you adjust it by replacing the bid. This page is the explicit how-to for that workflow. + + +This page is for the **provider** side — pricing for the on-chain bid. Pricing for **consumers** of the [hosted Inference API](/inference-api/overview) is a different layer (per-token billing on top of the marketplace) and is documented at [apidocs.mor.org](https://apidocs.mor.org). + + +## Units and floors + +- `pricePerSecond` is denominated in **wei of MOR** (1 MOR = 10^18 wei). +- Floor: `bidPricePerSecondMin = 10000000000` wei/sec = `0.00000001` MOR/sec ≈ `0.0006` MOR/min ≈ `0.036` MOR/hour at the floor. +- There is no upper limit, but rating algorithms and competing bids will push consumers away from over-priced bids. + +## Step 1 — Look at competing bids + +The cheapest reference is the live snapshot of bids the network is actually accepting: + +```bash +curl -sS https://active.mor.org/active_bids.json | jq +``` + +Filter by your model (or one similar in size and capability): + +```bash +curl -sS https://active.mor.org/active_bids.json \ + | jq '[.[] | select(.modelName == "your-model-name")] | sort_by(.pricePerSecond)' +``` + +Look at the distribution. **Median competitor pricing** is a sane starting point. + +## Step 2 — Estimate your cost floor + +``` +your_$/sec ≈ amortised_hardware_$/month + ÷ utilised_seconds_per_month + + amortised_electricity_$/sec + + amortised_bandwidth_$/sec + + your_target_margin +``` + +Rough sanity check: + +- A `g5.xlarge` on demand on AWS is roughly `$1.00 / hour` ≈ `$0.000278/sec` (a real provider would use spot or self-host, but this is a high bound). +- If `1 MOR ≈ $X` (look up live), then `1 MOR/sec ≈ $X/sec`. Convert your `$/sec` into `MOR/sec` via that rate. +- Convert to wei: `pricePerSecond_wei = MOR_per_second × 10^18`. + +For a resale provider, replace hardware cost with **upstream API cost** — e.g. Venice subscription `$X/month` divided by your expected utilised seconds. See [Resale registering-bid](/providers/resale/registering-bid) for the resale math. + +## Step 3 — Pick a number, post the bid + +```bash +curl -X POST 'http://localhost:8082/blockchain/bids' \ + -H 'Authorization: Basic ' \ + -H 'Content-Type: application/json' \ + -d '{ + "modelID": "0xYOUR_MODELID", + "pricePerSecond": "10000000000" + }' +``` + +The contract reverts if `pricePerSecond` is below the floor. + +## Step 4 — Watch and adjust + +There is no auto-adjust. To change a price you **delete the old bid and post a new one**. Both calls cost gas; the **`postModelBid`** call **also charges a non-refundable `marketplaceBidFee` of `0.3 MOR`** every time (see "How bid posts cost MOR" below). Don't repost more often than you have to. + +Things to watch: + +- **Bid acceptance rate**. If you get zero sessions over days while competitors with similar specs do, you're priced too high. +- **Provider reputation signals**. Even at the right price, low uptime / poor TTFT / failed sessions tank your match rate. See the [reputation system](/concepts/architecture#reputation-and-provider-selection). +- **Active rate from `active_bids.json`**. If your bid disappears from the snapshot, your `:3333` is no longer reachable to the verifier — see [verify-setup](/providers/full/verify-setup). + +## How bid posts cost MOR + +Every time you call `postModelBid`, the marketplace charges a non-refundable **`marketplaceBidFee = 0.3 MOR`** ([`Marketplace.sol`](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/blob/main/smart-contracts/contracts/diamond/facets/Marketplace.sol)). This fee is **separate from**, and on top of: + +- the refundable **provider stake** (`0.2` MOR) you posted at registration, +- the refundable **model stake** (`0.1` MOR) you posted when registering the model, +- BASE gas (paid in ETH on BASE). + +If you post → tweak → post → tweak → … six times during configuration, you've paid `~1.8 MOR` in non-refundable bid fees, plus gas. That's the most common reason new providers see "I lost ~2 MOR during setup": **it wasn't slashed, it was bid fees**. See also [Quickstart → "What can cost you MOR during setup"](/providers/full/quickstart#what-can-cost-you-mor-during-setup). + +## What about "stake-for-liquidity" rewards? + +That's a **different product** — the Capital Contract / stake-for-liquidity program documented at [mor.org](https://mor.org). It is **not** the same as provider session payouts and is unrelated to your bid pricing decisions. Your provider stake bonded at registration is **not** the same as staking in the Capital Contract. See [Tokens and fees](/concepts/tokens-and-fees) for the distinction. + +## What you can't do today + +The chat history surfaces a few asks that **do not have a solution yet**: + +- ❌ "Always use market price" toggle. You set the rate manually. +- ❌ Token-level pricing (input vs output, context size). Provider-side pricing is `wei/sec` only. +- ❌ Built-in pricing recommender. Use `active_bids.json` and your own cost model. + +If/when these land, this page is where it'll be documented. diff --git a/docs/providers/full/proxy-router-akash.mdx b/docs/providers/full/proxy-router-akash.mdx new file mode 100644 index 00000000..35dca14a --- /dev/null +++ b/docs/providers/full/proxy-router-akash.mdx @@ -0,0 +1,65 @@ +--- +title: "Proxy-router on Akash" +description: "Deploy the proxy-router on Akash Network for decentralized hosting. API-only access; no GUI or wallet components included." +audience: ["provider-full", "developer"] +product: ["proxy-router"] +last_verified: "v7.0.0" +source: "docs/02.2-proxy-router-akash.md" +--- + +This guide covers deploying the proxy-router on Akash Network. The deployment provides API access via Swagger interface — no GUI or wallet components. + +## Pre-requisites + +- AI model reachable on a private endpoint (e.g. `http://model.example:8080`). +- Funded wallet (MOR + ETH on BASE) and its private key. +- Akash account with deployment experience. + + +The final endpoint URL is only available **after** provider selection and Akash deployment. + + +## Configuration model + +Unlike a typical Docker run, on Akash the proxy-router uses **environment variables instead of volume mounts** for improved reliability: + +| Variable | Purpose | +|----------|---------| +| `COOKIE_CONTENT` | API authentication: `username:password` | +| `MODELS_CONFIG_CONTENT` | Single-line JSON for model endpoints (see [models-config](/reference/models-config)) | +| `WALLET_PRIVATE_KEY` | For blockchain interactions | +| Plus chain ID, contract addresses, etc. | See [Env: proxy-router](/reference/env-proxy-router) | + +## Deployment + + + + Download and customize [`docs/02.2-proxy-router-akash.yml`](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/blob/main/docs/02.2-proxy-router-akash.yml). Minimum proxy-router image version: `v2.3.0` (use a newer release tag for current features). + Configure: + - Wallet private key + - API credentials (`COOKIE_CONTENT`) + - `MODELS_CONFIG_CONTENT` (single-line JSON) + + Save securely — the SDL contains sensitive data. + + + In the Akash Dashboard: **Deploy → Custom Container**. Upload your SDL. Select a provider and deploy. Verify status and logs. + + + Update `WEB_PUBLIC_URL` with the provider URL and port. Note both API port (`8082`) and proxy-router port (`3333`). Format: `http://provider.example:port`. + + + Open `http://provider.example:port/swagger/index.html`. Authenticate with your `COOKIE_CONTENT` credentials. Update the provider endpoint via `POST /blockchain/providers`: + ```json + { + "endpoint": "provider.example:proxy_port", + "stake": "123000000000" + } + ``` + Verify with `GET /blockchain/providers`. Continue with model + bid registration in [Register on chain](/providers/full/register-onchain). + + + +## Sample logs + +A successful Akash startup looks like the screenshot at [`docs/images/akash_good_start.png`](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/blob/main/docs/images/akash_good_start.png). diff --git a/docs/providers/full/proxy-router-docker.mdx b/docs/providers/full/proxy-router-docker.mdx new file mode 100644 index 00000000..d27d84a4 --- /dev/null +++ b/docs/providers/full/proxy-router-docker.mdx @@ -0,0 +1,132 @@ +--- +title: "Proxy-router on Docker" +description: "Run the proxy-router as a Docker container. API access via Swagger; no GUI or wallet components included." +audience: ["provider-full", "developer"] +product: ["proxy-router"] +last_verified: "v7.0.0" +source: "docs/02.1-proxy-router-docker.md" +--- + +The proxy-router is a critical component that monitors the BASE blockchain and manages models, providers, and sessions. It's a standalone application that runs anywhere with access to your blockchain node and AI model. + +## Published image + +The official image is on GHCR: `ghcr.io/morpheusais/morpheus-lumerin-node:latest`. Built per release from the main branch. Browse: [MorpheusAIs Packages](https://github.com/orgs/MorpheusAIs/packages?repo_name=Morpheus-Lumerin-Node). + +For TEE-hardened images (`-tee` suffix), see [SecretVM quickstart](/providers/full/secretvm-quickstart) and [TEE reference](/providers/full/tee-reference). + +## Pre-requisites + +- AI model reachable on a private endpoint (e.g. `http://my-model.example:8080`). +- Funded wallet (MOR + ETH on BASE) and its private key. +- Public endpoint for the provider (`host:port`, no protocol), e.g. `mycoolmornode.example:3333`. + +## Volume + env layout + +Mount a host directory into `/app/data` so these files persist: + +| File | Purpose | +|------|---------| +| `proxy-router.env` | Per-[Env reference](/reference/env-proxy-router) | +| `.cookie` | Auto-generated admin credentials | +| `proxy.conf` | API user/permission whitelist | +| `models-config.json` | Models served (see [reference](/reference/models-config)) | +| `rating-config.json` | Provider rating ([reference](/reference/rating-config)) | + +Map `-p` for the proxy port (`3333`) and admin/API port (`8082`). + +## Run with .env file + +Minimal `proxy-router.env` (mainnet): + +```bash +AUTH_CONFIG_FILE_PATH=/app/data/proxy.conf +COOKIE_FILE_PATH=/app/data/.cookie +RATING_CONFIG_PATH=/app/data/rating-config.json +PROXY_STORAGE_PATH=/app/data/data +MODELS_CONFIG_PATH=/app/data/models-config.json +ETH_NODE_CHAIN_ID=8453 +BLOCKSCOUT_API_URL=https://base.blockscout.com/api/v2 +DIAMOND_CONTRACT_ADDRESS=0x6aBE1d282f72B474E54527D93b979A4f64d3030a +MOR_TOKEN_ADDRESS=0x7431aDa8a591C955a994a21710752EF9b882b8e3 +WALLET_PRIVATE_KEY= +# REQUIRED for any real deployment. The proxy-router has a built-in public RPC +# round-robin fallback, but it is rate-limited and unreliable; running without +# your own ETH_NODE_ADDRESS leads to silent missed events. +ETH_NODE_ADDRESS= +ETH_NODE_USE_SUBSCRIPTIONS=false +PROXY_ADDRESS=0.0.0.0:3333 +WEB_ADDRESS=0.0.0.0:8082 +WEB_PUBLIC_URL=https://your-public-host.example +``` + +Run: + +```bash +docker run -d \ + --env-file proxy-router.env \ + -v /path/to/local/data:/app/data \ + -p 3333:3333 \ + -p 8082:8082 \ + ghcr.io/morpheusais/morpheus-lumerin-node:latest +``` + +## Run with command-line variables + +```bash +docker run -d \ + -e AUTH_CONFIG_FILE_PATH=/app/data/proxy.conf \ + -e COOKIE_FILE_PATH=/app/data/.cookie \ + -e RATING_CONFIG_PATH=/app/data/rating-config.json \ + -e PROXY_STORAGE_PATH=/app/data/data \ + -e MODELS_CONFIG_PATH=/app/data/models-config.json \ + -e ETH_NODE_CHAIN_ID=8453 \ + -e BLOCKSCOUT_API_URL=https://base.blockscout.com/api/v2 \ + -e DIAMOND_CONTRACT_ADDRESS=0x6aBE1d282f72B474E54527D93b979A4f64d3030a \ + -e MOR_TOKEN_ADDRESS=0x7431aDa8a591C955a994a21710752EF9b882b8e3 \ + -e WALLET_PRIVATE_KEY= \ + -e ETH_NODE_ADDRESS=https://base-mainnet.g.alchemy.com/v2/ \ + -e ETH_NODE_USE_SUBSCRIPTIONS=false \ + -e PROXY_ADDRESS=0.0.0.0:3333 \ + -e WEB_ADDRESS=0.0.0.0:8082 \ + -e WEB_PUBLIC_URL=https://your-public-host.example \ + -v /path/to/local/data:/app/data \ + -p 3333:3333 \ + -p 8082:8082 \ + ghcr.io/morpheusais/morpheus-lumerin-node:latest +``` + + +**Set `ETH_NODE_ADDRESS` explicitly.** The proxy-router has a built-in public RPC round-robin fallback. It exists for first-run sanity checks only — for any real provider it is rate-limited and unreliable, and missing blockchain events will silently break your node. + + +## Manual build + +If you want to customize, build locally: + +```bash +git clone -b main https://github.com/MorpheusAIs/Morpheus-Lumerin-Node.git +cd Morpheus-Lumerin-Node/proxy-router + +# Copy and edit configs +cp .env.example .env # or .env.example.win on Windows +vi .env +cp models-config.json.example models-config.json +vi models-config.json +cp rating-config.json.example rating-config.json +vi rating-config.json + +# Build and run +./docker_build.sh --build +./docker_build.sh --run +``` + +## Validate & register + +- `http://localhost:8082/swagger/index.html` should render. +- Continue to [Register on chain](/providers/full/register-onchain). + +## Notes + +- We provide `docker-compose.yml`, `Dockerfile`, and `docker_build.sh` as templates — adapt them for your private key, ETH node, ports, volumes, and config files. +- Reference docs: [Env: proxy-router](/reference/env-proxy-router), [models-config.json](/reference/models-config), [rating-config.json](/reference/rating-config). diff --git a/docs/providers/full/quickstart.mdx b/docs/providers/full/quickstart.mdx new file mode 100644 index 00000000..6ee951e6 --- /dev/null +++ b/docs/providers/full/quickstart.mdx @@ -0,0 +1,134 @@ +--- +title: "Full P-Node quickstart" +description: "Run a standalone Morpheus provider proxy-router pointing at your own AI model." +audience: ["provider-full"] +product: ["proxy-router"] +last_verified: "v7.0.0" +source: "docs/02-provider-setup.md" +--- + +This page covers a **non-TEE provider** running on your own infrastructure. For TEE-hardened deployment on SecretVM, see [SecretVM quickstart](/providers/full/secretvm-quickstart). Hosted alternatives: [Docker](/providers/full/proxy-router-docker), [AWS EC2](/providers/full/aws), or [Akash](/providers/full/proxy-router-akash). + +## Assumptions + +- Your AI model is configured, started, and reachable from the proxy-router host on a private endpoint (e.g. `http://my-model.example:8080`). Use the bundled `llama.cpp` + `tinyllama` for testing — adjust `models-config.json` if your local port differs. +- You have a funded wallet on BASE (MOR + ETH) and the **private key** for `.env`. +- You have your **own** ETH node URL — Alchemy or Infura private API key for BASE works (`wss://base-mainnet.g.alchemy.com/v2/` or HTTPS). The proxy-router has a built-in round-robin of public RPC endpoints as a fallback, but it is rate-limited and unreliable in practice; running a real provider on it leads to silent missed events. Set `ETH_NODE_ADDRESS` explicitly. +- Your proxy-router has a **publicly accessible endpoint** for the provider (`host:port`, no protocol), e.g. `mycoolmornode.example:3333`. + +## Install & configure + + + + + + Download the latest release for your OS from [Releases](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/releases). Mainnet builds have no suffix; testnet builds end in `-test`. + + + ```bash + git clone -b main https://github.com/MorpheusAIs/Morpheus-Lumerin-Node.git + cd Morpheus-Lumerin-Node/proxy-router + ./build.sh + ``` + + + + + + + ```bash + cd ~/Downloads/morpheus + xattr -c proxy-router + ``` + + + ```bash + cd ~/Downloads/morpheus + ``` + + + Extract to `%USERPROFILE%\Downloads\morpheus`. + + + + + Linux/macOS: rename `env.example` to `.env`. Windows: rename `env.example.win` to `.env`. Edit at minimum: + - `WALLET_PRIVATE_KEY=` — provider's private key. + - `ETH_NODE_ADDRESS=` — **required for any real deployment.** The bundled minimal example does not set this; without it the node falls back to a built-in public RPC round-robin that is rate-limited and unreliable. Use your own Alchemy / Infura HTTPS or WSS URL. Match `ETH_NODE_USE_SUBSCRIPTIONS` accordingly (`true` for WSS, `false` for HTTPS — recommended HTTPS + `false`). + - Choose **mainnet** (default) or testnet — uncomment the testnet block, comment mainnet, save. + + Full reference: [Env: proxy-router](/reference/env-proxy-router) (see "Conflicting / overlapping variables" up top). + + + To resell or front another LLM, set `MODELS_CONFIG_PATH=` in `.env` and add the entry to `models-config.json`: + ```json + { + "modelId": "", + "modelName": "your-model-name", + "apiType": "openai", + "apiUrl": "https://api.example.com/v1/chat/completions", + "apiKey": "..." + } + ``` + Full schema: [models-config.json](/reference/models-config). Restart after edits. + + + Edit `rating-config.json` to bias selection or restrict to specific providers: + ```json + { + "algorithm": "default", + "providerAllowlist": [], + "params": { + "weights": { "tps": 0.24, "ttft": 0.08, "duration": 0.24, "success": 0.32, "stake": 0.12 } + } + } + ``` + Weights must sum to 1. Reference: [rating-config.json](/reference/rating-config). + + + +## Start + + + + ```bash + ./proxy-router + ``` + + + Double-click `proxy-router.exe`. Allow Defender if prompted. + + + +## Validate + +- `http://localhost:8082/swagger/index.html` should render. +- `./data/` directory contains logs. +- The proxy-router log should include: + ``` + INFO proxy state: running + INFO HTTP http server is listening: 0.0.0.0:8082 + INFO TCP tcp server is listening: 0.0.0.0:3333 + ``` + +## Next: register on chain + +Once running, register your provider, your model (with the `tee` tag if you've TEE-hardened), and your bid. See [Register on chain](/providers/full/register-onchain), then run the [self-checks in Verify your provider setup](/providers/full/verify-setup) before declaring victory. + +## What can cost you MOR during setup + +A few things will quietly draw down your MOR balance during initial configuration. None of them are slashing or forfeiture; they are normal protocol fees and stakes. Knowing them upfront prevents the "I lost ~2 MOR during setup, what happened?" support ticket. + +| Event | Cost | Refundable? | +|-------|------|-------------| +| Register provider (`providerRegister`) | `0.2 MOR` (or `10000 MOR` for subnet) | **Yes**, on `providerDeregister` (after deregistration cooldown opens) | +| Register model (`modelRegister`) | `0.1 MOR` | **Yes**, on `modelDeregister` (model must have no active bids) | +| **Post a bid** (`postModelBid`) | **`0.3 MOR` non-refundable `marketplaceBidFee`** | **No** — every bid post charges this fee | +| BASE gas | a few cents in ETH-on-BASE per tx | No (standard gas) | +| Sessions consumed before your node was actually serving | Possibly small — see "Disputed early closes" in [Sessions: stake, close, claim](/concepts/sessions-stake-close-recover) | n/a | + +The most common pattern: a new provider posts a bid, tweaks their setup, **deletes and reposts the bid** several times. Each repost charges `0.3 MOR`. Six iterations is `~1.8 MOR` gone before the node is even serving traffic. + +**Mitigation:** finish your model and `models-config.json` setup, run [verify-setup steps 1-4](/providers/full/verify-setup) **before** posting your first bid. Repost only when pricing actually needs to change. + +For details on bid pricing and how to change a price, see [Pricing](/providers/full/pricing). diff --git a/docs/providers/full/register-onchain.mdx b/docs/providers/full/register-onchain.mdx new file mode 100644 index 00000000..17258d0a --- /dev/null +++ b/docs/providers/full/register-onchain.mdx @@ -0,0 +1,130 @@ +--- +title: "Register on chain (provider, model, bid)" +description: "Approve the Diamond contract, register your provider, register your model (with optional tee tag), and post a bid." +audience: ["provider-full", "provider-resale"] +product: ["proxy-router"] +last_verified: "v7.0.0" +source: "docs/03-provider-offer.md" +--- + +After your proxy-router is running, register your provider, model, and bid on the BASE Diamond contract. All steps go through your local Swagger UI at `http://localhost:8082/swagger/index.html`. + +## Contract minimums + +| Item | Value (wei) | Display | +|------|-------------|---------| +| `providerMinStake` | `200000000000000000` | `0.2` MOR | +| `modelMinStake` | `100000000000000000` | `0.1` MOR | +| `marketplaceBidFee` | `300000000000000000` | `0.3` MOR | +| `bidPricePerSecondMin` | `10000000000` | `0.00000001` MOR/sec | + +## What you'll need + +| Item | Example | +|------|---------| +| Provider wallet | `0x9E26Fea97F7d644BAf62d0e20e4d4b8F836C166c` | +| Public endpoint | `server.example.com:3333` | +| Random `modelId` (32-byte hex) | `0xe1e6e3e77148d140065ef2cd4fba7f4ae59c90e1639184b6df5c84` | +| `ipfsCID` (32-byte hex) | `0xc2d3a5e4f9b7c1a2c8f0b1d5e6c78492fa7bcd34e9a3b9c9e18f25d3be47a1f6` | +| Model name | `CapybaraHermes-v2.5-Mistral-7b` | +| Bid `pricePerSecond` | `10000000000` (`0.00000001` MOR) | + +## Steps + + + + `POST /blockchain/approve` — set `spender = ` and `amount` ≥ `0.6` MOR (in wei: `600000000000000000`) to cover provider stake + model stake + bid fee. + + + `POST /blockchain/providers` — set `addStake` (≥ `0.2` MOR; `10000` MOR for a subnet provider) and `endpoint` (your **publicly accessible** `host:port`, no protocol). + + + `POST /ipfs/add` — capture the returned `Hash` (this is your `ipfsCID`). Then `POST /ipfs/pin` with the same hash to keep it pinned. + + + `POST /blockchain/models` with: + - `modelId`: random 32-byte hex (becomes the on-chain id paired with your providerId). + - `ipfsCID`: from the previous step. + - `Fee`: model fee. + - `addStake`: `0.1` MOR minimum. + - `Owner`: your provider wallet. + - `name`: human-readable model name. + - `tags`: array of strings. + - **TEE providers must include `"tee"` (case-insensitive)** to opt the model into the two-hop attestation chain. + - Other common tags: `llm`, `embedding`, `stt`, `tts`. + + Capture the `modelID` from the JSON response — this combines your requested modelId with your providerId and is required for `models-config.json` and bids. + + + Add the new on-chain `modelID` (the combined value) to your `models-config.json` and restart the proxy-router. See [models-config.json](/reference/models-config). + + + `POST /blockchain/bids` with `modelID` and `pricePerSecond` (≥ `10000000000`). Capture the returned `bidID`. + + + +## TEE tag deeper context + +Tagging the model `tee` engages two independent verifications on every session and prompt — one each side: + +- **Phase 1 (consumer → your P-Node).** Any v6.0.0+ consumer proxy-router will verify your P-Node's TDX attestation (CPU quote, TLS pinning, RTMR3 of the `-tee` image) at session open and on every prompt before forwarding inference. +- **Phase 2 (your P-Node → backend).** Your v7.0.0+ P-Node will verify the backend LLM your model's `apiUrl` points to — CPU TDX quote, TLS pinning, RTMR3 replay of the backend's `docker-compose.yaml`, CPU-GPU nonce binding, and NVIDIA NRAS GPU attestation — at startup and on every prompt. + +A v6+ consumer benefits from Phase 2 automatically by trusting your attested v7+ P-Node — no client-side upgrade needed. Models without the `tee` tag are treated as standard providers; neither hop runs. + +See [TEE overview](/concepts/tee-overview) and [TEE reference](/providers/full/tee-reference). + +## Where things show up afterward + +- Your provider on chain: `GET /blockchain/providers` +- Your model on chain: `GET /blockchain/models` +- Your bids on chain: `GET /blockchain/bids` +- Live network listings: [active.mor.org](https://active.mor.org) +- Operator dashboard: [myprovider.mor.org](/providers/full/myprovider-gui) + +## Choosing a `modelId` (community convention) + +The contract does **not enforce uniqueness** of model names. You can register a `modelId` with the same name and `ipfsCID` as an existing model — the marketplace will simply have multiple entries pointing at the same logical model. As a result, snapshots like [active.mor.org/active_models.json](https://active.mor.org/active_models.json) often show many entries for popular names with one provider each. + +Recommended practice: + +- **Reuse an existing `modelId`** when you're hosting the same logical model someone else has already registered. This keeps the marketplace clean, gives consumers a single dropdown entry with multiple providers (good for failover and competitive pricing), and avoids fragmenting reputation data. +- **Mint a new `modelId`** only when your model is genuinely different (different weights, different fine-tune, different `ipfsCID`). + +This is convention, not enforcement. Practical workflow: + +```bash +# Look up existing IDs for the model you intend to host +curl -sS https://active.mor.org/active_models.json \ + | jq '.[] | select(.modelName == "your-model-name") | {modelId, ipfsCID, providerAddress}' +``` + +If you see one already, use that `modelId` (the contract takes the same value as input — see how the on-chain `modelID` is `getModelId(modelOwner, requestedModelId)` in [`ModelRegistry.sol`](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/blob/main/smart-contracts/contracts/diamond/facets/ModelRegistry.sol); the resulting on-chain id will still be unique to your provider, but consumers can match on `modelName` + `ipfsCID`). + +## Pausing or temporarily disabling a model offering + +To stop offering a model **without deregistering it** (so you keep the `modelId`, keep the model stake bonded, and can resume cheaply): + +```bash +# Find your active bid +curl -sS -u 'admin:admin' 'http://localhost:8082/blockchain/bids' \ + | jq '.bids[] | select(.Provider=="0xYOUR_PROVIDER")' + +# Delete the bid +curl -X POST -u 'admin:admin' \ + 'http://localhost:8082/blockchain/bids/0xYOUR_BID_ID/delete' +``` + +The model record stays on chain. To resume, post a new bid (which charges the `0.3 MOR` `marketplaceBidFee` again — see [pricing](/providers/full/pricing)). + +If you want to **completely remove** a model: delete all of its bids first, then call `modelDeregister` to recover the `0.1 MOR` model stake. The contract refuses `modelDeregister` while any bid for that model is still active. + +## How and when you get paid + +For typical staked sessions, the protocol pays you **inside `closeSession`** via `_rewardProviderAfterClose`, with the funds coming from a **separate protocol `fundingAccount`** (via `transferFrom`), not from the consumer's stake in real time. There is no separate "session claim" step for the standard flow — the payment for time actually used hits your provider wallet in the same transaction that closes the session. + +What this means for you operationally: + +- Keep your provider wallet ready to **receive** MOR; you don't need to call a claim function. +- For the **direct-payment** carve-out (a separate flow some sessions use), behavior differs — see the contract source and [tech.mor.org/session.html](https://tech.mor.org/session.html) for the canonical breakdown. +- If `closeSession` ever fails because the protocol funding account is empty or under-approved, **no provider gets paid until operators top it up** — that's a network-wide failure mode, not a per-provider one. diff --git a/docs/providers/full/secretvm-quickstart.mdx b/docs/providers/full/secretvm-quickstart.mdx new file mode 100644 index 00000000..c6e1e78a --- /dev/null +++ b/docs/providers/full/secretvm-quickstart.mdx @@ -0,0 +1,196 @@ +--- +title: "SecretVM TEE quickstart" +description: "Shortest path to a v7 TEE provider: deploy the hardened -tee image on SecretVM and register a tee-tagged model." +audience: ["provider-full"] +product: ["proxy-router"] +last_verified: "v7.0.0" +source: "docs/02.4-proxy-router-secretvm-quickstart.md" +--- + +This guide walks you through deploying a Morpheus TEE-hardened provider node on [SecretVM](https://secretai.scrtlabs.com) (SCRT Labs' confidential VM platform). By the end you'll have a provider running inside a hardware-secured Intel TDX enclave that consumers can cryptographically verify before sending prompts. + +For deeper details (cosign verification, RTMR3 recomputation, attestation manifest inspection) see [TEE reference](/providers/full/tee-reference). For the trust-chain conceptual picture see [TEE overview](/concepts/tee-overview). + +## What you'll need + +- A **funded wallet** with MOR + ETH on Base Mainnet (or Base Sepolia for testnet). +- The wallet's **private key** — this stays encrypted inside the TEE. +- An **RPC endpoint** for Base Mainnet (e.g. `wss://base-mainnet.g.alchemy.com/v2/`). +- Your **AI model backend** reachable via a private URL (e.g. `http://my-model:8080/v1/chat/completions`). +- A **SecretVM account** at https://secretai.scrtlabs.com — sign up to get an API key. +- *(Recommended)* `secretvm-cli`: `sudo npm install --global secretvm-cli`. + +## Step 1: Get the Docker Compose file + +Each CI/CD build produces a deployed compose file pinning the TEE image by SHA-256 digest — that's what SecretVM uses to compute RTMR3. + +Download `docker-compose.tee.deployed.yml` from the [latest GitHub Release](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/releases) — the digest is already filled in. You can also use the template at [`proxy-router/docker-compose.tee.yml`](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/blob/main/proxy-router/docker-compose.tee.yml) and replace the image tag yourself. + +The compose includes a Traefik TLS sidecar that uses SecretVM's auto-generated certs to serve the API on HTTPS port 443. The full compose body is reproduced in [TEE reference → Step 1](/providers/full/tee-reference#step-1-prepare-the-docker-compose-file). + + +**Use the digest-pinned version.** Tags like `:latest` are mutable; the digest is not. Using the digest ensures RTMR3 will match the CI/CD-computed golden value. + + +## Step 2: Prepare your secrets + +Create a `.env` file with your 5 provider-specific secrets: + +```bash +WALLET_PRIVATE_KEY= +ETH_NODE_ADDRESS=wss://base-mainnet.g.alchemy.com/v2/ +MODELS_CONFIG_CONTENT={"models":[{"modelId":"0x","modelName":"your-model-name","apiType":"openai","apiUrl":"http://your-model:8080/v1/chat/completions","concurrentSlots":6,"capacityPolicy":"simple"}]} +WEB_PUBLIC_URL=https://your-public-domain.com +COOKIE_CONTENT=admin: +``` + +`MODELS_CONFIG_CONTENT` must be single-line JSON. Schema: [models-config.json](/reference/models-config). + +## Step 3: Deploy on SecretVM + + + + 1. Go to https://secretai.scrtlabs.com/secret-vms/create + 2. **Docker Compose**: paste the contents of your compose file. + 3. **Encrypted Secrets**: enter your 5 variables. + 4. **Advanced features**: + + | Setting | Recommended | Notes | + |---------|-------------|-------| + | **Platform** | Intel TDX | Required to match CI/CD golden values | + | **Additional Files** | Empty | Adding files changes RTMR3 | + | **Enable Persistence** | On | Preserves data across reboots | + | **Enable Upgrades** | On | Allows updates without reprovisioning | + | **Hide Runtime Info** | Off | Keeps the `/docker-compose` endpoint accessible for verification | + + 5. Click **Deploy**. + + + ```bash + secretvm-cli auth login + + secretvm-cli -k vm create \ + --name morpheus-provider \ + --type small \ + --persistence \ + --upgradeability \ + --docker-compose proxy-router/docker-compose.tee.yml \ + --env path/to/your/.env \ + --platform tdx + + secretvm-cli -k vm list + ``` + + Full CLI reference: [SecretVM CLI docs](https://docs.scrt.network/secret-network-documentation/secretvm-confidential-virtual-machines/secretvm-cli). + + + +## Step 4: Verify the node is running + +Once provisioned (typically 2-3 minutes): + +```bash +curl https:///healthcheck +``` + +The API is served on HTTPS port 443 via Traefik. Expected: + +```json +{ "status": "healthy", "version": "v7.0.0", "uptime": "1m30s" } +``` + +Verify the attestation endpoint (separate port, direct from SecretVM): + +```bash +curl -k https://:29343/cpu | head -c 100 +``` + +Returns a long hex string — your hardware-signed TDX attestation quote. + +## Step 5: Register as a TEE provider + +Same flow as a standard provider, with one critical addition: **tag your model `tee`**. + + + + `https:///swagger/index.html` + + + Follow [Register on chain](/providers/full/register-onchain). When creating the model, include the tag `"tee"` in the tags array. + + + +The `tee` tag is what triggers consumer-side attestation verification. Without it, consumers treat you as a standard provider. + +## Step 6: Verify your attestation + +### Quick check (SecretVM portal) + +1. Go to https://secretai.scrtlabs.com/attestation +2. Paste your compose file contents. +3. Enter your VM URL. +4. Click **Verify**. + +Three layers must pass: hardware (genuine Intel TDX), VM (known SecretVM firmware/kernel), software/RTMR3 (your image + compose match what CI/CD built). + +### Programmatic check (cosign) + +```bash +cosign verify \ + --certificate-oidc-issuer https://token.actions.githubusercontent.com \ + --certificate-identity-regexp 'MorpheusAIs/Morpheus-Lumerin-Node' \ + ghcr.io/morpheusais/morpheus-lumerin-node-tee: + +cosign verify-attestation \ + --certificate-oidc-issuer https://token.actions.githubusercontent.com \ + --certificate-identity-regexp 'MorpheusAIs/Morpheus-Lumerin-Node' \ + --type https://morpheusais.github.io/tee-attestation/v1 \ + ghcr.io/morpheusais/morpheus-lumerin-node-tee: \ + 2>/dev/null | jq -r '.payload' | base64 -d | jq '.predicate' +``` + +## What consumers see, what your P-Node does + +The two-hop trust chain — see [TEE overview](/concepts/tee-overview) for the full conceptual breakdown. + +``` +C-Node (v6.0.0+) ─Phase 1─▶ P-Node (-tee, v7.0.0+) ─Phase 2─▶ Backend LLM (SecretVM) +``` + +- **Phase 1** (consumer ↔ your P-Node): the consumer's proxy-router fetches your `:29343/cpu` quote, verifies via SecretAI portal, checks TLS binding, compares RTMR3 against the cosign-signed golden values, and re-checks with a ~50 ms fast path on every prompt. +- **Phase 2** (your P-Node ↔ backend): your P-Node fetches the backend's `:29343/cpu`, pins TLS, replays workload RTMR3 from `:29343/docker-compose`, verifies GPU evidence via NVIDIA NRAS, and re-checks per prompt. Per-model state is exposed at `GET /v1/models/attestation`. + +Forward compatibility: a v6.0.0+ C-Node only needs to understand Phase 1; Phase 2 is your P-Node's job. Any v6+ consumer works with any v7+ provider, gaining Phase 2 transparently. + +## Troubleshooting + +| Symptom | Likely cause | Fix | +|---------|-------------|-----| +| Healthcheck returns nothing | VM still provisioning | Wait 2-3 min, check `secretvm-cli vm list` | +| Attestation quote empty | Port 29343 not exposed | SecretVM exposes it automatically — check VM status | +| RTMR3 mismatch | Wrong compose content or rootfs version | Use the exact deployed compose from CI/CD artifacts (byte-for-byte) | +| TLS binding fails | Using a proxy/CDN that terminates TLS | The consumer must connect directly — no TLS-terminating intermediaries on `:29343` | +| `tee` model not getting sessions | Consumers on older versions | Consumers need v6.0.0+ for Phase 1 | +| Phase 2 failing silently on consumer | Phase 2 runs in **your** P-Node | Check `GET /v1/models/attestation` on your node | + +## Updating your node + +```bash +secretvm-cli -k vm edit \ + --docker-compose path/to/new/docker-compose.tee.yml +``` + +The VM reboots with the new image. Verify with `/healthcheck` and the attestation portal. + +## Further reading + +| Resource | Link | +|----------|------| +| Full TEE reference | [tee-reference](/providers/full/tee-reference) | +| Conceptual TEE overview | [TEE overview](/concepts/tee-overview) | +| models-config.json | [reference](/reference/models-config) | +| Provider/model/bid registration | [Register on chain](/providers/full/register-onchain) | +| Standard Docker (non-TEE) | [proxy-router-docker](/providers/full/proxy-router-docker) | +| SecretVM documentation | https://docs.scrt.network/secret-network-documentation/secretvm-confidential-virtual-machines | +| SecretVM CLI | https://docs.scrt.network/secret-network-documentation/secretvm-confidential-virtual-machines/secretvm-cli | +| TEE images on GHCR | https://github.com/orgs/MorpheusAIs/packages?repo_name=Morpheus-Lumerin-Node | diff --git a/docs/providers/full/tee-reference.mdx b/docs/providers/full/tee-reference.mdx new file mode 100644 index 00000000..9c6b4edb --- /dev/null +++ b/docs/providers/full/tee-reference.mdx @@ -0,0 +1,361 @@ +--- +title: "TEE reference" +description: "Build-time baked-in config, RTMR3 attestation, cosign image/manifest verification, and consumer-side verification steps for the -tee proxy-router image." +audience: ["provider-full", "developer", "consumer"] +product: ["proxy-router"] +last_verified: "v7.0.0" +source: "docs/02.3-proxy-router-tee.md" +--- + +This document covers two perspectives: + +1. **Provider** — how to deploy a TEE-hardened P-Node on a Confidential VM. +2. **Consumer** — how to verify a provider's image is genuine and untampered. + +For the shortest path to deploying on SecretVM, jump to [SecretVM quickstart](/providers/full/secretvm-quickstart). For a conceptual overview of the two-hop trust chain, see [TEE overview](/concepts/tee-overview). + +## What is the TEE image? + +The `-tee` Docker image (`ghcr.io/morpheusais/morpheus-lumerin-node-tee`) is a hardened version of the standard proxy-router image with all non-secret configuration **baked in at build time**: + +- Blockchain config (contract addresses, chain ID, blockscout URL) is frozen and cannot be changed at runtime. +- Chat context storage is disabled (`PROXY_STORE_CHAT_CONTEXT=false`). +- Logging is set to production mode (JSON, no color, minimal verbosity). +- Environment is locked to `production`. + +Two network variants are produced by CI/CD: + +| Branch | Image tag | Network | Chain ID | +|--------|-----------|---------|----------| +| `main` | `...-tee:vX.Y.Z` / `...-tee:latest` | BASE Mainnet | 8453 | +| `test` | `...-tee:vX.Y.Z-test` / `...-tee:latest-test` | BASE Sepolia | 84532 | + +Both share identical hardened settings; only the baked-in network's contracts and chain ID differ. The attestation manifest's `baked_env.network` field identifies which variant an image is. + +Only **5 variables** are configurable at runtime — the per-provider secrets: + +| Variable | Description | +|---|---| +| `WALLET_PRIVATE_KEY` | Provider's wallet private key | +| `ETH_NODE_ADDRESS` | RPC endpoint for BASE Mainnet (e.g., Alchemy, Infura) | +| `MODELS_CONFIG_CONTENT` | JSON model configuration (model IDs, backend URLs, slots) | +| `WEB_PUBLIC_URL` | Public-facing URL for the API (default: `http://localhost:8082`) | +| `COOKIE_CONTENT` | API auth credentials (default: `admin:admin`) | + +Because configuration is frozen in the image, when run inside a TEE (Intel TDX or AMD SEV-SNP) the hardware can measure and attest that the software has not been modified. + +--- + +## Part 1: Provider — Setting up a TEE P-Node + +### Prerequisites + +- Funded wallet (MOR + ETH) on the target network and access to its private key. +- An RPC endpoint for the target network (e.g. `wss://base-mainnet.g.alchemy.com/v2/`). +- Your AI model backend reachable on a private endpoint. +- A `models-config.json` content (see [models-config schema](/reference/models-config)). +- Access to a Confidential VM provider supporting Intel TDX or AMD SEV-SNP (e.g., [SecretVM](https://secretai.scrtlabs.com/secret-vms/create)). + + +**Mainnet vs testnet**: Use the mainnet TEE image (`:latest` or versioned tag without `-test`) for production. Use testnet (`:latest-test` / `*-test` tags) on Base Sepolia. Substitute the testnet image and a Sepolia RPC if testing. + + +### Step 1: Prepare the Docker Compose file + +Each CI/CD build produces a **deployed compose file** that pins the TEE image by immutable SHA-256 digest. RTMR3 is computed from the exact compose content. + +Download `docker-compose.tee.deployed.yml` from the [GitHub Release](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/releases) for your target version, or use the template at [`proxy-router/docker-compose.tee.yml`](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/blob/main/proxy-router/docker-compose.tee.yml) and fill in the digest yourself. + +The deployed compose looks like (digest differs per version): + +```yaml +services: + proxy-router: + image: ghcr.io/morpheusais/morpheus-lumerin-node-tee@sha256: + restart: unless-stopped + ports: + - 3333:3333 + volumes: + - proxy_data:/app/data + environment: + - WALLET_PRIVATE_KEY=${WALLET_PRIVATE_KEY} + - ETH_NODE_ADDRESS=${ETH_NODE_ADDRESS} + - MODELS_CONFIG_CONTENT=${MODELS_CONFIG_CONTENT} + - WEB_PUBLIC_URL=${WEB_PUBLIC_URL:-https://localhost} + - COOKIE_CONTENT=${COOKIE_CONTENT:-admin:admin} + env_file: + - usr/.env + networks: + - traefik + labels: + - traefik.enable=true + - traefik.http.routers.proxy-router.rule=PathPrefix(`/`) + - traefik.http.routers.proxy-router.entrypoints=websecure + - traefik.http.routers.proxy-router.tls=true + - traefik.http.services.proxy-router.loadbalancer.server.port=8082 + traefik: + image: traefik:v2.10 + command: + - --api.insecure=false + - --providers.docker=true + - --providers.docker.exposedbydefault=false + - --entrypoints.websecure.address=:443 + - --entrypoints.websecure.http.tls.options=default@file + - --providers.file.directory=/etc/traefik/dynamic + - --providers.file.watch=true + ports: + - 443:443 + volumes: + - /var/run/docker.sock:/var/run/docker.sock:ro + - /mnt/secure/cert:/certs:ro + networks: + - traefik + configs: + - source: tls_config + target: /etc/traefik/dynamic/tls.yml + env_file: + - usr/.env +volumes: + proxy_data: null +networks: + traefik: + driver: bridge +configs: + tls_config: + content: |- + tls: + certificates: + - certFile: /certs/secret_vm_fullchain.pem + keyFile: /certs/secret_vm_private.pem + stores: + default: + defaultCertificate: + certFile: /certs/secret_vm_fullchain.pem + keyFile: /certs/secret_vm_private.pem +``` + +The **only line that changes between versions** is the proxy-router image digest. The Traefik sidecar, TLS config, and network setup stay constant. + + +**Why digest, not tag?** Tags are mutable. The digest (`@sha256:...`) is an immutable content hash. Using the digest in the compose file guarantees RTMR3 is cryptographically bound to one specific image binary. + +**Exact byte content matters.** The compose file must end with exactly one newline after `proxy_data: null`. RTMR3 is computed from the exact byte content — a single extra or missing byte changes the hash. The SecretVM portal normalizes trailing whitespace down to one newline, so pasting as-is is safe. + + +Published images and digests: [GHCR packages](https://github.com/orgs/MorpheusAIs/packages?repo_name=Morpheus-Lumerin-Node). + +### Step 2: Prepare your secrets + +Set 5 values in your TEE platform's encrypted secrets section: + +``` +WALLET_PRIVATE_KEY= +ETH_NODE_ADDRESS=wss://base-mainnet.g.alchemy.com/v2/ +MODELS_CONFIG_CONTENT= +WEB_PUBLIC_URL=https://your-public-domain.com:8082 +COOKIE_CONTENT=admin: +``` + +`MODELS_CONFIG_CONTENT` must be a **single-line JSON string**: + +``` +MODELS_CONFIG_CONTENT={"models":[{"modelId":"0x626bcb19...","modelName":"hermes-4-14b","apiType":"openai","apiUrl":"http://your-model:8080/v1/chat/completions","concurrentSlots":6,"capacityPolicy":"simple"}]} +``` + +Schema: [models-config.json](/reference/models-config). + +### Step 3: Deploy on SecretVM (or other TEE platform) + +For SecretVM specifics (web portal vs CLI, advanced features, recommended platform = Intel TDX), see [SecretVM quickstart](/providers/full/secretvm-quickstart). + +For other TEE platforms, consult their documentation for Docker Compose with encrypted secret injection. The image and compose are platform-agnostic — any environment supporting `linux/amd64` Docker inside a TEE works. + +### Step 4: Verify the node is running + +```bash +curl https:///healthcheck +``` + +Expected: + +```json +{ "status": "healthy", "version": "", "uptime": "1m30s" } +``` + +Then proceed with [Register on chain](/providers/full/register-onchain) (with the `tee` model tag). + +### Step 5: Verify attestation (SecretVM) + +After deployment, SecretVM exposes attestation endpoints on `:29343`. Verify your own deployment: + +1. Quick verification at https://secretai.scrtlabs.com/attestation — paste your compose and the VM URL. +2. Programmatic verification — see Part 2. + +--- + +## Part 2: Consumer — Verifying a TEE provider image + +As a consumer you can independently verify a provider before using it. Verification will eventually be built into the C-Node automatically for `tee`-tagged models, but you can do it manually today. + +### Install cosign + +```bash +# macOS +brew install cosign +# Linux (Debian/Ubuntu) +sudo apt install cosign +# Or: https://github.com/sigstore/cosign/releases +``` + +### Step 1: Verify the image signature + +Confirms the image was built by the official MorpheusAIs CI/CD pipeline. + +```bash +cosign verify \ + --certificate-oidc-issuer https://token.actions.githubusercontent.com \ + --certificate-identity-regexp 'MorpheusAIs/Morpheus-Lumerin-Node' \ + ghcr.io/morpheusais/morpheus-lumerin-node-tee: +``` + +Successful output mentions: cosign claims validated, transparency log verified, code-signing cert verified by trusted CA. The output JSON includes the exact GitHub commit, branch, and workflow that produced the image. + +If verification fails, **do not trust the image.** + +### Step 2: Inspect the TEE attestation manifest + +```bash +cosign verify-attestation \ + --certificate-oidc-issuer https://token.actions.githubusercontent.com \ + --certificate-identity-regexp 'MorpheusAIs/Morpheus-Lumerin-Node' \ + --type https://morpheusais.github.io/tee-attestation/v1 \ + ghcr.io/morpheusais/morpheus-lumerin-node-tee: \ + 2>/dev/null | jq -r '.payload' | base64 -d | jq '.predicate' +``` + +Key fields: + +| Field | What to check | +|---|---| +| `tee_image` | Full image reference with `@sha256:` digest | +| `tee_image_digest` | Immutable `sha256:...` of this image | +| `compose_sha256` | Hash of the deployed compose (digest-pinned) | +| `compose_image_reference` | The exact `image@sha256:` reference inside the compose | +| `measurements.intel_tdx.rtmr3` | Expected RTMR3 — compare against live hardware quote | +| `measurements.intel_tdx.secretvm_release` | SecretVM release the RTMR3 was computed against | +| `build.commit` | Git commit that produced this image | +| `build.run_url` | Direct link to the GitHub Actions run | +| `baked_env.network` | `mainnet` or `testnet` | +| `baked_env.PROXY_STORE_CHAT_CONTEXT` | Should be `false` | +| `baked_env.ENVIRONMENT` | Should be `production` | +| `baked_env.ETH_NODE_CHAIN_ID` | `8453` or `84532` | +| `baked_env.DIAMOND_CONTRACT_ADDRESS` | Diamond proxy for the target network | +| `baked_env.MOR_TOKEN_ADDRESS` | MOR token for the target network | +| `runtime_secrets_only` | The 5 variables that can differ per provider | + +### Step 3: View all supply-chain artifacts + +```bash +cosign tree ghcr.io/morpheusais/morpheus-lumerin-node-tee: +``` + +Shows signatures (`.sig`), attestations (`.att`), and SBOMs (`.sbom`). + +### Step 4: Verify the running provider (SecretVM attestation) + +If the provider is on SecretVM: + +1. Go to https://secretai.scrtlabs.com/attestation +2. Paste the `docker-compose.tee.yml` (exact byte content — see warning above). +3. Enter the provider's VM URL or paste their attestation quote. +4. Click **Verify**. + +Three layers must pass: hardware (genuine Intel TDX / AMD SEV-SNP), VM (firmware + kernel + initramfs match a known SecretVM release), software (RTMR3: rootfs + Docker Compose match what was deployed). + +The expected RTMR3 is published in the signed manifest at `measurements.intel_tdx.rtmr3`. Compare it against the value reported by the hardware quote. + +### Step 5: Verify RTMR3 independently (optional) + +```bash +# Check the pinned version and rootfs variant +cat .github/tee/secretvm.env +# → SECRETVM_RELEASE=v0.0.25 +# → SECRETVM_ROOTFS_VARIANT=rootfs-prod-tdx + +# Download the same rootfs used by CI/CD +curl -L -o rootfs-prod-tdx.iso \ + "$(grep SECRETVM_ROOTFS_TDX_URL .github/tee/secretvm.env | cut -d= -f2-)" + +# Compute RTMR3 from the deployed compose + rootfs +python3 proxy-router/scripts/compute-rtmr3.py docker-compose.tee.deployed.yml rootfs-prod-tdx.iso +``` + +Output should match `measurements.intel_tdx.rtmr3`. If not, check that you're using the same rootfs version as the CI/CD build. + +--- + +## What this guarantees (and what it does not) + +See the conceptual breakdown in [TEE overview](/concepts/tee-overview), which mirrors and summarizes the per-phase guarantees and remaining gaps documented here. + +## Upgrading SecretVM artifacts + +When SCRT Labs publishes a new SecretVM release (e.g. `v0.0.25 → v0.0.26`), the rootfs changes and all RTMR3 values must be recomputed. The CI/CD pipeline is fully variabilized so updating requires only editing `.github/tee/secretvm.env`. + +### When to upgrade + +SCRT Labs publishes at [github.com/scrtlabs/secret-vm-build/releases](https://github.com/scrtlabs/secret-vm-build/releases). No push notifications — check periodically: + +```bash +curl -s https://api.github.com/repos/scrtlabs/secret-vm-build/releases \ + | jq '[.[] | {tag: .tag_name, prerelease: .prerelease, date: .published_at}] | .[0:5]' +``` + + +SCRT Labs sometimes marks new releases as **pre-release** on GitHub while already deploying them to the SecretVM portal. The `/releases/latest` API only returns non-prerelease versions, so always check the full list. + + +### How to upgrade + + + + ```bash + SECRETVM_RELEASE=v0.0.26 + SECRETVM_ROOTFS_TDX_URL=https://github.com/scrtlabs/secret-vm-build/releases/download/v0.0.26/rootfs-prod-v0.0.26-tdx.iso + SECRETVM_ROOTFS_TDX_SHA256= + ``` + `SECRETVM_ROOTFS_VARIANT` stays `rootfs-prod-tdx` unless naming changes. + + + The pipeline downloads the new rootfs, computes its SHA-256, computes the new RTMR3, and embeds it in the signed manifest. + + + Copy the SHA-256 from the GitHub Actions step summary back into `secretvm.env`: + ```bash + SECRETVM_ROOTFS_TDX_SHA256= + ``` + + + Providers running older SecretVM versions will have mismatched RTMR3. They should redeploy on the current SecretVM release. + + + + +**Always use the `prod` rootfs variant.** SecretVM runs "environment prod" even for developer-portal deployments. Using `dev` produces a wrong RTMR3. + + +--- + +## Reference + +| Resource | Link | +|---|---| +| TEE images on GHCR | https://github.com/orgs/MorpheusAIs/packages?repo_name=Morpheus-Lumerin-Node | +| RTMR3 computation script | [`proxy-router/scripts/compute-rtmr3.py`](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/blob/main/proxy-router/scripts/compute-rtmr3.py) | +| SecretVM artifact config | [`.github/tee/secretvm.env`](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/blob/main/.github/tee/secretvm.env) | +| Sigstore cosign | https://github.com/sigstore/cosign | +| SCRT Labs reproduce-mr | https://github.com/scrtlabs/reproduce-mr | +| SecretVM documentation | https://docs.scrt.network/secret-network-documentation/secretvm-confidential-virtual-machines | +| SecretVM CLI docs | https://docs.scrt.network/secret-network-documentation/secretvm-confidential-virtual-machines/secretvm-cli | +| SecretVM attestation portal | https://secretai.scrtlabs.com/attestation | +| Phase 2 backend developer reference | [`proxy-router/docs/tee-backend-verification.md`](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/blob/main/proxy-router/docs/tee-backend-verification.md) | diff --git a/docs/providers/full/verify-setup.mdx b/docs/providers/full/verify-setup.mdx new file mode 100644 index 00000000..e7e2165f --- /dev/null +++ b/docs/providers/full/verify-setup.mdx @@ -0,0 +1,120 @@ +--- +title: "Verify your provider setup" +description: "Self-check your provider end-to-end after setup: healthcheck, on-chain registration, network discovery, and a real prompt against your bid." +audience: ["provider-full", "provider-resale"] +product: ["proxy-router"] +last_verified: "v7.0.0" +--- + +After [registering](/providers/full/register-onchain) your provider, model, and bid, you want to know **before any consumer hits you** that everything works. There is no built-in setup wizard yet. This page walks the same five checks the support team uses to verify a provider when someone posts in Discord asking "can you check if my setup is OK?". + +## Step 1 — Local health + +Your proxy-router is up and listening: + +```bash +curl http://localhost:8082/healthcheck +``` + +Expected: + +```json +{ "status": "healthy", "version": "v7.0.0", "uptime": "..." } +``` + +Logs should show: + +``` +INFO proxy state: running +INFO HTTP http server is listening: 0.0.0.0:8082 +INFO TCP tcp server is listening: 0.0.0.0:3333 +``` + +If anything here is wrong, stop and fix it before the next steps — see [troubleshooting](/reference/troubleshooting). + +## Step 2 — Public TCP reachable + +Consumers connect to your `:3333` over the public internet. From a machine **outside your network**: + +```bash +# Replace with your provider's registered endpoint (host:port, no protocol) +nc -vz your-provider.example.com 3333 +``` + +Expected: `Connection succeeded`. If it times out, your firewall / security group / NAT is blocking; consumers will see your bid but never get inference. + +## Step 3 — On-chain provider record + +Confirm the marketplace recognises your registration: + +```bash +# Replace with your provider wallet address (lowercase 0x…) +curl -sS -u 'admin:admin' \ + 'http://localhost:8082/blockchain/providers' \ + | jq '.providers[] | select(.Address=="0xYOUR_PROVIDER")' +``` + +You should see your `Address`, `Endpoint` (the `host:port` you registered, no protocol), `Stake`, and `IsDeleted: false`. + +Same trick for your model: + +```bash +curl -sS -u 'admin:admin' 'http://localhost:8082/blockchain/models' \ + | jq '.models[] | select(.Owner=="0xYOUR_PROVIDER")' +``` + +And your bid: + +```bash +curl -sS -u 'admin:admin' 'http://localhost:8082/blockchain/bids' \ + | jq '.bids[] | select(.Provider=="0xYOUR_PROVIDER")' +``` + +If any of these doesn't return your record, the on-chain transaction either failed or is still pending. Check the explorer with your provider wallet address ([base.blockscout.com](https://base.blockscout.com)). + +## Step 4 — Network discovery + +Two cron-driven dashboards aggregate the marketplace into JSON snapshots. Your provider only shows up here if the cron has reached you successfully **after your registration**: + +```bash +# Active models — populated when the verifier can reach your provider's :3333 and ping the model +curl -sS https://active.mor.org/active_models.json | jq '.[] | select(.providerAddress=="0xYOUR_PROVIDER")' + +# Active bids — same, but for bids +curl -sS https://active.mor.org/active_bids.json | jq '.[] | select(.providerAddress=="0xYOUR_PROVIDER")' +``` + +If your bid is on chain (Step 3) but **not** in `active_bids.json`, it means the verifier could reach the chain but **could not reach your `:3333`**. Re-check Step 2. + +The dashboards refresh on a schedule (a few minutes); give it time before concluding it failed. + +## Step 5 — End-to-end prompt via the Inference API + +The hosted [Morpheus Inference API](/inference-api/overview) serves as the easiest end-to-end consumer. If a real prompt against your model name returns text, you've proven the full chain (consumer → API Gateway → discovery → your P-Node → your backend → response). + +1. Sign in at [app.mor.org](https://app.mor.org), grab an API key. +2. In the dashboard's **API Test** page (or any OpenAI-compatible client) pick your model name from the dropdown. +3. Send any short prompt. + +If it streams back a response — **you're done**. If the model isn't in the dropdown, go back to Step 4. If it's there but errors out, check your proxy-router logs for the incoming request and your backend's logs for the forwarded request. + +You can also do this directly from a separate consumer-side proxy-router; see [API direct](/reference/api-direct). + +## When in doubt + +The Discord `#tech-support` channel is the fastest path. Include: + +- Your provider wallet address (lowercase `0x…`). +- Your model ID and bid ID. +- The output of **Steps 1, 3, and 4**. + +The first thing support does is exactly the above checks; arriving with the answers shortcuts the conversation. + +## Common gotchas surfaced by the chat history + +| Symptom | Cause | Fix | +|---------|-------|-----| +| Provider on chain but missing from `active_bids.json` | Public `:3333` not reachable | Open firewall / security group; verify with `nc -vz` from outside | +| `:3333` reachable, model still missing from `active_models.json` | The verifier couldn't ping the model's `apiUrl` | Confirm `models-config.json` `apiUrl` is reachable **from inside the proxy-router host** | +| Healthcheck fails with `connection refused` to BASE | Default round-robin RPC rate-limited / unavailable | Set your own `ETH_NODE_ADDRESS` (Alchemy / Infura) — see [env-proxy-router](/reference/env-proxy-router) | +| Lost ~MOR during setup | Each `postModelBid` charges a non-refundable `marketplaceBidFee` (`0.3 MOR`); reposting bids during configuration adds up | See [Pricing](/providers/full/pricing) and the "What can cost you MOR during setup" section in [Quickstart](/providers/full/quickstart) | diff --git a/docs/providers/resale/container-pnode.mdx b/docs/providers/resale/container-pnode.mdx new file mode 100644 index 00000000..4b27e4be --- /dev/null +++ b/docs/providers/resale/container-pnode.mdx @@ -0,0 +1,83 @@ +--- +title: "Container P-Node for resale" +description: "Run a containerized proxy-router as a resale provider; only the configuration changes vs a full P-Node." +audience: ["provider-resale"] +product: ["proxy-router"] +last_verified: "v7.0.0" +--- + +A resale P-Node is the **same proxy-router image** as a full provider — `ghcr.io/morpheusais/morpheus-lumerin-node:latest`. Only the `models-config.json` differs. + +For full mechanics (volumes, env files, ports, build), follow [Provider Docker](/providers/full/proxy-router-docker). This page focuses on what changes. + +## Differences vs full P-Node + +| Aspect | Full P-Node | Resale P-Node | +|--------|-------------|---------------| +| `apiUrl` | Internal/private model URL | Upstream's chat-completions URL | +| `apiKey` | Usually omitted | Required (your upstream account key) | +| `concurrentSlots` | Bound by your hardware | Bound by your upstream rate limits | +| Model `tee` tag | Optional (for TEE) | Don't use — you can't attest the upstream | +| `endpoint` (on-chain) | Same | Same — must be publicly reachable | +| Subnet provider stake | Same `10000` MOR if applicable | Same | + +## Example `models-config.json` for a resale node + +```json +{ + "$schema": "./internal/config/models-config-schema.json", + "models": [ + { + "modelId": "0x", + "modelName": "gpt-4o-mini", + "apiType": "openai", + "apiUrl": "https://api.openai.com/v1/chat/completions", + "apiKey": "sk-...", + "concurrentSlots": 4, + "capacityPolicy": "simple" + }, + { + "modelId": "0x", + "modelName": "claude-3-5-sonnet-20241022", + "apiType": "claudeai", + "apiUrl": "https://api.anthropic.com/v1/messages", + "apiKey": "sk-ant-...", + "concurrentSlots": 4 + } + ] +} +``` + +Full schema: [models-config.json](/reference/models-config). + +## Bare minimum docker run + +```bash +docker run -d \ + --name morpheus-resale \ + -e ETH_NODE_CHAIN_ID=8453 \ + -e BLOCKSCOUT_API_URL=https://base.blockscout.com/api/v2 \ + -e DIAMOND_CONTRACT_ADDRESS=0x6aBE1d282f72B474E54527D93b979A4f64d3030a \ + -e MOR_TOKEN_ADDRESS=0x7431aDa8a591C955a994a21710752EF9b882b8e3 \ + -e WALLET_PRIVATE_KEY= \ + -e PROXY_ADDRESS=0.0.0.0:3333 \ + -e WEB_ADDRESS=0.0.0.0:8082 \ + -e WEB_PUBLIC_URL=https://your.public.host \ + -e MODELS_CONFIG_PATH=/app/data/models-config.json \ + -v $HOME/morpheus-resale:/app/data \ + -p 3333:3333 \ + -p 8082:8082 \ + ghcr.io/morpheusais/morpheus-lumerin-node:latest +``` + +(Place your `models-config.json` in `$HOME/morpheus-resale/` before starting.) + +## Reverse proxy and TLS + +Resale providers should put the proxy-router's `:8082` behind a reverse proxy (nginx, Caddy, Traefik) with TLS for the operator-facing API. The `:3333` TCP port stays plain for consumer traffic — it's an end-to-end TCP tunnel, not HTTPS. + +## Next + +- [Reselling Venice](/providers/resale/reselling-venice) — concrete walkthrough. +- [Registering a bid](/providers/resale/registering-bid) — pricing decisions. +- [Register on chain](/providers/full/register-onchain) — same flow as full providers. diff --git a/docs/providers/resale/overview.mdx b/docs/providers/resale/overview.mdx new file mode 100644 index 00000000..69520644 --- /dev/null +++ b/docs/providers/resale/overview.mdx @@ -0,0 +1,62 @@ +--- +title: "Resale provider overview" +description: "Why and how to resell capacity from Venice / OpenAI / Anthropic / Hyperbolic on Morpheus, without hosting your own model." +audience: ["provider-resale"] +product: ["proxy-router"] +last_verified: "v7.0.0" +--- + +A "resale" provider runs a Morpheus proxy-router but does **not** host the model itself. The proxy-router forwards prompts to a hosted backend (Venice, OpenAI, Anthropic, Hyperbolic, etc.) using the backend's API key, and you collect MOR from the marketplace. + +```mermaid +flowchart LR + Consumer[Morpheus consumer] --> ConsumerProxy[Consumer proxy-router] + ConsumerProxy -->|"3333 TCP"| YourProxy[Your proxy-router] + YourProxy -->|"https + apiKey"| External[Venice / OpenAI / Anthropic] +``` + +## Why resale + +- You already pay for capacity at a hosted LLM provider that has spare headroom. +- You want exposure to MOR earnings without operating GPUs. +- You can stack on top of subscription plans (e.g. Venice Diem) and arbitrage between subscription cost and per-second MOR pricing. + +## Why **not** resale + +- You are bound by the upstream provider's TOS — many forbid resale; check first. +- Your margins depend on upstream pricing changes and rate limits. +- You cannot offer TEE attestation guarantees (see [TEE overview](/concepts/tee-overview)) because you do not control the backend. + +## How it works mechanically + +1. You run a normal proxy-router (containerized or bare-metal) — see [Container P-Node](/providers/resale/container-pnode). +2. In your `models-config.json` you set `apiUrl` to the upstream's chat completions endpoint and `apiKey` to your upstream account key. +3. You register your provider, model, and bid on chain — same as a standard full provider, just **without the `tee` tag**. +4. Consumer prompts arrive on `:3333`, get routed to your proxy-router on `:8082`, which forwards to the upstream `apiUrl`. Upstream responses stream back the same way. + +## Things to watch for + + +**Upstream TOS.** Most commercial inference providers have explicit clauses about reselling. Read them. Reselling someone else's API in violation of their TOS is your risk, not Morpheus's. + + +- **Concurrency.** Set `concurrentSlots` in `models-config.json` to a value your upstream account actually supports — over-promising leads to dropped sessions and reputation damage. +- **Latency.** Resale adds two extra hops vs a colocated backend. Bid pricing should reflect this. +- **API compatibility.** The proxy-router speaks OpenAI-shaped requests; your upstream should as well. Mappings exist for Anthropic and Prodia. See [models-config.json](/reference/models-config). + +## Next steps + + + + Stand up a proxy-router container. + + + Concrete example: Venice Diem capacity. + + + Bid pricing for resale economics. + + + Same flow as a full provider (without `tee`). + + diff --git a/docs/providers/resale/registering-bid.mdx b/docs/providers/resale/registering-bid.mdx new file mode 100644 index 00000000..73f7b321 --- /dev/null +++ b/docs/providers/resale/registering-bid.mdx @@ -0,0 +1,65 @@ +--- +title: "Pricing a resale bid" +description: "Translate upstream subscription / per-token cost into a Morpheus pricePerSecond bid that clears your costs." +audience: ["provider-resale"] +product: ["proxy-router"] +last_verified: "v7.0.0" +--- + +Morpheus bids quote `pricePerSecond` in MOR. Most upstream APIs quote per-token or per-month. To set a defensible bid, you need to translate upstream cost into per-second MOR. + +## A simple model + +For a per-token upstream: + +``` +upstream_$_per_second ≈ tokens_per_second_average × upstream_$_per_token_blended + = tps × ((p × in_$/tok) + ((1−p) × out_$/tok)) +``` + +Where `p` is the share of input tokens (often ~0.3 for chat). Convert dollars to MOR using the current MOR/USD rate. + +For a flat-rate (subscription) upstream: + +``` +upstream_$_per_second ≈ subscription_$_per_month / (utilized_seconds_per_month) +``` + +You should `pricePerSecond ≥ upstream_$_per_second + your_margin + risk_buffer`. + +## Floor and minimums + +| Item | Value | +|------|-------| +| `bidPricePerSecondMin` | `10000000000` wei (`0.00000001` MOR/sec) | +| Marketplace bid fee (paid once) | `0.3` MOR | +| Provider stake (refundable) | `0.2` MOR (or `10000` MOR for subnet) | +| Model stake (refundable) | `0.1` MOR | + +You **cannot** post below the floor. There is no upper limit, but consumer rating algorithms will skip you if you're far above other providers serving the same model. + +## A worked example + +Suppose Venice Diem costs you `$30/mo` and you expect ~`100k` seconds of utilized inference per month: + +``` +$/sec = 30 / 100000 ≈ 0.0003 USD/sec +``` + +If `1 MOR ≈ $X` (check live), then `MOR/sec ≈ 0.0003 / X`. Add a `~30%` margin for headroom. + +## Iterating on pricing + +- Watch your bid acceptance rate. If you get no sessions, you may be priced too high. +- Watch upstream margin. If sessions cost more upstream than they bring in MOR, raise pricing or reduce concurrency. +- Look at competing bids on [active.mor.org](https://active.mor.org). + +## Updating an existing bid + +Bids are immutable on chain — to change pricing, **delete** the old bid (`DELETE /blockchain/bids/:id`) and post a new one. Plan for the bid fee on each post. + +## Risk hygiene + +- Keep a small ETH balance for gas; running out mid-session is bad UX. +- Keep extra MOR allowance approved to the Diamond contract so re-posting bids doesn't fail mid-month. +- For multi-model resale, post one bid per `modelId` — the proxy-router routes by `modelId` deterministically. diff --git a/docs/providers/resale/reselling-venice.mdx b/docs/providers/resale/reselling-venice.mdx new file mode 100644 index 00000000..6a0e31ba --- /dev/null +++ b/docs/providers/resale/reselling-venice.mdx @@ -0,0 +1,86 @@ +--- +title: "Reselling Venice (Diem) capacity" +description: "Stand up a Morpheus resale P-Node fronted by Venice's API, using your Venice Diem subscription's API access." +audience: ["provider-resale"] +product: ["proxy-router"] +last_verified: "v7.0.0" +--- + +[Venice](https://venice.ai) sells subscription tiers (including the Diem tier) that include API access. If you have spare headroom in your Venice subscription, you can resell that capacity through Morpheus by configuring your proxy-router to forward to Venice's API. + + +**Read Venice's TOS.** Resale terms vary by tier and over time — confirm yours allows reselling API access before going live. This page describes mechanics, not legal permission. + + +## Architecture + +```mermaid +flowchart LR + Consumer[Morpheus consumer] --> Marketplace[BASE Diamond contract] + Consumer --> CRouter[Consumer proxy-router] + CRouter -->|"3333 TCP"| YourProxy[Your proxy-router] + YourProxy -->|"venice.ai apiKey"| Venice[Venice API] +``` + +## Steps + + + + Sign up at https://venice.ai and obtain an API key from your account dashboard. Confirm your tier supports the model you intend to resell at the concurrency you intend to advertise. + + + Examples: `text-embedding-bge-m3`, `tts-kokoro`, plus chat models supported by Venice. Check Venice's docs for the exact `apiUrl` per model. + + + Follow [Container P-Node](/providers/resale/container-pnode). Start the container; it will create `models-config.json` defaults you can edit. + + + ```json + { + "$schema": "./internal/config/models-config-schema.json", + "models": [ + { + "modelId": "0x", + "modelName": "venice-chat", + "apiType": "openai", + "apiUrl": "https://api.venice.ai/api/v1/chat/completions", + "apiKey": "", + "concurrentSlots": 4, + "capacityPolicy": "simple" + }, + { + "modelId": "0x", + "modelName": "text-embedding-bge-m3", + "apiType": "openai", + "apiUrl": "https://api.venice.ai/api/v1/embeddings", + "apiKey": "" + }, + { + "modelId": "0x", + "modelName": "tts-kokoro", + "apiType": "openai", + "apiUrl": "https://api.venice.ai/api/v1/audio/speech", + "apiKey": "" + } + ] + } + ``` + Restart the proxy-router after edits. + + + Same as a full provider, **without** the `tee` tag (you cannot attest Venice). Follow [Register on chain](/providers/full/register-onchain). + + + Lower is more attractive but you must clear your Venice cost. See [Registering a bid](/providers/resale/registering-bid) for the math. + + + Open `http://your-host:8082/swagger/index.html`. From a separate consumer node, list models, open a session against your bid, and prompt. Watch your proxy-router logs and Venice usage dashboard simultaneously. + + + +## Operational tips + +- **Track Venice usage** — set Venice account limits/alerts so a session can't blow your budget. +- **Throttle `concurrentSlots`** — start conservatively. Going too high causes upstream 429s, which surface to consumers as a bad experience. +- **Failover**: if you maintain multiple upstream accounts, run multiple proxy-routers and post separate bids; consumers route to whichever is cheapest and healthy. +- **Avoid the `tee` tag** — you cannot prove anything about Venice's runtime. Only use `tee` when you control the backend on a SecretVM-style TEE. diff --git a/docs/proxy-router-api-direct.md b/docs/proxy-router-api-direct.md deleted file mode 100644 index 1558518c..00000000 --- a/docs/proxy-router-api-direct.md +++ /dev/null @@ -1,164 +0,0 @@ -# Direct Consumer interaction with the proxy-router (no MorpheusUI) -This document provides a step-by-step flow to query your local proxy router and interact with a remote model using only the API. This is useful for developers or users who want to interact with the model directly without using the MorpheusUI. - -## Pre-requisites: -* Create or use an existing ERC-20 wallet that has MOR and ETH on BASE - you can use Metamask (new wallet..not derived) or any other ERC-20 wallet. -* You will need to have access to the wallet's private key **NEVER SHARE THIS WITH ANYONE** for steps below to authorize the contract to spend on your behalf. -* Install and launch the local llama.cpp and proxy-router from source (see [/docs/mac-boot-strap.md](/docs/mac-boot-strap.md) for instructions) - -## TL;DR -* Authorize the contract to spend on your behalf (once) -* Query the blockchain for various models / providers & get the ModelID `Id` (every session) -* Create a session with the provider using the ModelID `Id` (every session) -* Interact with the provider by sending the prompt (every session) - -## Detail: -### A. Start the proxy-router (per instructions) -See [/docs/proxy-router-api-auth.md](/docs/proxy-router-api-auth.md) for auth instructions. - -### B. Authorize the contract to spend on your behalf -Either via the swagger interface http://localhost:8082/swagger/index.html#/wallet/post_blockchain_allowance or following CLI, you can authorize the contract to spend on your behalf. **This only needs to be done once per wallet, or when funds have been depleted.** - -Approve the contract to spend 3 MOR tokens on your behalf - -```sh -curl -X 'POST' 'http://localhost:8082/blockchain/approve?spender=0x6aBE1d282f72B474E54527D93b979A4f64d3030a&amount=3' -H 'accept: application/json' -d '' -``` - -### C. Query the blockchain for various models / providers (Get ModelID) -* You can query the blockchain for various models and providers to get the ModelID. -* This can be done via the swagger interface http://localhost:8082/swagger/index.html#/marketplace/get_marketplace_models or following CLI: -```sh -# Returns the wallet ID (confirm that it matches your wallet): -curl -X 'GET' 'http://localhost:8082/wallet' -H 'accept: application/json' - -# Returns the list of models and providers: -curl -X 'GET' 'http://localhost:8082/blockchain/models' -H 'accept: application/json' -``` -* The first model in the list is the default model that you can use for testing purposes...see example below -* `Id` is the ID of the model that you will use to create a session with the provider. -* `Name` is the type of model offered - -``` -{ - "models": [ - { - "Id": "0x6a4813e866a48da528c533e706344ea853a1d3f21e37b4c8e7ffd5ff25779018", - "IpfsCID": "0x0000000000000000000000000000000000000000000000000000000000000000", - "Fee": 0, - "Stake": 0, - "Owner": "0x0eb467381abbc5b71f275df0c8a4e0ed8561f46f", - "Name": "llama2:7b", - "Tags": [], - "CreatedAt": 1721220139, - "IsDeleted": false - }, - { - "Id": "0x72eb5a6a575cdfb59e650994240961db2b1d915dbaa7c009b53b20fe8b9d2d7c", - "IpfsCID": "0x019ae5515ec6259cf835639fd645620811fe951f54c55ae5c85c1bb101cdcc3a", - "Fee": 42, - "Stake": 0, - "Owner": "0x65bbb982d9b0afe9aed13e999b79c56ddf9e04fc", - "Name": "CollectiveCognition-v1.1-Mistral-7b", - "Tags": [], - "CreatedAt": 1721222411, - "IsDeleted": false - }, - { - "Id": "0x84b6df5c84e1e6ae59c90e1639e3e77148d140065ef2cd4fba7f41cc7440e2c5", - "IpfsCID": "0xa3b9c9e18f25d3be47a2c8f0b1d5e6c78492fa7bcd34e9a1f6c2d3a5e4f9b7c1", - "Fee": 42, - "Stake": 0, - "Owner": "0xb8f836c167d60e20e44baf62d4d46c9e26fea97f", - "Name": "CapybaraHermes-v2.5-Mistral-7b", - "Tags": [], - "CreatedAt": 1721224046, - "IsDeleted": false - } - ] -} -``` - -### D. Create a session with the provider -```bash -curl -s -X 'POST' 'http://localhost:8082/blockchain/models//session' \ --H 'accept:application/json' \ --H 'Content-Type: application/json' \ --d '{"sessionDuration": 600}' -``` -Now that the session is open, you can send inference queries to the provider and process responses in usual OpenAI format. -Your Wallet (on https://base.blockscout.com/address/) should show the transaction for the session creation. - -### E. Interact with the provider -* Send the prompt (Standard OpenAI format) with session_id in the header to interact. -* Minimally, you need to provide the `content` and `role` in the messages block and (currently) `"stream":true` for the remote prompt to work. -```bash -curl -X 'POST' \ - 'http://localhost:8082/v1/chat/completions' \ - -H 'accept: application/json' \ - -H 'session_id: ' \ - -H 'Content-Type: application/json' \ - -d '{ - "messages": [ - { - "content": "tell me a joke", - "role": "user" - } - ], - "stream": true - }' -``` - - -### Quick and Dirty Sample: -`curl -X 'POST' 'http://localhost:8082/blockchain/approve?spender=0x6aBE1d282f72B474E54527D93b979A4f64d3030a&amount=3' -H 'accept: application/json' -d ''` - # approves the smart contract to spend 3 MOR tokens on your behalf - -`curl -s -X 'GET' 'http://localhost:8082/wallet' -H 'accept: application/json' | jq .address` - # returns the wallet ID (confirm that it matches your wallet) - -`curl -s -X 'GET' 'http://localhost:8082/blockchain/models' -H 'accept: application/json' | jq -r '.models[] | "\(.Id), \(.Name)"'` - # returns model ID and Name ... copy the ID for the next step `0x84b6df5c84e1e6ae59c90e1639e3e77148d140065ef2cd4fba7f41cc7440e2c5` - -`curl -s -X 'POST' 'http://localhost:8082/blockchain/models/0x84b6df5c84e1e6ae59c90e1639e3e77148d140065ef2cd4fba7f41cc7440e2c5/session' -H 'accept:application/json' -H 'Content-Type: application/json' -d '{"sessionDuration": 600}' | jq .sessionId` - # returns the session ID ... copy the ID for the next step `0x089111479fa2847106b4f7b17eace2e9b37e0d3c0db331b4e01a6e24de827477` - -```bash -curl -X 'POST' \ - 'http://localhost:8082/v1/chat/completions' \ - -H 'accept: application/json' \ - -H 'session_id: 0x089111479fa2847106b4f7b17eace2e9b37e0d3c0db331b4e01a6e24de827477' \ - -H 'Content-Type: application/json' \ - -d '{ - "messages": [ - { - "content": "tell me a joke", - "role": "user" - } - ], - "stream": true - }' -``` -#### Sample Output: -``` -data: {"id":"chatcmpl-8wtgv86nUWMJneEObprWKXcWKX81PAAo","object":"chat.completion.chunk","created":1721758293,"model":"llama2","choices":[{"index":0,"delta":{"content":"Why"},"finish_reason":null,"content_filter_results":{"hate":{"filtered":false},"self_harm":{"filtered":false},"sexual":{"filtered":false},"violence":{"filtered":false}}}]} -data: {"id":"chatcmpl-8wtgv86nUWMJneEObprWKXcWKX81PAAo","object":"chat.completion.chunk","created":1721758293,"model":"llama2","choices":[{"index":0,"delta":{"content":" don"},"finish_reason":null,"content_filter_results":{"hate":{"filtered":false},"self_harm":{"filtered":false},"sexual":{"filtered":false},"violence":{"filtered":false}}}]} -data: {"id":"chatcmpl-8wtgv86nUWMJneEObprWKXcWKX81PAAo","object":"chat.completion.chunk","created":1721758293,"model":"llama2","choices":[{"index":0,"delta":{"content":"'"},"finish_reason":null,"content_filter_results":{"hate":{"filtered":false},"self_harm":{"filtered":false},"sexual":{"filtered":false},"violence":{"filtered":false}}}]} -data: {"id":"chatcmpl-8wtgv86nUWMJneEObprWKXcWKX81PAAo","object":"chat.completion.chunk","created":1721758293,"model":"llama2","choices":[{"index":0,"delta":{"content":"t"},"finish_reason":null,"content_filter_results":{"hate":{"filtered":false},"self_harm":{"filtered":false},"sexual":{"filtered":false},"violence":{"filtered":false}}}]} -data: {"id":"chatcmpl-8wtgv86nUWMJneEObprWKXcWKX81PAAo","object":"chat.completion.chunk","created":1721758293,"model":"llama2","choices":[{"index":0,"delta":{"content":" scientists"},"finish_reason":null,"content_filter_results":{"hate":{"filtered":false},"self_harm":{"filtered":false},"sexual":{"filtered":false},"violence":{"filtered":false}}}]} -data: {"id":"chatcmpl-8wtgv86nUWMJneEObprWKXcWKX81PAAo","object":"chat.completion.chunk","created":1721758293,"model":"llama2","choices":[{"index":0,"delta":{"content":" trust"},"finish_reason":null,"content_filter_results":{"hate":{"filtered":false},"self_harm":{"filtered":false},"sexual":{"filtered":false},"violence":{"filtered":false}}}]} -data: {"id":"chatcmpl-8wtgv86nUWMJneEObprWKXcWKX81PAAo","object":"chat.completion.chunk","created":1721758293,"model":"llama2","choices":[{"index":0,"delta":{"content":" atoms"},"finish_reason":null,"content_filter_results":{"hate":{"filtered":false},"self_harm":{"filtered":false},"sexual":{"filtered":false},"violence":{"filtered":false}}}]} -data: {"id":"chatcmpl-8wtgv86nUWMJneEObprWKXcWKX81PAAo","object":"chat.completion.chunk","created":1721758294,"model":"llama2","choices":[{"index":0,"delta":{"content":"?"},"finish_reason":null,"content_filter_results":{"hate":{"filtered":false},"self_harm":{"filtered":false},"sexual":{"filtered":false},"violence":{"filtered":false}}}]} -data: {"id":"chatcmpl-8wtgv86nUWMJneEObprWKXcWKX81PAAo","object":"chat.completion.chunk","created":1721758294,"model":"llama2","choices":[{"index":0,"delta":{"content":"\n"},"finish_reason":null,"content_filter_results":{"hate":{"filtered":false},"self_harm":{"filtered":false},"sexual":{"filtered":false},"violence":{"filtered":false}}}]} -data: {"id":"chatcmpl-8wtgv86nUWMJneEObprWKXcWKX81PAAo","object":"chat.completion.chunk","created":1721758294,"model":"llama2","choices":[{"index":0,"delta":{"content":"\n"},"finish_reason":null,"content_filter_results":{"hate":{"filtered":false},"self_harm":{"filtered":false},"sexual":{"filtered":false},"violence":{"filtered":false}}}]} -data: {"id":"chatcmpl-8wtgv86nUWMJneEObprWKXcWKX81PAAo","object":"chat.completion.chunk","created":1721758294,"model":"llama2","choices":[{"index":0,"delta":{"content":"Because"},"finish_reason":null,"content_filter_results":{"hate":{"filtered":false},"self_harm":{"filtered":false},"sexual":{"filtered":false},"violence":{"filtered":false}}}]} -data: {"id":"chatcmpl-8wtgv86nUWMJneEObprWKXcWKX81PAAo","object":"chat.completion.chunk","created":1721758294,"model":"llama2","choices":[{"index":0,"delta":{"content":" they"},"finish_reason":null,"content_filter_results":{"hate":{"filtered":false},"self_harm":{"filtered":false},"sexual":{"filtered":false},"violence":{"filtered":false}}}]} -data: {"id":"chatcmpl-8wtgv86nUWMJneEObprWKXcWKX81PAAo","object":"chat.completion.chunk","created":1721758294,"model":"llama2","choices":[{"index":0,"delta":{"content":" make"},"finish_reason":null,"content_filter_results":{"hate":{"filtered":false},"self_harm":{"filtered":false},"sexual":{"filtered":false},"violence":{"filtered":false}}}]} -data: {"id":"chatcmpl-8wtgv86nUWMJneEObprWKXcWKX81PAAo","object":"chat.completion.chunk","created":1721758294,"model":"llama2","choices":[{"index":0,"delta":{"content":" up"},"finish_reason":null,"content_filter_results":{"hate":{"filtered":false},"self_harm":{"filtered":false},"sexual":{"filtered":false},"violence":{"filtered":false}}}]} -data: {"id":"chatcmpl-8wtgv86nUWMJneEObprWKXcWKX81PAAo","object":"chat.completion.chunk","created":1721758294,"model":"llama2","choices":[{"index":0,"delta":{"content":" everything"},"finish_reason":null,"content_filter_results":{"hate":{"filtered":false},"self_harm":{"filtered":false},"sexual":{"filtered":false},"violence":{"filtered":false}}}]} -data: {"id":"chatcmpl-8wtgv86nUWMJneEObprWKXcWKX81PAAo","object":"chat.completion.chunk","created":1721758294,"model":"llama2","choices":[{"index":0,"delta":{"content":"!"},"finish_reason":null,"content_filter_results":{"hate":{"filtered":false},"self_harm":{"filtered":false},"sexual":{"filtered":false},"violence":{"filtered":false}}}]} -data: {"id":"chatcmpl-8wtgv86nUWMJneEObprWKXcWKX81PAAo","object":"chat.completion.chunk","created":1721758294,"model":"llama2","choices":[{"index":0,"delta":{"content":"\u003c|im_end|\u003e"},"finish_reason":null,"content_filter_results":{"hate":{"filtered":false},"self_harm":{"filtered":false},"sexual":{"filtered":false},"violence":{"filtered":false}}}]} -data: {"id":"chatcmpl-8wtgv86nUWMJneEObprWKXcWKX81PAAo","object":"chat.completion.chunk","created":1721758294,"model":"llama2","choices":[{"index":0,"delta":{},"finish_reason":"stop","content_filter_results":{"hate":{"filtered":false},"self_harm":{"filtered":false},"sexual":{"filtered":false},"violence":{"filtered":false}}}]} -``` - - diff --git a/docs/rating-config.json.md b/docs/rating-config.json.md deleted file mode 100644 index e1fa572e..00000000 --- a/docs/rating-config.json.md +++ /dev/null @@ -1,27 +0,0 @@ -# Information about rating-config.json configuration file - -This file configures rating system of proxy-router, that is responsible for provider selection. The file should be placed in the root directory of the project. - -- `providerAllowlist` - the list of providers that are allowed to be used by the proxy-router. Keep it empty to allow all providers. - - `"providerAllowlist": ["0x0000000000000000000000000000000000000000"]` will only allow the local, default model to be used -- `algorithm` - the algorithm used for rating calculation. -- `params` - algorithm parameters, like weights for different metrics. Each algorithm has its own set of parameters. - -Please refer to the json schema for the full list of available fields. - -```json -{ - "$schema": "./internal/rating/rating-config-schema.json", - "algorithm": "default", - "providerAllowlist": [], - "params": { - "weights": { - "tps": 0.24, - "ttft": 0.08, - "duration": 0.24, - "success": 0.32, - "stake": 0.12 - } - } -} -``` diff --git a/docs/reference/api-auth.mdx b/docs/reference/api-auth.mdx new file mode 100644 index 00000000..33d13597 --- /dev/null +++ b/docs/reference/api-auth.mdx @@ -0,0 +1,152 @@ +--- +title: "API authentication" +description: "How the proxy-router authenticates HTTP API callers: the .cookie file, proxy.conf, rpcauth/rpcwhitelist, and the /auth/users endpoints." +audience: ["consumer", "prosumer", "provider-full", "provider-resale", "developer"] +product: ["proxy-router"] +last_verified: "v7.0.0" +source: "docs/02.5-api-auth.md" +--- + +API access requires authentication and network access. This was introduced in main release `2.0.0` (and dev/test `1.6.1`) to: +1. Prevent unauthorized access to the API and the wallet in case of network or firewall mis-configuration. +2. Enable governed access for AI agents — agents should have **scoped** access to the API, not full admin. + +## Files involved + +| File | Default location | Purpose | +|------|------------------|---------| +| `.cookie` | proxy-router binary directory | Admin username/password | +| `proxy.conf` | proxy-router binary directory | All users + per-user method whitelists | + +Override paths via env vars: + +| Var | Effect | +|-----|--------| +| `COOKIE_FILE_PATH` | Where to read/write the `.cookie` file | +| `AUTH_CONFIG_FILE_PATH` | Where to read/write `proxy.conf` | + +## Cookie file + +When the cookie file does not exist, the proxy-router auto-generates one: + +``` +admin:JJLRNze08ZN3vlNdgwgbrh6c4dRw9gQT +``` + +- `admin` is the administrator username. +- The trailing string is a randomly generated password. + +## Proxy configuration file + +`proxy.conf` stores user credentials (`rpcauth=`) and permission whitelists (`rpcwhitelist=`): + +``` +rpcauth=admin:e13576ba0e96bd69f71317c75a06c6f8$cc56ee41055c65b184a34aa5e953d2d069626ce061dd56e22337d2e73804c35c +rpcwhitelist=admin:* +rpcwhitelistdefault=0 +``` + +| Line | Meaning | +|------|---------| +| `rpcauth=:$` | Username with salted, hashed password | +| `rpcwhitelist=:` | Allowed methods. `*` = all permitted | +| `rpcwhitelistdefault=0` | `0` = only whitelisted methods allowed; `1` = all allowed unless restricted | + +### Adding a scoped user + +``` +rpcauth=admin:e13576ba0e96bd69f71317c75a06c6f8$cc56ee41055c65b184a34aa5e953d2d069626ce061dd56e22337d2e73804c35c +rpcauth=agent:ad7a18621d37167502f29712ffc5f324$c056e5f7aa94f6e48c88c81973dc280d16436c1f7bc3c8bded090ae8ea8fc121 +rpcwhitelist=agent:get_balance +rpcwhitelist=admin:* +rpcwhitelistdefault=0 +``` + +The `agent` user can only call `get_balance`. The `admin` user retains full access. + +## HTTP endpoints to manage users + +Both endpoints require **Basic Auth** (administrator credentials). + +### Add or update a user + +`POST /auth/users` — `application/json` + +```http +POST /auth/users +Authorization: Basic YWRtaW46SkpMUk56ZTA4Wk4zdmxOZGd3Z2JyaDZjNGRSdzlnUVQ= +Content-Type: application/json + +{ + "username": "agent", + "password": "agentPassword", + "methods": ["get_balance"] +} +``` + +### Remove a user + +`DELETE /auth/users` — `application/json` + +```http +DELETE /auth/users +Authorization: Basic YWRtaW46SkpMUk56ZTA4Wk4zdmxOZGd3Z2JyaDZjNGRSdzlnUVQ= +Content-Type: application/json + +{ + "username": "agent" +} +``` + +## Authorization header + +All endpoints require: + +``` +Authorization: Basic +``` + +For example, `YWRtaW46SkpMUk56ZTA4Wk4zdmxOZGd3Z2JyaDZjNGRSdzlnUVQ=` decodes to `admin:JJLRNze08ZN3vlNdgwgbrh6c4dRw9gQT`. + +## Permission methods + +These method names are recognized in `rpcwhitelist=` entries (e.g. `rpcwhitelist=agent:get_balance,get_transactions`). Set `rpcwhitelistdefault=1` to allow them by default unless restricted. + +``` +get_balance +get_transactions +get_allowance +get_latest_block +approve +send_eth +send_mor +get_providers +create_provider +delete_provider +get_models +create_model +delete_model +create_bid +get_bids +delete_bids +get_sessions +session_provider_claim +open_session +close_session +get_budget +get_supply +system_config +add_user +remove_user +initiate_session +chat +get_local_models +get_chat_history +edit_chat_history +``` + +## Recommendations + +- For **prosumer / agent** setups, add **per-agent users with restricted whitelists** — never share the admin password with agents. +- For **TEE / SecretVM** deployments, set `COOKIE_CONTENT=admin:` in your encrypted env so the `.cookie` is seeded from secrets. +- Rotate the admin password regularly. Keep `proxy.conf` out of version control. diff --git a/docs/reference/api-direct.mdx b/docs/reference/api-direct.mdx new file mode 100644 index 00000000..8e727db8 --- /dev/null +++ b/docs/reference/api-direct.mdx @@ -0,0 +1,131 @@ +--- +title: "API direct (curl walkthrough)" +description: "End-to-end consumer flow using only the proxy-router HTTP API: approve, query, open session, prompt." +audience: ["consumer", "prosumer", "developer"] +product: ["proxy-router"] +last_verified: "v7.0.0" +source: "docs/proxy-router-api-direct.md" +--- + +This is the curl-only path through Morpheus — no MorpheusUI, no CLI. Useful for developers, scripts, or agent frameworks. + +## Pre-requisites + +- A consumer-side proxy-router running locally with a funded wallet. See [Install from source](/consumers/install-from-source) or [C-Node setup](/prosumers/c-node-setup). +- BasicAuth credentials. The default `admin` lives in `.cookie`. See [API auth](/reference/api-auth). + +## TL;DR + + + Once per wallet, or when allowance is depleted. + Per session: list models, pick a `modelId`. + Per session: `POST /blockchain/models/:id/session`. + Send completions with the `session_id` header. + + +## A. Authorize the contract + +```bash +curl -X POST \ + 'http://localhost:8082/blockchain/approve?spender=0x6aBE1d282f72B474E54527D93b979A4f64d3030a&amount=3' \ + -H 'Authorization: Basic ' \ + -H 'accept: application/json' -d '' +``` + +This authorizes the Diamond contract to spend up to `3` MOR on your behalf. + +## B. Query for a model + +```bash +curl -X GET 'http://localhost:8082/wallet' \ + -H 'Authorization: Basic ' \ + -H 'accept: application/json' + +curl -X GET 'http://localhost:8082/blockchain/models' \ + -H 'Authorization: Basic ' \ + -H 'accept: application/json' +``` + +Sample response: + +```json +{ + "models": [ + { + "Id": "0x6a4813e866a48da528c533e706344ea853a1d3f21e37b4c8e7ffd5ff25779018", + "Name": "llama2:7b", + "Tags": [], + "Owner": "0x0eb467381abbc5b71f275df0c8a4e0ed8561f46f", + "IsDeleted": false + } + ] +} +``` + +Pick an `Id` for the next step. + +## C. Open a session + +```bash +curl -s -X POST \ + 'http://localhost:8082/blockchain/models//session' \ + -H 'Authorization: Basic ' \ + -H 'accept: application/json' \ + -H 'Content-Type: application/json' \ + -d '{"sessionDuration": 600}' +``` + +The transaction will appear at `https://base.blockscout.com/address/`. + +## D. Prompt + +```bash +curl -X POST 'http://localhost:8082/v1/chat/completions' \ + -H 'Authorization: Basic ' \ + -H 'accept: application/json' \ + -H 'session_id: ' \ + -H 'Content-Type: application/json' \ + -d '{ + "messages": [{"role":"user","content":"tell me a joke"}], + "stream": true + }' +``` + +OpenAI-compatible SSE response. + +## Quick-and-dirty one-liner + +```bash +SPENDER=0x6aBE1d282f72B474E54527D93b979A4f64d3030a +AUTH='Authorization: Basic ' + +curl -s -X POST "http://localhost:8082/blockchain/approve?spender=$SPENDER&amount=3" -H "$AUTH" -d '' + +curl -s 'http://localhost:8082/wallet' -H "$AUTH" | jq .address + +curl -s 'http://localhost:8082/blockchain/models' -H "$AUTH" \ + | jq -r '.models[] | "\(.Id), \(.Name)"' + +# Pick a modelId +MODEL=0x84b6df5c84e1e6ae59c90e1639e3e77148d140065ef2cd4fba7f41cc7440e2c5 + +SESSION=$(curl -s -X POST "http://localhost:8082/blockchain/models/$MODEL/session" \ + -H "$AUTH" -H 'Content-Type: application/json' \ + -d '{"sessionDuration":600}' | jq -r .sessionId) + +curl -X POST 'http://localhost:8082/v1/chat/completions' \ + -H "$AUTH" -H "session_id: $SESSION" -H 'Content-Type: application/json' \ + -d '{"messages":[{"role":"user","content":"tell me a joke"}],"stream":true}' +``` + +## Sample streaming output (truncated) + +``` +data: {"choices":[{"delta":{"content":"Why"}}]} +data: {"choices":[{"delta":{"content":" don"}}]} +data: {"choices":[{"delta":{"content":"'"}}]} +... +data: {"choices":[{"delta":{},"finish_reason":"stop"}]} +``` + +For full request/response schemas across endpoints, see [API endpoints](/reference/api-endpoints) or [`proxy-router/docs/swagger.yaml`](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/blob/main/proxy-router/docs/swagger.yaml). diff --git a/docs/reference/api-endpoints.mdx b/docs/reference/api-endpoints.mdx new file mode 100644 index 00000000..7a747c5f --- /dev/null +++ b/docs/reference/api-endpoints.mdx @@ -0,0 +1,202 @@ +--- +title: "API endpoints (selected)" +description: "Hand-picked, prose-explained endpoints of the proxy-router HTTP API. Full schema lives in the repo at proxy-router/docs/swagger.yaml." +audience: ["developer", "prosumer", "provider-full", "provider-resale"] +product: ["proxy-router"] +last_verified: "v7.0.0" +source: "docs/proxy-router-api-endpoints.md" +--- + +This page gives prose context for the endpoints integrators reach for first when calling **the proxy-router HTTP API** (i.e. the API your local node exposes on `:8082`). The complete schema lives at [`proxy-router/docs/swagger.yaml`](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/blob/main/proxy-router/docs/swagger.yaml) and is browsable at `http://localhost:8082/swagger/index.html` when your node is running. + + +If you're looking for the **hosted** OpenAI-compatible Morpheus product (no node required), that is a separate service — see [Inference API overview](/inference-api/overview) and [apidocs.mor.org](https://apidocs.mor.org). + + +## Authentication + +All endpoints require **Basic Authentication**: + +``` +Authorization: Basic +``` + +See [API auth](/reference/api-auth). + +--- + +## Chat completions + +`POST /v1/chat/completions` + +OpenAI-compatible chat. The request body is forwarded to the provider; you don't need a `model` field — it's set by the provider based on `session_id`. + +| Header | Purpose | +|--------|---------| +| `session_id` (hex32) | Required for remote provider routing | + +```bash +curl --location 'http://localhost:8084/v1/chat/completions' \ + --header 'Accept: application/json' \ + --header 'session_id: 0x8e12df2f764b416c0ea1936a253c2a4be01005651c2d73f22dd0d72520f93ca1' \ + --header 'Content-Type: application/json' \ + --header 'Authorization: Basic YWRtaW46YWRtaW4=' \ + --data '{ + "messages": [ + {"role": "system", "content": "You are a helpful assistant."}, + {"role": "user", "content": "Tell me about AI."} + ], + "stream": false, + "max_tokens": 2048 + }' +``` + +Response: `200 OK`, `text/event-stream` (streaming) or `application/json`. + +--- + +## Audio transcriptions + +`POST /v1/audio/transcriptions` + +`multipart/form-data`. The body is forwarded — any field the provider accepts will pass through. Common fields: + +| Field | Notes | +|-------|-------| +| `file` | Audio file | +| `s3_presigned_url` | Pre-signed URL for secure file access | +| `language` | | +| `response_format` | `json` / `text` / `srt` / `verbose_json` / `vtt` | +| `timestamp_granularities[]` | `word` / `segment` | +| `output_content` | | +| `enable_diarization` | Boolean | + +```bash +curl --location 'http://localhost:8084/v1/audio/transcriptions' \ + --header 'session_id: 0x9fe60aa88c4e8d44414431dd565353efb762a923d639f54f856b3ac657e16263' \ + --header 'Authorization: Basic YWRtaW46YWRtaW4=' \ + --form 'file=@"/path/to/harvard.wav"' +``` + +--- + +## Audio speech (TTS) + +`POST /v1/audio/speech` + +JSON. Common fields: `input` (required), `voice`, `response_format` (`mp3`/`opus`/`aac`/`flac`/`wav`/`pcm`; default `mp3`), `speed`. + +```bash +curl --location 'http://localhost:8085/v1/audio/speech' \ + --header 'session_id: 0xf38101fbd00ed4db25444e9d9a65b737d4cd3d464da3aeb118b749c10ee48b10' \ + --header 'Content-Type: application/json' \ + --header 'Authorization: Basic YWRtaW46YWRtaW4=' \ + --data '{"input": "Lorem ipsum dolor sit amet.", "voice": "af_alloy"}' +``` + +--- + +## Embeddings + +`POST /v1/embeddings` + +```bash +curl --location 'http://localhost:8084/v1/embeddings' \ + --header 'session_id: 0xbd5585da9c1e62b4ac89152e7770cdc2779400afa181f831484c60aabc2422f4' \ + --header 'Content-Type: application/json' \ + --header 'Authorization: Basic YWRtaW46YWRtaW4=' \ + --data '{ "encoding_format": "float", "input": "The quick brown fox..." }' +``` + +--- + +## Get providers + +`GET /blockchain/providers` + +Query params: `offset`, `limit`, `order`. + +```bash +curl --location 'http://localhost:8082/blockchain/providers' \ + --header 'Authorization: Basic YWRtaW46YWRtaW4=' +``` + +--- + +## Get models + +`GET /blockchain/models` + +`ModelType` is one of `LLM`, `STT`, `TTS`, `EMBEDDING`, `UNKNOWN`. Use it to choose the appropriate endpoint family. Full sample response in [`proxy-router/docs/swagger.yaml`](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/blob/main/proxy-router/docs/swagger.yaml). + +--- + +## Open session by model ID + +`POST /blockchain/models/:id/session` + +| Body field | Required | Notes | +|------------|----------|-------| +| `sessionDuration` | yes | Seconds | +| `directPayment` | optional | | +| `failover` | optional | | + +```bash +curl --location 'http://localhost:8084/blockchain/models/0xe086adc275c99e32bb10b0aff5e8bfc391aad18cbb184727a75b2569149425c6/session' \ + --header 'Content-Type: application/json' \ + --header 'Authorization: Basic YWRtaW46YWRtaW4=' \ + --data '{ "sessionDuration": 600, "failover": false, "directPayment": false }' +``` + +Response includes `sessionID`. + +--- + +## Close session + +`POST /blockchain/sessions/:id/close` + +```bash +curl --location 'http://localhost:8084/blockchain/sessions/0xf343b654cc8a21d0666c38606146ae68ef67b4445643deba02991a72f0d09785/close' \ + --header 'Content-Type: application/json' \ + --header 'Authorization: Basic YWRtaW46YWRtaW4=' \ + --data '{}' +``` + +Response includes the on-chain transaction hash. + +**Note on refunds:** on **natural expiration** (`closedAt >= endsAt`) your full share is `safeTransfer`'d back to your wallet inside this same transaction. On **early close** a slice may be parked in `userStakesOnHold` with a 1-day timelock — you must call `withdrawUserStakes` (below) after the timelock to receive it. See [Sessions: stake, close, claim](/concepts/sessions-stake-close-recover) for full mechanics. + +--- + +## List sessions for a wallet + +`GET /blockchain/sessions/user?user=0x…&offset=0&limit=20&order=desc` + +```bash +curl --location -u 'admin:admin' \ + 'http://localhost:8082/blockchain/sessions/user?user=0xYOUR_WALLET&offset=0&limit=20&order=desc' +``` + +Variant for IDs only: `GET /blockchain/sessions/user/ids?user=0x…`. Fetch one: `GET /blockchain/sessions/0x`. + +--- + +## Claim early-close on-hold balance (no node HTTP route) + +There is **no proxy-router HTTP route** for `withdrawUserStakes` today. You send a transaction to the Diamond (Inference) contract on Base directly: + +```bash +cast send 0x6aBE1d282f72B474E54527D93b979A4f64d3030a \ + "withdrawUserStakes(address,uint8)" 0xYOUR_WALLET 20 \ + --rpc-url https://mainnet.base.org \ + --private-key "$PRIVATE_KEY_OF_DELEGATEE" +``` + +Function selector: `0xa98a7c6b`. The caller must be the delegatee allowed for that consumer (usually the same key your consumer node uses). `iterations_` (e.g. `20`) caps how many releasable on-hold rows to process per call. Read on-hold balance via `getUserStakesOnHold(addr, iterations_)` — see [Where is my MOR? → Bucket 2](/ai/where-is-my-mor#bucket-2-on-hold-queue-early-close-timelock). + +--- + +## Full schema + +The complete OpenAPI schema lives at [`proxy-router/docs/swagger.yaml`](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/blob/main/proxy-router/docs/swagger.yaml). When your proxy-router is running, the same spec is browsable interactively at `http://localhost:8082/swagger/index.html`. diff --git a/docs/reference/api-overview.mdx b/docs/reference/api-overview.mdx new file mode 100644 index 00000000..ca7b3ef2 --- /dev/null +++ b/docs/reference/api-overview.mdx @@ -0,0 +1,61 @@ +--- +title: "API overview" +description: "How to talk to the proxy-router HTTP API: ports, auth, schema sources, and where to look up endpoints." +audience: ["consumer", "prosumer", "provider-full", "provider-resale", "developer"] +product: ["proxy-router"] +last_verified: "v7.0.0" +--- + +The proxy-router exposes an OpenAI-compatible HTTP API plus Morpheus-specific routes for blockchain operations and node management. + +## Surface + +This page documents the **proxy-router HTTP API** — the local API exposed by the proxy-router binary in this repo. It is **not** the hosted Morpheus Inference API; that is a separate product at [apidocs.mor.org](https://apidocs.mor.org), described in [Inference API overview](/inference-api/overview). + +| Surface | URL (default) | Purpose | +|---------|---------------|---------| +| Local API | `http://localhost:8082` | All proxy-router HTTP endpoints (auth-protected) | +| Swagger UI | `http://localhost:8082/swagger/index.html` | Interactive request playground served by your own proxy-router | +| Public proxy | `tcp://:3333` | TCP tunnel for consumer ↔ provider sessions | +| TEE attestation | `https://:29343` | TDX attestation (`/cpu`, `/gpu`, `/docker-compose`) | + +## Authentication + +All endpoints require **HTTP Basic Auth**: + +``` +Authorization: Basic +``` + +The `.cookie` file in your proxy-router directory has the default `admin:`. Add scoped users via `proxy.conf` and the `/auth/users` endpoints. Full reference: [API auth](/reference/api-auth). + +## Where the schema lives + +The canonical OpenAPI schema for the proxy-router HTTP API is [`proxy-router/docs/swagger.yaml`](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/blob/main/proxy-router/docs/swagger.yaml), auto-generated by `swag init` as part of every release build. When you run the proxy-router locally, browse it at `http://localhost:8082/swagger/index.html`. For a curated subset of the most-used endpoints with prose context, see [API endpoints](/reference/api-endpoints). + +## Endpoint families + + + + `/v1/chat/completions`, `/v1/embeddings`, `/v1/audio/transcriptions`, `/v1/audio/speech`. + + + `GET /blockchain/providers`, `GET /blockchain/models`, `GET /blockchain/bids`. + + + `POST /blockchain/providers`, `POST /blockchain/models`, `POST /blockchain/bids`. + + + `POST /blockchain/models/:id/session`, `POST /blockchain/sessions/:id/close`. + + + `GET /wallet`, `GET /blockchain/balance`, `POST /blockchain/approve`. + + + `POST /auth/users`, `DELETE /auth/users`. + + + +## Direct vs UI + +Most users go through MorpheusUI or the CLI; both call this API underneath. For headless scripts and agents, see [API direct](/reference/api-direct) for a curl-only walkthrough. diff --git a/docs/reference/env-proxy-router.mdx b/docs/reference/env-proxy-router.mdx new file mode 100644 index 00000000..57468288 --- /dev/null +++ b/docs/reference/env-proxy-router.mdx @@ -0,0 +1,223 @@ +--- +title: "Env: proxy-router" +description: "Every environment variable consumed by the proxy-router, with mainnet/testnet defaults and explicit precedence rules where two variables overlap." +audience: ["provider-full", "provider-resale", "prosumer", "developer"] +product: ["proxy-router"] +last_verified: "v7.0.0" +source: "docs/proxy-router.all.env" +--- + +The proxy-router is configured through `.env` (or container env vars). This page documents every variable. The canonical `.env.example` lives in the repo at [`proxy-router/.env.example`](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/blob/main/proxy-router/.env.example) and the full annotated dump at [`docs/proxy-router.all.env`](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/blob/main/docs/proxy-router.all.env). + + +Defaults below are from the source of truth (`proxy-router/internal/config/config.go`). When in doubt, the source wins. + + +## Conflicting / overlapping variables — read this first + +Several pairs of variables look like they do "the same thing." They don't. The proxy-router resolves each pair with a specific precedence rule, and getting it wrong is a common cause of "I changed the env but nothing happened." + + +For every `*_CONTENT` ↔ `*_PATH` pair below, the **`*_CONTENT`** variable is a **one-shot file seeder**, not a runtime override. It only takes effect when the corresponding file **does not exist**. After the first successful start the file exists, and changing the `*_CONTENT` env on subsequent runs has **no effect** until you delete the file at `*_PATH`. + + +### `COOKIE_FILE_PATH` ↔ `COOKIE_CONTENT` + +| Situation | What the proxy-router does | +|-----------|---------------------------| +| File at `COOKIE_FILE_PATH` already exists | Reads the file. **`COOKIE_CONTENT` is silently ignored.** | +| File does not exist + `COOKIE_CONTENT` is set | Writes `COOKIE_CONTENT` to the file (`username:password\n`), then reads it. | +| File does not exist + `COOKIE_CONTENT` is unset | Generates a random 32-char password for `admin`, writes it to the file. | + +Source: [`proxy-router/internal/system/auth.go`](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/blob/main/proxy-router/internal/system/auth.go) (`EnsureConfigFilesExist`). + +**Practical implications** + +- For TEE / Akash / ephemeral container deployments, set `COOKIE_CONTENT` once on first start; the file gets seeded inside the volume and persists. +- To rotate credentials on a self-hosted node, use the **`POST /auth/users` endpoint** (or edit the cookie file in place) — changing `COOKIE_CONTENT` after first start does nothing. + +### `MODELS_CONFIG_PATH` ↔ `MODELS_CONFIG_CONTENT` + +| Situation | What the proxy-router does | +|-----------|---------------------------| +| File at `MODELS_CONFIG_PATH` already exists | Reads the file. **`MODELS_CONFIG_CONTENT` is silently ignored.** | +| File does not exist + `MODELS_CONFIG_CONTENT` is set | Writes `MODELS_CONFIG_CONTENT` to the file, then reads it. | +| File does not exist + `MODELS_CONFIG_CONTENT` is unset | Logs a warning and runs with an empty model registry. | + +Source: [`proxy-router/internal/config/models_config.go`](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/blob/main/proxy-router/internal/config/models_config.go) (`ModelConfigLoader.Init`). + +**Practical implications** + +- Use `MODELS_CONFIG_CONTENT` (single-line JSON) in TEE/Akash deployments where you can't mount a volume. +- To update models on a self-hosted node, edit the JSON file directly and restart — don't bump `MODELS_CONFIG_CONTENT`. See [models-config.json](/reference/models-config). + +### `AGENT_CONFIG_PATH` ↔ `AGENT_CONFIG_CONTENT` + +Same `*_CONTENT`-only-seeds-the-file rule as the two above. Source: [`proxy-router/internal/config/agents_config.go`](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/blob/main/proxy-router/internal/config/agents_config.go). + +### `AUTH_CONFIG_FILE_PATH` (no inline twin) + +Path to `proxy.conf`, which holds `rpcauth=` and `rpcwhitelist=` lines. **There is no `AUTH_CONFIG_CONTENT` env** — the file is built at runtime by the proxy-router itself when you add users via [`POST /auth/users`](/reference/api-auth#add-or-update-a-user). For TEE / ephemeral deployments, `proxy.conf` is created on first start (with the admin entry derived from the cookie file) and managed via the API afterwards. + +### `WALLET_PRIVATE_KEY` ↔ system keychain + +| Situation | What the proxy-router does | +|-----------|---------------------------| +| `WALLET_PRIVATE_KEY` is set | Uses it. The keychain is **not** read. | +| `WALLET_PRIVATE_KEY` is unset and the OS supports a keychain (macOS) | Reads / writes the key from the system keychain. | +| Neither | Refuses to start signing transactions; read-only operations still work. | + +`APP_RESET_KEYCHAIN=true` wipes the macOS keychain entry on start (use with care). + +### `WEB_PUBLIC_URL` fallback + +If `WEB_PUBLIC_URL` is unset, the proxy-router synthesizes `http://localhost:`. For provider deployments where consumers must reach you over the public internet, **always set this explicitly** to your public URL (e.g. `https://provider.example.com`). The TLS-pinning step in TEE attestation reads this URL. + +### `ETH_NODE_USE_SUBSCRIPTIONS` ↔ `ETH_NODE_POLLING_INTERVAL` + +Not a precedence pair, but easy to misconfigure: + +- `ETH_NODE_USE_SUBSCRIPTIONS=true` → expects a **WSS** `ETH_NODE_ADDRESS` (e.g. `wss://...`). Polling interval is irrelevant. +- `ETH_NODE_USE_SUBSCRIPTIONS=false` (default) → expects an **HTTPS** `ETH_NODE_ADDRESS` and uses `ETH_NODE_POLLING_INTERVAL` (default `10` seconds). + +Mismatch (e.g. `subscriptions=true` with HTTPS endpoint) makes the node fail to receive blockchain events even though startup may look healthy. + +### `PROXY_STORE_CHAT_CONTEXT` is TEE-frozen + +In the **`-tee` image** this is hard-coded `false` at build time and **cannot be overridden at runtime**. Setting it in the env has no effect inside a TEE deployment. See [TEE reference](/providers/full/tee-reference). + +--- + +## Application + +| Variable | Default | Notes | +|----------|---------|-------| +| `APP_RESET_KEYCHAIN` | `false` | Set `true` to reset the macOS keychain entry on start | +| `AUTH_CONFIG_FILE_PATH` | `./proxy.conf` | Path to the auth config file (no inline twin) | +| `COOKIE_FILE_PATH` | `./.cookie` | Path to admin cookie file | +| `COOKIE_CONTENT` | (unset) | **Seeds the cookie file on first start only.** See precedence above. | + +## Blockchain + +| Variable | Default | Notes | +|----------|---------|-------| +| `ETH_NODE_CHAIN_ID` | `8453` (mainnet) / `84532` (testnet) | BASE chain ID | +| `ETH_NODE_ADDRESS` | (unset, falls back to built-in public RPC round-robin) | RPC endpoint URL (HTTPS or WSS — must match `ETH_NODE_USE_SUBSCRIPTIONS`). **Set explicitly for any real deployment** — the public round-robin fallback is rate-limited and unreliable; missed events break the node silently. | +| `ETH_NODE_LEGACY_TX` | `false` | Set `true` to disable EIP-1559 | +| `BLOCKSCOUT_API_URL` | `https://base.blockscout.com/api/v2` | Block explorer API | +| `EXPLORER_RETRY_DELAY` | `5` | Delay between explorer retries (seconds) | +| `EXPLORER_MAX_RETRIES` | `5` | Max explorer retries | +| `ETH_NODE_USE_SUBSCRIPTIONS` | `false` | `true` to use WSS subscriptions; `false` for HTTP polling | +| `ETH_NODE_POLLING_INTERVAL` | `10` | Polling interval (seconds, only when `ETH_NODE_USE_SUBSCRIPTIONS=false`) | +| `ETH_NODE_MAX_RECONNECTS` | `30` | Max reconnect attempts | + +## Environment + +| Variable | Default | Notes | +|----------|---------|-------| +| `ENVIRONMENT` | `development` | Use `production` in deployments | + +## Marketplace + +| Variable | Default | Notes | +|----------|---------|-------| +| `DIAMOND_CONTRACT_ADDRESS` | mainnet `0x6aBE1d282f72B474E54527D93b979A4f64d3030a`; testnet `0x6e4d0B775E3C3b02683A6F277Ac80240C4aFF930` | Diamond marketplace contract | +| `MOR_TOKEN_ADDRESS` | mainnet `0x7431aDa8a591C955a994a21710752EF9b882b8e3`; testnet `0x5C80Ddd187054E1E4aBBfFCD750498e81d34FfA3` | MOR ERC-20 token | +| `WALLET_PRIVATE_KEY` | (unset) | Wallet private key. Falls back to system keychain when unset. See precedence above. | + +## Logging + +| Variable | Default | Notes | +|----------|---------|-------| +| `LOG_COLOR` | `false` | Colored console output | +| `LOG_FOLDER_PATH` | (unset) | If set, also write logs to files in this directory | +| `LOG_IS_PROD` | `false` | Production log format | +| `LOG_JSON` | `false` | JSON-formatted log lines | +| `LOG_LEVEL_APP` | `warn` | App-level log level: `debug` `info` `warn` `error` `dpanic` `panic` `fatal` | +| `LOG_LEVEL_TCP` | `warn` | TCP layer log level | +| `LOG_LEVEL_ETH_RPC` | `warn` | Ethereum RPC log level | +| `LOG_LEVEL_STORAGE` | `warn` | Badger storage log level | + +For TEE images logging is **frozen** to production / JSON / minimal at build time — these vars have no effect inside a `-tee` image. + +## Network ports & URLs + +| Variable | Default | Notes | +|----------|---------|-------| +| `WEB_ADDRESS` | `0.0.0.0:8082` | Bind for the HTTP/Swagger API | +| `WEB_PUBLIC_URL` | `http://localhost:` | Public-facing URL of the API. **Set explicitly** for any provider that consumers must reach. | +| `PROXY_ADDRESS` | `0.0.0.0:3333` | Bind for the consumer-to-provider TCP proxy | + +## Proxy state & configs + +| Variable | Default | Notes | +|----------|---------|-------| +| `MAX_CACHED_DESTS` | `5` | Max cached provider destinations | +| `PROXY_STORAGE_PATH` | `./data/badger/` | Local Badger / runtime state | +| `PROXY_STORE_CHAT_CONTEXT` | `true` | Persist chat context. **Frozen `false` in `-tee` images.** | +| `PROXY_FORWARD_CHAT_CONTEXT` | `true` | Prepend stored history to prompts | +| `MODELS_CONFIG_PATH` | `./models-config.json` | See [models-config](/reference/models-config). See precedence above. | +| `MODELS_CONFIG_CONTENT` | (unset) | **Seeds the models config file on first start only.** See precedence above. | +| `AGENT_CONFIG_PATH` | (built-in default) | Local agent registry path | +| `AGENT_CONFIG_CONTENT` | (unset) | **Seeds the agent config file on first start only.** Same rules as the models pair. | +| `RATING_CONFIG_PATH` | `./rating-config.json` | See [rating-config](/reference/rating-config) | + +## Timeouts & retries + +| Variable | Default | Notes | +|----------|---------|-------| +| `LLM_TIMEOUT` | (depends on release) | P-Node → backend LLM timeout (streaming + non-streaming) | +| `CNODE_PNODE_TIMEOUT` | (depends on release) | Per-attempt timeout for C-Node waiting for P-Node first response | +| `CNODE_PNODE_MAX_RETRIES` | (depends on release) | Max retries for C-Node → P-Node read timeout (chat / embeddings) | +| `CNODE_PNODE_AUDIO_MAX_RETRIES` | (depends on release) | Max retries for audio transcription / speech routes | + +For exact defaults check the source of truth ([`config.go`](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/blob/main/proxy-router/internal/config/config.go)) — these can change between releases as we tune the network. + +## TEE (Phase 1 + Phase 2 attestation) + +These are only consulted when at least one model in the marketplace is `tee`-tagged. Otherwise they are unused. + +| Variable | Default | Notes | +|----------|---------|-------| +| `TEE_PORTAL_URL` | `https://secretai.scrtlabs.com/api` | SecretAI Portal used to verify raw TDX CPU quotes | +| `TEE_IMAGE_REPO` | `ghcr.io/morpheusais/morpheus-lumerin-node-tee` | GHCR repo where the consumer-side P-Node attestation fetches the signed golden manifest via cosign | +| `ARTIFACT_REGISTRY_URL` | `https://raw.githubusercontent.com/scrtlabs/secretvm-verify/main/artifacts_registry/tdx.csv` | SecretVM TDX artifact registry CSV (MRTD + RTMR0-2 lookup) | +| `ARTIFACT_REGISTRY_REFRESH_INTERVAL` | `1h` | How often the proxy-router re-downloads the artifact registry | + +See [TEE overview](/concepts/tee-overview) and [TEE reference](/providers/full/tee-reference). + +## System tuning (optional sysctl tweaks) + +These map to OS-level adjustments and only apply when `SYS_ENABLE=true`. + +| Variable | Default | Notes | +|----------|---------|-------| +| `SYS_ENABLE` | `false` | Set `true` to apply the values below at startup | +| `SYS_LOCAL_PORT_RANGE` | `1024 65535` | | +| `SYS_NET_DEV_MAX_BACKLOG` | `100000` | | +| `SYS_RLIMIT_HARD` | `524288` | | +| `SYS_RLIMIT_SOFT` | `524288` | | +| `SYS_SOMAXCONN` | `100000` (Linux) / `2048` (Darwin/macOS) | | +| `SYS_TCP_MAX_SYN_BACKLOG` | `100000` | | + +## Mainnet vs testnet quick switch + +Comment / uncomment the appropriate block in `.env`: + +```bash +# MAINNET +ETH_NODE_CHAIN_ID=8453 +DIAMOND_CONTRACT_ADDRESS=0x6aBE1d282f72B474E54527D93b979A4f64d3030a +MOR_TOKEN_ADDRESS=0x7431aDa8a591C955a994a21710752EF9b882b8e3 +BLOCKSCOUT_API_URL=https://base.blockscout.com/api/v2 + +# TESTNET (Base Sepolia) +# ETH_NODE_CHAIN_ID=84532 +# DIAMOND_CONTRACT_ADDRESS=0x6e4d0B775E3C3b02683A6F277Ac80240C4aFF930 +# MOR_TOKEN_ADDRESS=0x5C80Ddd187054E1E4aBBfFCD750498e81d34FfA3 +# BLOCKSCOUT_API_URL=https://base-sepolia.blockscout.com/api/v2 +``` + +## Full annotated dump + +For the complete annotated reference (every variable, every example value), see [`docs/proxy-router.all.env`](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/blob/main/docs/proxy-router.all.env) in the repo. diff --git a/docs/reference/env-ui-desktop.mdx b/docs/reference/env-ui-desktop.mdx new file mode 100644 index 00000000..80b1e61d --- /dev/null +++ b/docs/reference/env-ui-desktop.mdx @@ -0,0 +1,46 @@ +--- +title: "Env: MorpheusUI" +description: "Environment variables consumed by the MorpheusUI Electron desktop app." +audience: ["consumer", "developer"] +product: ["ui-desktop"] +last_verified: "v7.0.0" +source: "docs/ui-desktop.all.env" +--- + +MorpheusUI configuration lives in `MorpheusUI/.env` (or the equivalent platform-specific resource). The complete annotated dump is at [`docs/ui-desktop.all.env`](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/blob/main/docs/ui-desktop.all.env). Source of truth: `MorpheusUI/src/main/config/index.ts`. + +## Auth & networking + +| Variable | Default | Notes | +|----------|---------|-------| +| `BYPASS_AUTH` | `false` | `true` to bypass auth (dev only) | +| `PROXY_WEB_DEFAULT_PORT` | `8082` | Default port for the local proxy-router | +| `PROXY_WEB_URL` | `http://localhost:8082` | Override the local API URL | + +## Chain + +| Variable | Default | Notes | +|----------|---------|-------| +| `CHAIN_ID` | (unset) | `8453` (mainnet) or `84532` (testnet) | +| `DEFAULT_SELLER_CURRENCY` | `BTC` | Default seller currency symbol | +| `DIAMOND_ADDRESS` | mainnet `0x6aBE1d282f72B474E54527D93b979A4f64d3030a`; testnet `0x6e4d0B775E3C3b02683A6F277Ac80240C4aFF930` | Diamond contract | +| `EXPLORER_URL` | (unset) | Block explorer URL | + +## Branding + +| Variable | Default | Notes | +|----------|---------|-------| +| `DISPLAY_NAME` | `MorpheusUI` | Window/title text | + +## Pairing with a custom proxy-router + +Most consumer setups use the bundled proxy-router that `mor-launch` starts. To point the UI at a separate proxy-router (e.g. a Docker container or a remote C-Node): + +1. Stop the bundled proxy-router (or don't run `mor-launch`). +2. Start your own proxy-router and confirm `http://:8082/healthcheck`. +3. Set `PROXY_WEB_URL=http://:8082` in MorpheusUI's `.env`. +4. Restart MorpheusUI. + +## Full annotated dump + +For every variable (including theme tweaks, debug flags, and feature toggles), see [`docs/ui-desktop.all.env`](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/blob/main/docs/ui-desktop.all.env). diff --git a/docs/reference/glossary.mdx b/docs/reference/glossary.mdx new file mode 100644 index 00000000..0fce9d6f --- /dev/null +++ b/docs/reference/glossary.mdx @@ -0,0 +1,55 @@ +--- +title: "Glossary" +description: "Canonical, agent-friendly definitions of Morpheus terms." +audience: ["consumer", "prosumer", "provider-full", "provider-resale", "developer"] +product: ["proxy-router", "ui-desktop"] +last_verified: "v7.0.0" +--- + +LLM-friendly definitions — short, opinionated, and consistent across the rest of the docs. If a term here disagrees with anything elsewhere on this site, the rest of the site is wrong; file an issue. + +| Term | Definition | +|------|-----------| +| **Morpheus Inference Marketplace** | The decentralized, peer-to-peer marketplace coordinating consumers and providers on BASE. The conceptual whole. | +| **BASE** | Coinbase's Ethereum L2 rollup. Morpheus settles here. Mainnet chain ID `8453`; Sepolia `84532`. | +| **MOR** | Morpheus marketplace ERC-20 token, used for stake, fees, and session payment. | +| **Compute Node contracts** | The set of smart contracts (Diamond marketplace) that register providers and models, match consumers with providers, and secure the connection. | +| **Diamond contract** | The on-chain Diamond proxy implementing the Compute Node marketplace. Tracks providers, models, bids, and sessions. | +| **Reputation system** | Per-provider performance tracking (uptime, TTFT, throughput, success, stake). Used by the consumer-side proxy-router to bias session routing — see [rating-config](/reference/rating-config). | +| **Session-time pricing** | Pricing model — providers post `pricePerSecond`, not `pricePerToken`. Long contexts and short contexts cost the same per second. | +| **Provider** | An on-chain record representing a node that hosts (or fronts) one or more AI models. Identified by a wallet address. | +| **P-Node** | A "Provider Node" — the proxy-router process running in the provider role. | +| **C-Node** | A "Consumer Node" — the proxy-router process running in the consumer role. | +| **Bid** | An on-chain offer: `(modelId, providerId, pricePerSecond)`. Consumers accept by opening a session. | +| **Session** | A time-boxed contract with escrowed MOR. `openSession` moves stake into the Inference Contract; `closeSession` returns the consumer's share and pays the provider from a separate `fundingAccount`. Natural expiration returns the full share inside one txn; early close may park a slice in `userStakesOnHold`. | +| **Stake** | (1) Consumer: MOR escrowed for a session. (2) Provider: refundable bond a provider must post to register a provider or model. | +| **`userStakesOnHold`** | Per-user array on the Inference Contract that holds early-close timelock entries. Each entry has an amount and `releaseAt = startOfTheDay(closedAt) + 1 day`. Cleared via `withdrawUserStakes`. | +| **`withdrawUserStakes`** | On-chain function (`withdrawUserStakes(address, uint8)`, selector `0xa98a7c6b`) on the Diamond contract that moves past-`releaseAt` rows from `userStakesOnHold` to the user's wallet. **No HTTP route** on the proxy-router. | +| **`fundingAccount`** | Protocol-owned wallet that pays providers inside `closeSession` via `transferFrom`. If empty or under-approved, every `closeSession` fails network-wide. | +| **Natural expiration** | Session close where `closedAt >= endsAt`. Full consumer share returns inside the same `closeSession` transaction. No `userStakesOnHold` row created. | +| **Early close** | User-initiated `closeSession` before `endsAt`. May create a `userStakesOnHold` row alongside the immediate transfer. | +| **Subnet provider** | A provider that has staked `10000` MOR (vs the standard `0.2`) and gets elevated marketplace standing. | +| **Allowance** | Standard ERC-20 approval the consumer / provider grants to the Diamond contract so it can move MOR on their behalf. | +| **proxy-router** | The Go service in this repo. Same binary serves consumer and provider roles; configuration differs. | +| **MorpheusUI** | The Electron desktop UI in this repo. | +| **mor-cli** | The Go CLI client in this repo. | +| **mor-launch** | A small launcher in releases that starts the proxy-router (and optionally `llama.cpp`) plus the UI. | +| **`local` model** | The bundled tinyllama demo model. Started with `mor-launch local`. Not a Morpheus marketplace model. | +| **`tee` tag** | Tag added to a model on chain to engage the two-hop attestation chain (Phase 1 + Phase 2). | +| **`-tee` image** | The hardened proxy-router image (`ghcr.io/morpheusais/morpheus-lumerin-node-tee`) with config baked at build time. | +| **RTMR3** | Intel TDX runtime-measurement register #3. Computed from the rootfs and the deployed compose; the unique fingerprint of the running TEE workload. | +| **Phase 1** | Consumer's proxy-router verifies the provider's P-Node TDX attestation. | +| **Phase 2** | Provider's P-Node verifies its own backend LLM TDX + GPU attestation. | +| **SecretVM** | SCRT Labs' confidential VM platform. Hosts most current TEE-tagged Morpheus providers. | +| **SecretAI portal** | https://secretai.scrtlabs.com — used to verify TEE attestation interactively. | +| **`apidocs.mor.org`** | Documentation for the **Morpheus Inference API** — a separate, hosted, OpenAI-compatible gateway product. It is **not** the proxy-router HTTP API reference. See [Inference API overview](/inference-api/overview). | +| **Inference API / API Gateway** | Hosted OpenAI-compatible HTTPS gateway built on top of Morpheus. Base URL: `https://api.mor.org/api/v1`. Docs at [apidocs.mor.org](https://apidocs.mor.org). For users who don't want to run their own node. | +| **Morpheus Chat App / `app.mor.org`** | Hosted browser-based consumer chat UI, powered by the hosted Inference API Gateway. | +| **`gitbook.mor.org`** | Broader Morpheus documentation hub. Supports an `?ask=` query parameter that returns natural-language answers + sources — useful for AI agents. See [LLM cheatsheet](/ai/llm-prompt-cheatsheet#dynamic-querying-of-the-broader-morpheus-docs). | +| **`active.mor.org`** | Live marketplace state — status, active models, active bids. | +| **`tech.mor.org`** | Calculators, sessions, TEE, throughput explainers. | +| **MyProvider** | Hosted operator GUI at https://myprovider.mor.org for provider management. | +| **NodeNeo** | Cross-platform consumer experience at https://nodeneo.io. | +| **Everclaw** | Agent project at https://everclaw.xyz, with a Morpheus skill for OpenClaw. | +| **`models-config.json`** | Local file mapping on-chain `modelId` → backend `apiUrl`. See [reference](/reference/models-config). | +| **`rating-config.json`** | Local file controlling provider selection weights and allowlists. See [reference](/reference/rating-config). | diff --git a/docs/reference/models-config.mdx b/docs/reference/models-config.mdx new file mode 100644 index 00000000..3829a630 --- /dev/null +++ b/docs/reference/models-config.mdx @@ -0,0 +1,102 @@ +--- +title: "models-config.json" +description: "How the proxy-router maps on-chain model IDs to backend HTTP endpoints, including OpenAI / Anthropic / Prodia / Hyperbolic API types." +audience: ["provider-full", "provider-resale", "developer"] +product: ["proxy-router"] +last_verified: "v7.0.0" +source: "docs/models-config.json.md" +--- + +`models-config.json` tells the proxy-router how to translate on-chain `modelId` values into actual backend HTTP calls. The schema is enforced by [`proxy-router/internal/config/models-config-schema.json`](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/blob/main/proxy-router/internal/config/models-config-schema.json). + +## Per-model fields + +| Field | Required | Notes | +|-------|----------|-------| +| `modelId` | yes | The on-chain model id (32-byte hex) | +| `modelName` | yes | Human-readable name | +| `apiType` | yes | One of `openai`, `claudeai`, `prodia-sd`, `prodia-sdxl`, `prodia-v2`, `hyperbolic-sd`, etc. | +| `apiUrl` | yes | Full backend URL including the endpoint path | +| `apiKey` | optional | Backend API key (resale providers usually need this) | +| `concurrentSlots` | optional | Distinct concurrent chats your backend can handle for **this** model | +| `capacityPolicy` | optional | `idle_timeout` or `simple` | + + +**`concurrentSlots` is per-model, not global.** The proxy-router will accept up to `sum(concurrentSlots)` across all configured models concurrently. There is no built-in global cap. If your hardware can serve only one of N models at a time, register all N models but **only post a bid for the one currently active**, and rotate the bid when you want to switch. See [Pausing or temporarily disabling a model offering](/providers/full/register-onchain#pausing-or-temporarily-disabling-a-model-offering). + +| `parameters` | optional | Per-`apiType` extra parameters (e.g. SD `cfg_scale`, `steps`) | + +For the canonical per-`apiType` schema, see the JSON schema file linked above. + +## Examples + +```json +{ + "$schema": "./internal/config/models-config-schema.json", + "models": [ + { + "modelId": "0x0000000000000000000000000000000000000000000000000000000000000000", + "modelName": "llama2", + "apiType": "openai", + "apiUrl": "http://localhost:8080/v1/chat/completions" + }, + { + "modelId": "0x0000000000000000000000000000000000000000000000000000000000000001", + "modelName": "inference.sdxl.txt2img.v1", + "apiType": "prodia-v2", + "apiUrl": "https://inference.prodia.com/v2/job", + "apiKey": "FILL_ME_IN" + }, + { + "modelId": "0x0000000000000000000000000000000000000000000000000000000000000002", + "modelName": "SDXL1.0-base", + "apiType": "hyperbolic-sd", + "apiUrl": "https://api.hyperbolic.xyz/v1/image/generation", + "apiKey": "FILL_ME_IN", + "parameters": { + "cfg_scale": "5", + "steps": "30" + } + }, + { + "modelId": "0x0000000000000000000000000000000000000000000000000000000000000003", + "modelName": "claude-3-5-sonnet-20241022", + "apiType": "claudeai", + "apiUrl": "https://api.anthropic.com/v1/messages", + "apiKey": "FILL_ME_IN" + }, + { + "modelId": "0x0000000000000000000000000000000000000000000000000000000000000004", + "modelName": "gpt-4o-mini", + "apiType": "openai", + "apiUrl": "https://api.openai.com/v1/chat/completions", + "apiKey": "FILL_ME_IN" + }, + { + "modelId": "0x0000000000000000000000000000000000000000000000000000000000000005", + "modelName": "text-embedding-bge-m3", + "apiType": "openai", + "apiUrl": "https://api.venice.ai/api/v1/embeddings", + "apiKey": "FILL_ME_IN" + }, + { + "modelId": "0x0000000000000000000000000000000000000000000000000000000000000006", + "modelName": "tts-kokoro", + "apiType": "openai", + "apiUrl": "https://api.venice.ai/api/v1/audio/speech", + "apiKey": "FILL_ME_IN" + }, + { + "modelId": "0x0000000000000000000000000000000000000000000000000000000000000007", + "modelName": "whisper-1", + "apiType": "openai", + "apiUrl": "https://api.openai.com/v1/audio/transcriptions", + "apiKey": "FILL_ME_IN" + } + ] +} +``` + +## Inline content (for TEE / Akash) + +For deployments where mounting a JSON file is impractical, set `MODELS_CONFIG_CONTENT` to a **single-line JSON string** with the exact same shape as above. The proxy-router reads it instead of `MODELS_CONFIG_PATH`. This is the standard approach in [TEE](/providers/full/secretvm-quickstart) and [Akash](/providers/full/proxy-router-akash) deployments. diff --git a/docs/reference/rating-config.mdx b/docs/reference/rating-config.mdx new file mode 100644 index 00000000..e7378b0e --- /dev/null +++ b/docs/reference/rating-config.mdx @@ -0,0 +1,78 @@ +--- +title: "rating-config.json" +description: "Configure provider rating, allowlists, and selection weights for consumer proxy-routers." +audience: ["consumer", "prosumer", "developer"] +product: ["proxy-router"] +last_verified: "v7.0.0" +source: "docs/rating-config.json.md" +--- + +`rating-config.json` configures the **rating system** the consumer proxy-router uses when picking which provider to route a session to. It lives in the project root by default; override path via `RATING_CONFIG_PATH`. + +## Fields + +| Field | Notes | +|-------|-------| +| `providerAllowlist` | Array of provider addresses. **Empty** = allow all providers. | +| `algorithm` | Rating algorithm. `default` is the canonical built-in. | +| `params` | Algorithm-specific parameters. For `default`, the `weights` block (see below). | + +The full schema is enforced by [`proxy-router/internal/rating/rating-config-schema.json`](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/blob/main/proxy-router/internal/rating/rating-config-schema.json). + +## Default algorithm weights + +```json +{ + "$schema": "./internal/rating/rating-config-schema.json", + "algorithm": "default", + "providerAllowlist": [], + "params": { + "weights": { + "tps": 0.24, + "ttft": 0.08, + "duration": 0.24, + "success": 0.32, + "stake": 0.12 + } + } +} +``` + +| Weight | Meaning | +|--------|---------| +| `tps` | Tokens per second | +| `ttft` | Time to first token | +| `duration` | Session duration / stability | +| `success` | Successful completions over total | +| `stake` | Provider's posted stake | + +Weights must sum to `1.0`. + +## Restricting to specific providers + +To only allow the local default model: + +```json +{ + "providerAllowlist": ["0x0000000000000000000000000000000000000000"] +} +``` + +To prefer a curated set, list their on-chain addresses (lower-case `0x...`). An empty array allows all. + +## Practical patterns + + + + Boost `ttft` and `tps`, lower `stake`. + + + Boost `success` and `duration`, lower `tps`. + + + Pair with a low `pricePerSecond` upper bound (currently outside `rating-config`; filter at session-open time). + + + Filter at the `models` layer to `tee`-tagged models; rating then operates over TEE providers only. + + diff --git a/docs/reference/troubleshooting.mdx b/docs/reference/troubleshooting.mdx new file mode 100644 index 00000000..97351252 --- /dev/null +++ b/docs/reference/troubleshooting.mdx @@ -0,0 +1,117 @@ +--- +title: "Troubleshooting" +description: "Common failure modes for the proxy-router and MorpheusUI, with diagnostics and fixes." +audience: ["consumer", "prosumer", "provider-full", "provider-resale", "developer"] +product: ["proxy-router", "ui-desktop"] +last_verified: "v7.0.0" +source: "docs/99-troubleshooting.md" +--- + +The single most important rule: **MorpheusUI / Swagger / CLI all depend on a healthy proxy-router**. If the proxy-router is wedged or can't talk to the BASE node, none of the higher layers will work. + +Tip: run the proxy-router in a foreground terminal at least once so you can see startup logs in real time. For log destinations and verbosity, see the **Logging Configuration** section of [`docs/proxy-router.all.env`](https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/blob/main/docs/proxy-router.all.env). + +## Healthy startup looks like + +``` +INFO proxy state: running +INFO HTTP http server is listening: 0.0.0.0:8082 +INFO TCP tcp server is listening: 0.0.0.0:3333 +``` + +You can also confirm via `http://localhost:8082/swagger/index.html` (or whatever URL is set in your `.env`). + +--- + +## Proxy-router is not starting / crashing immediately + +### Likely cause 1: `.env` misconfiguration + +These four values **must** match your chain and OS. Use `proxy-router/env.main.example` as the canonical reference: + +- `DIAMOND_CONTRACT_ADDRESS=` +- `MOR_TOKEN_ADDRESS=` +- `BLOCKSCOUT_API_URL=` +- `ETH_NODE_CHAIN_ID=` +- `PROXY_STORAGE_PATH=` + +If running the proxy-router headless (without the UI), set: + +- `WALLET_PRIVATE_KEY=` — the provider's wallet private key. + +If you bring your own ETH node (Alchemy, Infura, etc.): + +- Confirm `ETH_NODE_URL=` (or `ETH_NODE_ADDRESS=`) is correct for the chain. +- Recommended: HTTPS over WSS, with `ETH_NODE_USE_SUBSCRIPTIONS=false`. + +Full reference: [Env: proxy-router](/reference/env-proxy-router). + +### Likely cause 2: `models-config.json` misconfiguration + +- `MODELS_CONFIG_PATH=` in `.env` must point to the actual file with read permissions. +- The JSON must follow [models-config.json](/reference/models-config). +- Restart the proxy-router after edits. + +### Resolution + +1. Fix `.env` and `models-config.json`. +2. Restart the proxy-router. +3. Watch the log for connection errors to the ETH node and the Diamond contract. + +--- + +## Wallet shows zero MOR / ETH after recovering from mnemonic + +You probably recovered a **derived address**. The MorpheusUI mnemonic flow only works with **top-level (tier-1)** addresses. Either: + +- Use a wallet that was originally created from this mnemonic at index 0, or +- Import the **private key** directly instead of the mnemonic. + +--- + +## "Where is my MOR?" + +Almost always: it's escrowed in the Diamond contract because of an open or recently-closed session. Walk through: + +- [Sessions: stake, close, claim](/concepts/sessions-stake-close-recover) +- [Where is my MOR?](/ai/where-is-my-mor) +- [Why is my MOR locked in the contract?](/ai/why-locked-in-contract) + +--- + +## Local model returns nonsense + +The bundled `tinyllama` is a **demo** model. It will hallucinate, miscount, and contradict itself. Compare quality only against real Morpheus models. See [Local vs on-chain models](/concepts/local-vs-onchain-models). + +--- + +## Provider-side: consumers can't connect + +- Confirm `:3333` is **publicly reachable** (`telnet host 3333` from outside your network). +- Confirm `WEB_PUBLIC_URL` and the registered provider `endpoint` match your actual public host. +- Inspect provider logs — connection attempts and rejections show up there. + +--- + +## Provider-side: TEE attestation fails on the consumer + +- Confirm your model is registered with the `tee` tag. +- Confirm the consumer is on `v6.0.0+` (Phase 1) or `v7.0.0+` for full benefit. +- Recheck the SecretVM portal at https://secretai.scrtlabs.com/attestation with your compose and VM URL — all three layers must pass. +- Use `cosign verify` and `cosign verify-attestation` on your `-tee` image. See [TEE reference](/providers/full/tee-reference). + +--- + +## "Locked files" or stale processes after Ctrl+C + +- macOS / Linux: + ```bash + ps -ax | grep proxy-router + kill -9 + + lsof | grep /proxy-router/data/ + kill -9 + ``` +- For Electron / MorpheusUI: `ps -ax | grep electron` and kill stragglers. + +See also: [Consumer troubleshooting](/consumers/troubleshooting). diff --git a/docs/scripts/build-site.mjs b/docs/scripts/build-site.mjs new file mode 100644 index 00000000..8eaa475f --- /dev/null +++ b/docs/scripts/build-site.mjs @@ -0,0 +1,36 @@ +#!/usr/bin/env node +/** + * Build static docs site: mint export → postprocess (Pagefind + llms.txt). + * Usage: SITE_URL=https://nodedocs.mor.org node scripts/build-site.mjs [outDir] + */ +import { execSync } from "child_process"; +import fs from "fs"; +import os from "os"; +import path from "path"; +import { fileURLToPath } from "url"; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const docsDir = path.join(__dirname, ".."); +const outDir = path.resolve(process.argv[2] ?? path.join(docsDir, "..", ".site")); +const siteUrl = process.env.SITE_URL ?? "https://nodedocs.mor.org"; +const zipPath = path.join(os.tmpdir(), `nodedocs-${Date.now()}.zip`); + +console.log(`Building docs site → ${outDir}`); +console.log(`Canonical URL: ${siteUrl}`); + +execSync(`npx mint export --output "${zipPath}"`, { + stdio: "inherit", + cwd: docsDir, +}); + +fs.rmSync(outDir, { recursive: true, force: true }); +fs.mkdirSync(outDir, { recursive: true }); +execSync(`unzip -q -o "${zipPath}" -d "${outDir}"`, { stdio: "inherit" }); +fs.rmSync(zipPath, { force: true }); + +execSync(`node "${path.join(__dirname, "postprocess-export.mjs")}" "${outDir}"`, { + stdio: "inherit", + env: { ...process.env, SITE_URL: siteUrl }, +}); + +console.log(`Site ready at ${outDir}`); diff --git a/docs/scripts/generate-llms-txt.mjs b/docs/scripts/generate-llms-txt.mjs new file mode 100644 index 00000000..9da88aff --- /dev/null +++ b/docs/scripts/generate-llms-txt.mjs @@ -0,0 +1,107 @@ +#!/usr/bin/env node +/** + * Generate llms.txt and llms-full.txt from docs.json navigation + MDX source. + * Usage: SITE_URL=https://nodedocs.mor.org node scripts/generate-llms-txt.mjs [docsDir] [outDir] + */ +import fs from "fs"; +import path from "path"; +import { fileURLToPath } from "url"; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const docsDir = path.resolve(process.argv[2] ?? path.join(__dirname, "..")); +const outDir = path.resolve(process.argv[3] ?? docsDir); +const siteUrl = (process.env.SITE_URL ?? "https://nodedocs.mor.org").replace(/\/$/, ""); + +const docsJson = JSON.parse(fs.readFileSync(path.join(docsDir, "docs.json"), "utf8")); + +function walkNavItems(items, slugs) { + for (const item of items ?? []) { + if (typeof item === "string") { + slugs.push(item); + } else if (item && Array.isArray(item.pages)) { + walkNavItems(item.pages, slugs); + } + } +} + +function collectSlugs() { + const slugs = []; + for (const tab of docsJson.navigation?.tabs ?? []) { + for (const group of tab.groups ?? []) { + walkNavItems(group.pages, slugs); + } + } + return [...new Set(slugs)]; +} + +function parseFrontmatter(filePath) { + const raw = fs.readFileSync(filePath, "utf8"); + const match = raw.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/); + if (!match) return { meta: {}, body: raw }; + + const meta = {}; + for (const line of match[1].split("\n")) { + const kv = line.match(/^(\w+):\s*"?(.+?)"?\s*$/); + if (kv) meta[kv[1]] = kv[2]; + } + return { meta, body: match[2] }; +} + +function slugToUrl(slug) { + return slug === "index" ? siteUrl : `${siteUrl}/${slug}`; +} + +function slugToMdxPath(slug) { + if (slug === "index") return path.join(docsDir, "index.mdx"); + return path.join(docsDir, `${slug}.mdx`); +} + +const entries = []; +const fullSections = []; + +for (const slug of collectSlugs()) { + const mdxPath = slugToMdxPath(slug); + if (!fs.existsSync(mdxPath)) continue; + + const { meta, body } = parseFrontmatter(mdxPath); + const title = meta.title ?? meta.sidebarTitle ?? slug; + const description = meta.description ?? ""; + const url = slugToUrl(slug); + + entries.push({ title, description, url }); + fullSections.push(`# ${title}\n\nSource: ${url}\n\n${body.trim()}\n`); +} + +const siteName = docsJson.name ?? "Morpheus Lumerin Node Docs"; +const siteDescription = + docsJson.description ?? + "Canonical documentation for the Morpheus Lumerin Node."; + +const llmsTxt = [ + `# ${siteName}`, + "", + `> ${siteDescription}`, + "", + "## Pages", + "", + ...entries.map((e) => + e.description + ? `- [${e.title}](${e.url}): ${e.description}` + : `- [${e.title}](${e.url})` + ), + "", +].join("\n"); + +const llmsFullTxt = [ + `# ${siteName} — full text export`, + "", + `> ${siteDescription}`, + "", + ...fullSections, +].join("\n\n"); + +fs.mkdirSync(outDir, { recursive: true }); +fs.writeFileSync(path.join(outDir, "llms.txt"), llmsTxt); +fs.writeFileSync(path.join(outDir, "llms-full.txt"), llmsFullTxt); + +console.log(`Wrote llms.txt (${entries.length} pages) and llms-full.txt to ${outDir}`); diff --git a/docs/scripts/postprocess-export.mjs b/docs/scripts/postprocess-export.mjs new file mode 100644 index 00000000..2a566bfd --- /dev/null +++ b/docs/scripts/postprocess-export.mjs @@ -0,0 +1,72 @@ +#!/usr/bin/env node +/** + * Post-process a mint export directory: Pagefind index + UI hook + llms.txt. + * Usage: SITE_URL=https://nodedocs.mor.org node scripts/postprocess-export.mjs + */ +import { execSync } from "child_process"; +import fs from "fs"; +import path from "path"; +import { fileURLToPath } from "url"; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const siteDir = path.resolve(process.argv[2] ?? "."); +const docsDir = path.join(__dirname, ".."); +const siteUrl = process.env.SITE_URL ?? "https://nodedocs.mor.org"; + +if (!fs.existsSync(siteDir)) { + console.error(`Site directory not found: ${siteDir}`); + process.exit(1); +} + +console.log("Running Pagefind index…"); +execSync(`npx pagefind --site "${siteDir}"`, { stdio: "inherit", cwd: docsDir }); + +console.log("Generating llms.txt…"); +execSync( + `node "${path.join(__dirname, "generate-llms-txt.mjs")}" "${docsDir}" "${siteDir}"`, + { stdio: "inherit", env: { ...process.env, SITE_URL: siteUrl } } +); + +const pagefindSnippet = ` + + + +`; + +function injectPagefind(htmlPath) { + let html = fs.readFileSync(htmlPath, "utf8"); + if (html.includes("pagefind-ui.js")) return; + if (html.includes("")) { + html = html.replace("", `${pagefindSnippet}\n`); + fs.writeFileSync(htmlPath, html); + } +} + +function walkHtml(dir) { + for (const entry of fs.readdirSync(dir, { withFileTypes: true })) { + const full = path.join(dir, entry.name); + if (entry.isDirectory() && entry.name !== "pagefind" && entry.name !== "_next") { + walkHtml(full); + } else if (entry.isFile() && entry.name.endsWith(".html")) { + injectPagefind(full); + } + } +} + +console.log("Injecting Pagefind UI…"); +walkHtml(siteDir); + +console.log("Post-process complete."); diff --git a/docs/toc.md b/docs/toc.md deleted file mode 100644 index 321e0212..00000000 --- a/docs/toc.md +++ /dev/null @@ -1,50 +0,0 @@ - -Document outline: -1. Design & Expectations - * How is the proxy-router supposed to be leveraged? - * Where does it fall in the larger design for Morpheus? - * Pictures to illustrate flow of interaction and setting expecations - * How do you know it's working? (from which perspective?) - -1. Installation - 1. From Binaries, most simplistic to get up and running [install_from_binaries.md](install_from_binaries.md) - * Need ETH node solution (Http round robin) from Shev - * Create new Wallet within MorpheusUI - * Send aETH and aMOR to wallet (from separate wallet or mechanism) - * Variations for Mac ARM, Mac Intel, Linux, Windows - * Needs to be as easy and as simple as possible (minimal clicks/configuration) - * Both "private provider" and "consumer" - - 2. From Source, more complex but more control [install_from_source.md](install_from_source.md) - * Variants include - * Use existing "on-box" model - * Separate Model hosted elsewhere (with accessible endpoint) - * proxy-router node with private API access and publicly accessible router port - * directions on how to use the Swagger API / CLI / CURL - * Asssume separate eth node WSS subscription for proxy-router - * Assume using existing Wallet (with access to private key) - * Full control of proxy-router as core (tying blockchain-contracts, provider, model, bid, etc between AI Compute and Consumers) -1. Utilization - * "Done-Consumer" looks like - - download, - - unzip, - - allow binaries, - - run, - - accept, - - create, - - receive (*may need separate doc for getting tokens/eth..especailly on sa), - - chat local, - - chat remote (existing providers) - * "Done-Personal-Provider" looks like - - "Done-Consumer" plus - - authorize contract, - - create provider, - - create model, - - create bid - - validate that model is working (available on chain and accessible via proxy-router) - * "Done-Enterprise-Provider" looks like - - Assume existing Wallet (with privatekey) - - Assume existing ETH Node WSS subscription - - Assume familiarity working with API/CLI/CURL and existing blockchain stuff - - Assume existing AI Compute Resource/Model that wants to be provided - diff --git a/readme.md b/readme.md index d750d281..06bbbc14 100644 --- a/readme.md +++ b/readme.md @@ -1,6 +1,9 @@ # Morpheus Lumerin Node + ### Take part in the Lumerin coding weight rewards!! [stake.mor.lumerin.io](https://stake.mor.lumerin.io/) + ![Simple-Overview](docs/images/simple.png) + The purpose of this software is to enable interaction with distributed, decentralized LLMs on the Morpheus network through a desktop chat experience. > **v7.0.0 — Full TEE capability.** The v7 release completes a two-hop Trusted Execution Environment (TEE) trust chain for any model registered on-chain with the `tee` tag: @@ -8,55 +11,70 @@ The purpose of this software is to enable interaction with distributed, decentra > - **Phase 1** — *consumer → P-Node.* A consumer proxy-router (v6.0.0+) cryptographically verifies the provider's P-Node runs the exact official hardened `-tee` image inside a genuine Intel TDX SecretVM, with TLS pinning, at session open and on every prompt. > - **Phase 2 (new in v7)** — *P-Node → backend LLM.* The v7+ P-Node itself verifies the backend LLM it forwards inference to (CPU TDX quote, TLS pinning, workload RTMR3 replay of the backend's `docker-compose.yaml`, CPU-GPU nonce binding, and NVIDIA NRAS GPU attestation) at startup and on every prompt. > -> Because Phase 2 runs inside the attested P-Node, **any v6+ consumer is forward-compatible with a v7+ provider** and gains the Phase 2 guarantees automatically — no client-side upgrade required. See [02.3-proxy-router-tee.md](docs/02.3-proxy-router-tee.md), [02.4-proxy-router-secretvm-quickstart.md](docs/02.4-proxy-router-secretvm-quickstart.md), and the developer reference at [proxy-router/docs/tee-backend-verification.md](proxy-router/docs/tee-backend-verification.md). - -0. PreRequisites: BASE Layer 2 Blockchain, MOR and ETH on BASE for staking and bidding -1. Existing, Hosted AI model that is available for inference via the Morpheus network -2. The proxy-router talks to and listens to the blockchain, routes prompts and inference between the providers’ models and the consumers that purchase and use the models -3. Providers register their models via bids on the blockchain -4. The consumer node is the “client” that will be purchasing bids from the blockchain, sending prompts via the proxy-router and receiving inference back from the provider’s models -5. Consumers purchase the bid and stake MOR for their session time -6. Once the bid has been purchased, prompt and inference (ChatGPT-like) can start - - -**Components that are included in this repository are:** -* Local `Llama.cpp` and tinyllama model to run locally for demonstration purposes only -* Lumerin `proxy-router` is a background process that monitors sepcific blockchain contract events, -manages secure sessions between consumers and providers and routes prompts and responses between them -* Lumerin `MorpheusUI` is the front end UI to interact with LLMs and the Morpheus network via the proxy-router as a consumer -* Lumerin `cli` is the cli client to interact with LLMs and the Morpheus network via the proxy-router as a consumer -* Kubo `ipfs` is the ipfs client to interact with the ipfs network to store and retrieve model/agent files - -## Tokens and Contract Information (updated 12/17/2025) -### MainNet: (MAIN Branch and MAIN-* Releases) -* Blockchain: BASE Mainnet (ChainID: `8453`) -* Morpheus MOR Token: `0x7431aDa8a591C955a994a21710752EF9b882b8e3` -* Diamond MarketPlace Contract: `0x6aBE1d282f72B474E54527D93b979A4f64d3030a` -* Blockchain Explorer: `https://base.blockscout.com/` -* GitHub Source: https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/tree/main - -### TestNet (TEST Branch and TEST-* Releases) -* Blockchain: BASE Sepolia (ChainID: `84532`) -* Morpheus MOR Token: `0x5C80Ddd187054E1E4aBBfFCD750498e81d34FfA3` -* Diamond MarketPlace Contract: `0x6e4d0B775E3C3b02683A6F277Ac80240C4aFF930` -* Blockchain Explorer: `https://base-sepolia.blockscout.com/` -* GitHub Source: https://github.com/MorpheusAIs/Morpheus-Lumerin-Node/tree/test - -## Funds -* **WALLET:** For testing as a provider or consumer, you will need both `MOR` and `ETH` tokens in your wallet. - * `MOR` is the token used to pay for the model provider staking and consumer usage - * `ETH` is the token used to pay for the gas fees on the network - -## Installation & Operation -* [00-Overview](docs/00-overview.md) - This provides a comprehensive picture of the Provider, Blockchain and Consumer environments and how they interact. This will also link to other documents for more advanced setup and configuration. - -* [04-Consumer-Setup](docs/04-consumer-setup.md) - This is the simplest way to get started with the Morpheus Lumerin Node as a Consumer. This will allow you to interact with the Morpheus network and the models offered on the network as a consumer running from packaged releases. - -* [02-Provider-Setup](docs/02-provider-setup.md) - This is the simplest way to get started with the Morpheus Lumerin Node as a Provider. This will allow you to connect your existing AI-Model to the Morpheus network and offer it for use by consumers. - * [02.1-Proxy-Router-Docker](docs/02.1-proxy-router-docker.md) - Fast start using existing Docker image and proxy-router configuration - * [02.2-Proxy-Router-Akash](docs/02.2-proxy-router-akash.md) - Run the proxy-router on the Akash decentralized cloud - * [02.3-Proxy-Router-TEE](docs/02.3-proxy-router-tee.md) - Full TEE (Trusted Execution Environment) reference: build-time baked-in config, RTMR3 attestation, cosign image/manifest verification, and consumer-side verification steps - * [02.4-Proxy-Router-SecretVM-Quickstart](docs/02.4-proxy-router-secretvm-quickstart.md) - Shortest path to a v7 TEE provider: deploy the hardened `-tee` image on SecretVM and register a `tee`-tagged model - * [02.5-API-Auth](docs/02.5-api-auth.md) - API authentication (cookie/proxy.conf) required since v2.0.0 - -* [03-Provider-Offer](docs/03-provider-offer.md) - Register your provider, model (optionally with the `tee` tag), and bid on-chain. \ No newline at end of file +> Because Phase 2 runs inside the attested P-Node, **any v6+ consumer is forward-compatible with a v7+ provider** and gains the Phase 2 guarantees automatically — no client-side upgrade required. See the new [TEE reference](docs/providers/full/tee-reference.mdx), the [SecretVM quickstart](docs/providers/full/secretvm-quickstart.mdx), and the developer reference at [proxy-router/docs/tee-backend-verification.md](proxy-router/docs/tee-backend-verification.md). + +## Documentation + +The canonical documentation is in **[`/docs`](docs/)** and is built with [Mintlify](https://mintlify.com). It replaces the previous `00-overview.md` / `02-*.md` / `04-*.md` / `99-troubleshooting.md` set of files; old paths still resolve via redirects in [`docs/docs.json`](docs/docs.json). + +To preview the site locally: + +```bash +npm i -g mint +cd docs +mint dev +# open http://localhost:3000 +``` + +The site is structured around **role-based journeys** (consumer / prosumer / provider tiers), with anti-hallucination [AI knowledge](docs/ai/) pages and curated mirrors of the broader [ecosystem](docs/ecosystem/) ([mor.org](https://mor.org), [tech.mor.org](https://tech.mor.org), [active.mor.org](https://active.mor.org), [MyProvider](https://myprovider.mor.org), [Everclaw](https://everclaw.xyz), [NodeNeo](https://nodeneo.io), [app.mor.org](https://app.mor.org)). + +## What's in this repo + +- Local `Llama.cpp` and tinyllama model to run locally for demonstration purposes only. +- Lumerin `proxy-router` — background process that monitors blockchain contract events, manages secure sessions between consumers and providers, and routes prompts and responses between them. +- Lumerin `MorpheusUI` — the Electron front end UI to interact with LLMs and the Morpheus network as a consumer. +- Lumerin `cli` — CLI client to interact with LLMs and the Morpheus network as a consumer. +- Kubo `ipfs` — IPFS client to store and retrieve model/agent files. + +## End-to-end picture + +0. **PreRequisites**: BASE Layer 2 Blockchain, MOR and ETH on BASE for staking and bidding. +1. Existing, Hosted AI model available for inference via the Morpheus network. +2. The proxy-router talks to and listens to the blockchain; it routes prompts and inference between providers' models and consumers. +3. Providers register their models via bids on the blockchain. +4. The consumer node is the "client" that purchases bids, sends prompts via the proxy-router, and receives inference back from the provider's models. +5. Consumers stake MOR to open a session for the duration they intend to use. +6. Once the session is open, prompt and inference (ChatGPT-like) can start. + +## Tokens and contract information + +| Item | BASE Mainnet | BASE Sepolia (testnet) | +|------|--------------|------------------------| +| Chain ID | `8453` | `84532` | +| Branch | `main` (`MAIN-*` releases) | `test` (`*-test` releases) | +| MOR Token | `0x7431aDa8a591C955a994a21710752EF9b882b8e3` | `0x5C80Ddd187054E1E4aBBfFCD750498e81d34FfA3` | +| Diamond Marketplace | `0x6aBE1d282f72B474E54527D93b979A4f64d3030a` | `0x6e4d0B775E3C3b02683A6F277Ac80240C4aFF930` | +| Block Explorer | https://base.blockscout.com/ | https://base-sepolia.blockscout.com/ | + +You will need both **MOR** (for stake / fees / session payment) and **ETH on BASE** (for gas) in your wallet. + +## Quickstart + +| Role | Start here | +|------|-----------| +| Consumer (chat) | [Consumer quickstart](docs/get-started/quickstart-consumer.mdx) | +| Provider (host your own model) | [Provider quickstart](docs/get-started/quickstart-provider.mdx) | +| TEE provider (SecretVM) | [SecretVM quickstart](docs/providers/full/secretvm-quickstart.mdx) | +| Resale provider | [Resale overview](docs/providers/resale/overview.mdx) | +| Prosumer / agent | [Prosumer overview](docs/prosumers/overview.mdx) | +| Developer (API) | [API overview](docs/reference/api-overview.mdx) | + +## For AI agents reading this repo + +Start with [`AGENTS.md`](AGENTS.md) and the curated [AI knowledge](docs/ai/) section. Key anti-hallucination pages: + +- [Where is my MOR?](docs/ai/where-is-my-mor.mdx) +- [Session states (open, close, recover)](docs/ai/session-states-open-close-recover.mdx) +- [Why is my MOR locked in the contract?](docs/ai/why-locked-in-contract.mdx) +- [Local vs blockchain models](docs/ai/local-vs-blockchain-models.mdx) +- [LLM prompt cheatsheet](docs/ai/llm-prompt-cheatsheet.mdx)