diff --git a/.claude/commands/create-frontend-release.md b/.claude/commands/create-frontend-release.md index de6695710..38ed14651 100644 --- a/.claude/commands/create-frontend-release.md +++ b/.claude/commands/create-frontend-release.md @@ -294,7 +294,6 @@ echo "Last stable release: $LAST_STABLE" 1. Run complete test suite: ```bash pnpm test:unit - pnpm test:component ``` 2. Run type checking: ```bash diff --git a/.claude/commands/setup_repo.md b/.claude/commands/setup_repo.md index 48605271e..d82e22ec6 100644 --- a/.claude/commands/setup_repo.md +++ b/.claude/commands/setup_repo.md @@ -120,7 +120,6 @@ echo "Available commands:" echo " pnpm dev - Start development server" echo " pnpm build - Build for production" echo " pnpm test:unit - Run unit tests" -echo " pnpm test:component - Run component tests" echo " pnpm typecheck - Run TypeScript checks" echo " pnpm lint - Run ESLint" echo " pnpm format - Format code with Prettier" diff --git a/.gitattributes b/.gitattributes index bd0518cde..0f538ae76 100644 --- a/.gitattributes +++ b/.gitattributes @@ -12,5 +12,5 @@ *.yaml text eol=lf # Generated files -src/types/comfyRegistryTypes.ts linguist-generated=true +packages/registry-types/src/comfyRegistryTypes.ts linguist-generated=true src/workbench/extensions/manager/types/generatedManagerTypes.ts linguist-generated=true diff --git a/.github/actions/setup-frontend/action.yml b/.github/actions/setup-frontend/action.yml new file mode 100644 index 000000000..3ebc12eb3 --- /dev/null +++ b/.github/actions/setup-frontend/action.yml @@ -0,0 +1,67 @@ +name: Setup Frontend +description: 'Setup ComfyUI frontend development environment' +inputs: + extra_server_params: + description: 'Additional parameters to pass to ComfyUI server' + required: false + default: '' +runs: + using: 'composite' + steps: + - name: Checkout ComfyUI + uses: actions/checkout@v4 + with: + repository: 'comfyanonymous/ComfyUI' + path: 'ComfyUI' + + - name: Checkout ComfyUI_frontend + uses: actions/checkout@v4 + with: + repository: 'Comfy-Org/ComfyUI_frontend' + path: 'ComfyUI_frontend' + + - name: Copy ComfyUI_devtools from frontend repo + shell: bash + run: | + mkdir -p ComfyUI/custom_nodes/ComfyUI_devtools + cp -r ComfyUI_frontend/tools/devtools/* ComfyUI/custom_nodes/ComfyUI_devtools/ + + - name: Install pnpm + uses: pnpm/action-setup@v4 + with: + version: 10 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 'lts/*' + cache: 'pnpm' + cache-dependency-path: 'ComfyUI_frontend/pnpm-lock.yaml' + + - name: Setup Python + uses: actions/setup-python@v4 + with: + python-version: '3.10' + + - name: Install Python requirements + shell: bash + working-directory: ComfyUI + run: | + python -m pip install --upgrade pip + pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu + pip install -r requirements.txt + pip install wait-for-it + + - name: Build & Install ComfyUI_frontend + shell: bash + working-directory: ComfyUI_frontend + run: | + pnpm install --frozen-lockfile + pnpm build + + - name: Start ComfyUI server + shell: bash + working-directory: ComfyUI + run: | + python main.py --cpu --multi-user --front-end-root ../ComfyUI_frontend/dist ${{ inputs.extra_server_params }} & + wait-for-it --service 127.0.0.1:8188 -t 600 \ No newline at end of file diff --git a/.github/actions/setup-playwright/action.yml b/.github/actions/setup-playwright/action.yml new file mode 100644 index 000000000..ddd1a7605 --- /dev/null +++ b/.github/actions/setup-playwright/action.yml @@ -0,0 +1,31 @@ +name: Setup Playwright +description: Cache and install Playwright browsers with dependencies +runs: + using: composite + steps: + - name: Detect Playwright version + id: detect-version + shell: bash + working-directory: ComfyUI_frontend + run: | + PLAYWRIGHT_VERSION=$(pnpm ls @playwright/test --json | jq --raw-output '.[0].devDependencies["@playwright/test"].version') + echo "playwright-version=$PLAYWRIGHT_VERSION" >> $GITHUB_OUTPUT + + - name: Cache Playwright Browsers + uses: actions/cache@v4 + id: cache-playwright-browsers + with: + path: '~/.cache/ms-playwright' + key: ${{ runner.os }}-playwright-browsers-${{ steps.detect-version.outputs.playwright-version }} + + - name: Install Playwright Browsers + if: steps.cache-playwright-browsers.outputs.cache-hit != 'true' + shell: bash + run: pnpm exec playwright install chromium --with-deps + working-directory: ComfyUI_frontend + + - name: Install Playwright Browsers (operating system dependencies) + if: steps.cache-playwright-browsers.outputs.cache-hit == 'true' + shell: bash + run: pnpm exec playwright install-deps + working-directory: ComfyUI_frontend \ No newline at end of file diff --git a/.github/workflows/backport.yaml b/.github/workflows/auto-backport.yaml similarity index 99% rename from .github/workflows/backport.yaml rename to .github/workflows/auto-backport.yaml index 178bd4ee8..20eadc0c9 100644 --- a/.github/workflows/backport.yaml +++ b/.github/workflows/auto-backport.yaml @@ -60,7 +60,7 @@ jobs: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: fetch-depth: 0 diff --git a/.github/workflows/chromatic.yaml b/.github/workflows/chromatic.yaml deleted file mode 100644 index 127186d68..000000000 --- a/.github/workflows/chromatic.yaml +++ /dev/null @@ -1,57 +0,0 @@ -name: 'Chromatic' - -# - [Automate Chromatic with GitHub Actions • Chromatic docs]( https://www.chromatic.com/docs/github-actions/ ) - -on: - workflow_dispatch: # Allow manual triggering - pull_request: - branches: [main] - -jobs: - chromatic-deployment: - runs-on: ubuntu-latest - # Only run for PRs from version-bump-* branches or manual triggers - if: github.event_name == 'workflow_dispatch' || startsWith(github.head_ref, 'version-bump-') - steps: - - name: Checkout code - uses: actions/checkout@v4 - with: - fetch-depth: 0 # Required for Chromatic baseline - - - name: Install pnpm - uses: pnpm/action-setup@v4 - with: - version: 10 - - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: '20' - cache: 'pnpm' - - - - name: Cache tool outputs - uses: actions/cache@v4 - with: - path: | - .cache - storybook-static - tsconfig.tsbuildinfo - key: storybook-cache-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}-${{ hashFiles('src/**/*.{ts,vue,js}', '*.config.*', '.storybook/**/*') }} - restore-keys: | - storybook-cache-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}- - storybook-cache-${{ runner.os }}- - storybook-tools-cache-${{ runner.os }}- - - - name: Install dependencies - run: pnpm install --frozen-lockfile - - - name: Build Storybook and run Chromatic - id: chromatic - uses: chromaui/action@latest - with: - projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }} - buildScriptName: build-storybook - autoAcceptChanges: 'main' # Auto-accept changes on main branch - exitOnceUploaded: true # Don't wait for UI tests to complete - diff --git a/.github/workflows/claude-pr-review.yml b/.github/workflows/claude-pr-review.yml index d1eecafe3..08ad70727 100644 --- a/.github/workflows/claude-pr-review.yml +++ b/.github/workflows/claude-pr-review.yml @@ -29,11 +29,9 @@ jobs: - name: Check if we should proceed id: check-status run: | - # Get all check runs for this commit - CHECK_RUNS=$(gh api repos/${{ github.repository }}/commits/${{ github.event.pull_request.head.sha }}/check-runs --jq '.check_runs[] | select(.name | test("lint-and-format|test|playwright-tests")) | {name, conclusion}') - - # Check if any required checks failed - if echo "$CHECK_RUNS" | grep -q '"conclusion": "failure"'; then + CHECK_RUNS=$(gh api repos/${{ github.repository }}/commits/${{ github.event.pull_request.head.sha }}/check-runs --jq '.check_runs[] | select(.name | test("lint-and-format")) | {name, conclusion}') + + if echo "$CHECK_RUNS" | grep -Eq '"conclusion": "(failure|cancelled|timed_out|action_required)"'; then echo "Some CI checks failed - skipping Claude review" echo "proceed=false" >> $GITHUB_OUTPUT else @@ -50,9 +48,10 @@ jobs: timeout-minutes: 30 steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: fetch-depth: 0 + ref: refs/pull/${{ github.event.pull_request.number }}/head - name: Install pnpm uses: pnpm/action-setup@v4 @@ -86,4 +85,4 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} COMMIT_SHA: ${{ github.event.pull_request.head.sha }} BASE_SHA: ${{ github.event.pull_request.base.sha }} - REPOSITORY: ${{ github.repository }} \ No newline at end of file + REPOSITORY: ${{ github.repository }} diff --git a/.github/workflows/dev-release.yaml b/.github/workflows/create-dev-pypi-package.yaml similarity index 97% rename from .github/workflows/dev-release.yaml rename to .github/workflows/create-dev-pypi-package.yaml index 0b45420c6..b592a8371 100644 --- a/.github/workflows/dev-release.yaml +++ b/.github/workflows/create-dev-pypi-package.yaml @@ -15,7 +15,7 @@ jobs: version: ${{ steps.current_version.outputs.version }} steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Install pnpm uses: pnpm/action-setup@v4 with: @@ -62,7 +62,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Download dist artifact uses: actions/download-artifact@v4 with: diff --git a/.github/workflows/create-release-candidate-branch.yaml b/.github/workflows/create-release-branch.yaml similarity index 99% rename from .github/workflows/create-release-candidate-branch.yaml rename to .github/workflows/create-release-branch.yaml index e3fcd9e2b..7891a845d 100644 --- a/.github/workflows/create-release-candidate-branch.yaml +++ b/.github/workflows/create-release-branch.yaml @@ -18,7 +18,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: fetch-depth: 0 token: ${{ secrets.PR_GH_TOKEN || secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/release.yaml b/.github/workflows/create-release-draft.yaml similarity index 100% rename from .github/workflows/release.yaml rename to .github/workflows/create-release-draft.yaml diff --git a/.github/workflows/devtools-python-check.yaml b/.github/workflows/devtools-python-check.yaml new file mode 100644 index 000000000..f0893e99d --- /dev/null +++ b/.github/workflows/devtools-python-check.yaml @@ -0,0 +1,26 @@ +name: Devtools Python Check + +on: + pull_request: + paths: + - 'tools/devtools/**' + push: + branches: [ main ] + paths: + - 'tools/devtools/**' + +jobs: + syntax: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v5 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.11' + + - name: Validate Python syntax + run: python3 -m compileall -q tools/devtools diff --git a/.github/workflows/lint-and-format.yaml b/.github/workflows/lint-and-format.yaml index 3b6bf1538..1f20ab92e 100644 --- a/.github/workflows/lint-and-format.yaml +++ b/.github/workflows/lint-and-format.yaml @@ -13,11 +13,9 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout PR - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: - token: ${{ secrets.GITHUB_TOKEN }} - ref: ${{ github.event.pull_request.head.ref }} - fetch-depth: 0 + ref: ${{ !github.event.pull_request.head.repo.fork && github.head_ref || github.ref }} - name: Install pnpm uses: pnpm/action-setup@v4 @@ -69,7 +67,7 @@ jobs: git config --local user.email "action@github.com" git config --local user.name "GitHub Action" git add . - git commit -m "[auto-fix] Apply ESLint and Prettier fixes" + git commit -m "[automated] Apply ESLint and Prettier fixes" git push - name: Final validation @@ -102,4 +100,4 @@ jobs: owner: context.repo.owner, repo: context.repo.repo, body: '## ⚠️ Linting/Formatting Issues Found\n\nThis PR has linting or formatting issues that need to be fixed.\n\n**Since this PR is from a fork, auto-fix cannot be applied automatically.**\n\n### Option 1: Set up pre-commit hooks (recommended)\nRun this once to automatically format code on every commit:\n```bash\npnpm prepare\n```\n\n### Option 2: Fix manually\nRun these commands and push the changes:\n```bash\npnpm lint:fix\npnpm format\n```\n\nSee [CONTRIBUTING.md](https://github.com/Comfy-Org/ComfyUI_frontend/blob/main/CONTRIBUTING.md#git-pre-commit-hooks) for more details.' - }) \ No newline at end of file + }) diff --git a/.github/workflows/pr-playwright-deploy.yaml b/.github/workflows/pr-playwright-deploy-forks.yaml similarity index 99% rename from .github/workflows/pr-playwright-deploy.yaml rename to .github/workflows/pr-playwright-deploy-forks.yaml index 19bb28253..660fee77f 100644 --- a/.github/workflows/pr-playwright-deploy.yaml +++ b/.github/workflows/pr-playwright-deploy-forks.yaml @@ -30,7 +30,7 @@ jobs: echo "Is forked: ${{ github.event.workflow_run.head_repository.full_name != github.event.workflow_run.repository.full_name }}" - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Get PR Number id: pr diff --git a/.github/workflows/pr-storybook-comment.yaml b/.github/workflows/pr-storybook-comment.yaml deleted file mode 100644 index 53691d826..000000000 --- a/.github/workflows/pr-storybook-comment.yaml +++ /dev/null @@ -1,126 +0,0 @@ -name: PR Storybook Comment - -on: - workflow_run: - workflows: ['Chromatic'] - types: [requested, completed] - -jobs: - comment-storybook: - runs-on: ubuntu-latest - if: >- - github.repository == 'Comfy-Org/ComfyUI_frontend' - && github.event.workflow_run.event == 'pull_request' - && startsWith(github.event.workflow_run.head_branch, 'version-bump-') - permissions: - pull-requests: write - actions: read - steps: - - name: Get PR number - id: pr - uses: actions/github-script@v7 - with: - script: | - const { data: pullRequests } = await github.rest.pulls.list({ - owner: context.repo.owner, - repo: context.repo.repo, - state: 'open', - head: `${context.repo.owner}:${context.payload.workflow_run.head_branch}`, - }); - - if (pullRequests.length === 0) { - console.log('No open PR found for this branch'); - return null; - } - - return pullRequests[0].number; - - - name: Log when no PR found - if: steps.pr.outputs.result == 'null' - run: | - echo "⚠️ No open PR found for branch: ${{ github.event.workflow_run.head_branch }}" - echo "Workflow run ID: ${{ github.event.workflow_run.id }}" - echo "Repository: ${{ github.event.workflow_run.repository.full_name }}" - echo "Event: ${{ github.event.workflow_run.event }}" - - - name: Get workflow run details - if: steps.pr.outputs.result != 'null' && github.event.action == 'completed' - id: workflow-run - uses: actions/github-script@v7 - with: - script: | - const run = await github.rest.actions.getWorkflowRun({ - owner: context.repo.owner, - repo: context.repo.repo, - run_id: context.payload.workflow_run.id, - }); - - return { - conclusion: run.data.conclusion, - html_url: run.data.html_url - }; - - - name: Get completion time - id: completion-time - run: echo "time=$(date -u '+%m/%d/%Y, %I:%M:%S %p')" >> $GITHUB_OUTPUT - - - name: Comment PR - Storybook Started - if: steps.pr.outputs.result != 'null' && github.event.action == 'requested' - uses: edumserrano/find-create-or-update-comment@82880b65c8a3a6e4c70aa05a204995b6c9696f53 # v3.0.0 - with: - issue-number: ${{ steps.pr.outputs.result }} - body-includes: '' - comment-author: 'github-actions[bot]' - edit-mode: replace - body: | - - ## 🎨 Storybook Build Status - - comfy-loading-gif **Build is starting...** - - ⏰ Started at: ${{ steps.completion-time.outputs.time }} UTC - - ### 🚀 Building Storybook - - 📦 Installing dependencies... - - 🔧 Building Storybook components... - - 🎨 Running Chromatic visual tests... - - --- - ⏱️ Please wait while the Storybook build is in progress... - - - name: Comment PR - Storybook Complete - if: steps.pr.outputs.result != 'null' && github.event.action == 'completed' - uses: edumserrano/find-create-or-update-comment@82880b65c8a3a6e4c70aa05a204995b6c9696f53 # v3.0.0 - with: - issue-number: ${{ steps.pr.outputs.result }} - body-includes: '' - comment-author: 'github-actions[bot]' - edit-mode: replace - body: | - - ## 🎨 Storybook Build Status - - ${{ - fromJSON(steps.workflow-run.outputs.result).conclusion == 'success' && '✅' - || fromJSON(steps.workflow-run.outputs.result).conclusion == 'skipped' && '⏭️' - || fromJSON(steps.workflow-run.outputs.result).conclusion == 'cancelled' && '🚫' - || '❌' - }} **${{ - fromJSON(steps.workflow-run.outputs.result).conclusion == 'success' && 'Build completed successfully!' - || fromJSON(steps.workflow-run.outputs.result).conclusion == 'skipped' && 'Build skipped.' - || fromJSON(steps.workflow-run.outputs.result).conclusion == 'cancelled' && 'Build cancelled.' - || 'Build failed!' - }}** - - ⏰ Completed at: ${{ steps.completion-time.outputs.time }} UTC - - ### 🔗 Links - - [📊 View Workflow Run](${{ fromJSON(steps.workflow-run.outputs.result).html_url }}) - - --- - ${{ - fromJSON(steps.workflow-run.outputs.result).conclusion == 'success' && '🎉 Your Storybook is ready for review!' - || fromJSON(steps.workflow-run.outputs.result).conclusion == 'skipped' && 'ℹ️ Chromatic was skipped for this PR.' - || fromJSON(steps.workflow-run.outputs.result).conclusion == 'cancelled' && 'ℹ️ The Chromatic run was cancelled.' - || '⚠️ Please check the workflow logs for error details.' - }} diff --git a/.github/workflows/pr-storybook-deploy-forks.yaml b/.github/workflows/pr-storybook-deploy-forks.yaml new file mode 100644 index 000000000..da27867c4 --- /dev/null +++ b/.github/workflows/pr-storybook-deploy-forks.yaml @@ -0,0 +1,90 @@ +name: PR Storybook Deploy (Forks) + +on: + workflow_run: + workflows: ['Storybook and Chromatic CI'] + types: [requested, completed] + +env: + DATE_FORMAT: '+%m/%d/%Y, %I:%M:%S %p' + +jobs: + deploy-and-comment-forked-pr: + runs-on: ubuntu-latest + if: | + github.repository == 'Comfy-Org/ComfyUI_frontend' && + github.event.workflow_run.event == 'pull_request' && + github.event.workflow_run.head_repository != null && + github.event.workflow_run.repository != null && + github.event.workflow_run.head_repository.full_name != github.event.workflow_run.repository.full_name + permissions: + pull-requests: write + actions: read + steps: + - name: Log workflow trigger info + run: | + echo "Repository: ${{ github.repository }}" + echo "Event: ${{ github.event.workflow_run.event }}" + echo "Head repo: ${{ github.event.workflow_run.head_repository.full_name || 'null' }}" + echo "Base repo: ${{ github.event.workflow_run.repository.full_name || 'null' }}" + echo "Is forked: ${{ github.event.workflow_run.head_repository.full_name != github.event.workflow_run.repository.full_name }}" + + - name: Checkout repository + uses: actions/checkout@v5 + + - name: Get PR Number + id: pr + uses: actions/github-script@v7 + with: + script: | + const { data: prs } = await github.rest.pulls.list({ + owner: context.repo.owner, + repo: context.repo.repo, + state: 'open', + }); + + const pr = prs.find(p => p.head.sha === context.payload.workflow_run.head_sha); + + if (!pr) { + console.log('No PR found for SHA:', context.payload.workflow_run.head_sha); + return null; + } + + console.log(`Found PR #${pr.number} from fork: ${context.payload.workflow_run.head_repository.full_name}`); + return pr.number; + + - name: Handle Storybook Start + if: steps.pr.outputs.result != 'null' && github.event.action == 'requested' + env: + GITHUB_TOKEN: ${{ github.token }} + run: | + chmod +x scripts/cicd/pr-storybook-deploy-and-comment.sh + ./scripts/cicd/pr-storybook-deploy-and-comment.sh \ + "${{ steps.pr.outputs.result }}" \ + "${{ github.event.workflow_run.head_branch }}" \ + "starting" \ + "$(date -u '${{ env.DATE_FORMAT }}')" + + - name: Download and Deploy Storybook + if: steps.pr.outputs.result != 'null' && github.event.action == 'completed' && github.event.workflow_run.conclusion == 'success' + uses: actions/download-artifact@v4 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + run-id: ${{ github.event.workflow_run.id }} + name: storybook-static + path: storybook-static + + - name: Handle Storybook Completion + if: steps.pr.outputs.result != 'null' && github.event.action == 'completed' + env: + CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} + CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + GITHUB_TOKEN: ${{ github.token }} + WORKFLOW_CONCLUSION: ${{ github.event.workflow_run.conclusion }} + WORKFLOW_URL: ${{ github.event.workflow_run.html_url }} + run: | + chmod +x scripts/cicd/pr-storybook-deploy-and-comment.sh + ./scripts/cicd/pr-storybook-deploy-and-comment.sh \ + "${{ steps.pr.outputs.result }}" \ + "${{ github.event.workflow_run.head_branch }}" \ + "completed" \ No newline at end of file diff --git a/.github/workflows/pr-storybook-deploy.yaml b/.github/workflows/pr-storybook-deploy.yaml new file mode 100644 index 000000000..da27867c4 --- /dev/null +++ b/.github/workflows/pr-storybook-deploy.yaml @@ -0,0 +1,90 @@ +name: PR Storybook Deploy (Forks) + +on: + workflow_run: + workflows: ['Storybook and Chromatic CI'] + types: [requested, completed] + +env: + DATE_FORMAT: '+%m/%d/%Y, %I:%M:%S %p' + +jobs: + deploy-and-comment-forked-pr: + runs-on: ubuntu-latest + if: | + github.repository == 'Comfy-Org/ComfyUI_frontend' && + github.event.workflow_run.event == 'pull_request' && + github.event.workflow_run.head_repository != null && + github.event.workflow_run.repository != null && + github.event.workflow_run.head_repository.full_name != github.event.workflow_run.repository.full_name + permissions: + pull-requests: write + actions: read + steps: + - name: Log workflow trigger info + run: | + echo "Repository: ${{ github.repository }}" + echo "Event: ${{ github.event.workflow_run.event }}" + echo "Head repo: ${{ github.event.workflow_run.head_repository.full_name || 'null' }}" + echo "Base repo: ${{ github.event.workflow_run.repository.full_name || 'null' }}" + echo "Is forked: ${{ github.event.workflow_run.head_repository.full_name != github.event.workflow_run.repository.full_name }}" + + - name: Checkout repository + uses: actions/checkout@v5 + + - name: Get PR Number + id: pr + uses: actions/github-script@v7 + with: + script: | + const { data: prs } = await github.rest.pulls.list({ + owner: context.repo.owner, + repo: context.repo.repo, + state: 'open', + }); + + const pr = prs.find(p => p.head.sha === context.payload.workflow_run.head_sha); + + if (!pr) { + console.log('No PR found for SHA:', context.payload.workflow_run.head_sha); + return null; + } + + console.log(`Found PR #${pr.number} from fork: ${context.payload.workflow_run.head_repository.full_name}`); + return pr.number; + + - name: Handle Storybook Start + if: steps.pr.outputs.result != 'null' && github.event.action == 'requested' + env: + GITHUB_TOKEN: ${{ github.token }} + run: | + chmod +x scripts/cicd/pr-storybook-deploy-and-comment.sh + ./scripts/cicd/pr-storybook-deploy-and-comment.sh \ + "${{ steps.pr.outputs.result }}" \ + "${{ github.event.workflow_run.head_branch }}" \ + "starting" \ + "$(date -u '${{ env.DATE_FORMAT }}')" + + - name: Download and Deploy Storybook + if: steps.pr.outputs.result != 'null' && github.event.action == 'completed' && github.event.workflow_run.conclusion == 'success' + uses: actions/download-artifact@v4 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + run-id: ${{ github.event.workflow_run.id }} + name: storybook-static + path: storybook-static + + - name: Handle Storybook Completion + if: steps.pr.outputs.result != 'null' && github.event.action == 'completed' + env: + CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} + CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + GITHUB_TOKEN: ${{ github.token }} + WORKFLOW_CONCLUSION: ${{ github.event.workflow_run.conclusion }} + WORKFLOW_URL: ${{ github.event.workflow_run.html_url }} + run: | + chmod +x scripts/cicd/pr-storybook-deploy-and-comment.sh + ./scripts/cicd/pr-storybook-deploy-and-comment.sh \ + "${{ steps.pr.outputs.result }}" \ + "${{ github.event.workflow_run.head_branch }}" \ + "completed" \ No newline at end of file diff --git a/.github/workflows/publish-desktop-ui-on-merge.yaml b/.github/workflows/publish-desktop-ui-on-merge.yaml new file mode 100644 index 000000000..b1adaa0c2 --- /dev/null +++ b/.github/workflows/publish-desktop-ui-on-merge.yaml @@ -0,0 +1,59 @@ +name: Publish Desktop UI on PR Merge + +on: + pull_request: + types: [ closed ] + branches: [ main, core/* ] + paths: + - 'apps/desktop-ui/package.json' + +jobs: + resolve: + name: Resolve Version and Dist Tag + runs-on: ubuntu-latest + if: > + github.event.pull_request.merged == true && + contains(github.event.pull_request.labels.*.name, 'Release') + outputs: + version: ${{ steps.get_version.outputs.version }} + dist_tag: ${{ steps.dist.outputs.dist_tag }} + steps: + - name: Checkout code + uses: actions/checkout@v5 + with: + ref: ${{ github.event.pull_request.merge_commit_sha }} + persist-credentials: false + + - name: Setup Node.js + uses: actions/setup-node@v5 + with: + node-version: '24.x' + + - name: Read desktop-ui version + id: get_version + run: | + VERSION=$(node -p "require('./apps/desktop-ui/package.json').version") + echo "version=$VERSION" >> $GITHUB_OUTPUT + + - name: Determine dist-tag + id: dist + env: + VERSION: ${{ steps.get_version.outputs.version }} + run: | + if [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+- ]]; then + echo "dist_tag=next" >> $GITHUB_OUTPUT + else + echo "dist_tag=latest" >> $GITHUB_OUTPUT + fi + + publish: + name: Publish Desktop UI to npm + needs: resolve + uses: ./.github/workflows/publish-desktop-ui.yaml + with: + version: ${{ needs.resolve.outputs.version }} + dist_tag: ${{ needs.resolve.outputs.dist_tag }} + ref: ${{ github.event.pull_request.merge_commit_sha }} + secrets: + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + diff --git a/.github/workflows/publish-desktop-ui.yaml b/.github/workflows/publish-desktop-ui.yaml new file mode 100644 index 000000000..92324d2f5 --- /dev/null +++ b/.github/workflows/publish-desktop-ui.yaml @@ -0,0 +1,205 @@ +name: Publish Desktop UI + +on: + workflow_dispatch: + inputs: + version: + description: 'Version to publish (e.g., 1.2.3)' + required: true + type: string + dist_tag: + description: 'npm dist-tag to use' + required: true + default: latest + type: string + ref: + description: 'Git ref to checkout (commit SHA, tag, or branch)' + required: false + type: string + workflow_call: + inputs: + version: + required: true + type: string + dist_tag: + required: false + type: string + default: latest + ref: + required: false + type: string + secrets: + NPM_TOKEN: + required: true + +concurrency: + group: publish-desktop-ui-${{ github.workflow }}-${{ inputs.version }}-${{ inputs.dist_tag }} + cancel-in-progress: false + +jobs: + publish_desktop_ui: + name: Publish @comfyorg/desktop-ui + runs-on: ubuntu-latest + permissions: + contents: read + env: + PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: '1' + steps: + - name: Validate inputs + env: + VERSION: ${{ inputs.version }} + shell: bash + run: | + set -euo pipefail + SEMVER_REGEX='^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(-((0|[1-9][0-9]*|[0-9]*[A-Za-z-][0-9A-Za-z-]*)(\.(0|[1-9][0-9]*|[0-9]*[A-Za-z-][0-9A-Za-z-]*))*))?(\+([0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*))?$' + if [[ ! "$VERSION" =~ $SEMVER_REGEX ]]; then + echo "::error title=Invalid version::Version '$VERSION' must follow semantic versioning (x.y.z[-suffix][+build])" >&2 + exit 1 + fi + + - name: Determine ref to checkout + id: resolve_ref + env: + REF: ${{ inputs.ref }} + VERSION: ${{ inputs.version }} + shell: bash + run: | + set -euo pipefail + if [ -n "$REF" ]; then + if ! git check-ref-format --allow-onelevel "$REF"; then + echo "::error title=Invalid ref::Ref '$REF' fails git check-ref-format validation." >&2 + exit 1 + fi + echo "ref=$REF" >> "$GITHUB_OUTPUT" + else + echo "ref=refs/tags/v$VERSION" >> "$GITHUB_OUTPUT" + fi + + - name: Checkout repository + uses: actions/checkout@v5 + with: + ref: ${{ steps.resolve_ref.outputs.ref }} + fetch-depth: 1 + persist-credentials: false + + - name: Install pnpm + uses: pnpm/action-setup@v4 + with: + version: 10 + + - name: Setup Node.js + uses: actions/setup-node@v5 + with: + node-version: '24.x' + cache: 'pnpm' + registry-url: https://registry.npmjs.org + + - name: Install dependencies + run: pnpm install --frozen-lockfile --ignore-scripts + + - name: Build Desktop UI + run: pnpm build:desktop + + - name: Prepare npm package + id: pkg + shell: bash + run: | + set -euo pipefail + APP_PKG=apps/desktop-ui/package.json + ROOT_PKG=package.json + + NAME=$(jq -r .name "$APP_PKG") + APP_VERSION=$(jq -r .version "$APP_PKG") + ROOT_LICENSE=$(jq -r .license "$ROOT_PKG") + REPO=$(jq -r .repository "$ROOT_PKG") + + if [ -z "$NAME" ] || [ "$NAME" = "null" ]; then + echo "::error title=Missing name::apps/desktop-ui/package.json is missing 'name'" >&2 + exit 1 + fi + + INPUT_VERSION="${{ inputs.version }}" + if [ "$APP_VERSION" != "$INPUT_VERSION" ]; then + echo "::error title=Version mismatch::apps/desktop-ui version $APP_VERSION does not match input $INPUT_VERSION" >&2 + exit 1 + fi + + if [ ! -d apps/desktop-ui/dist ]; then + echo "::error title=Missing build::apps/desktop-ui/dist not found. Did build succeed?" >&2 + exit 1 + fi + + PUBLISH_DIR=apps/desktop-ui/.npm-publish + rm -rf "$PUBLISH_DIR" + mkdir -p "$PUBLISH_DIR" + cp -R apps/desktop-ui/dist "$PUBLISH_DIR/dist" + + INPUT_VERSION="${{ inputs.version }}" + jq -n \ + --arg name "$NAME" \ + --arg version "$INPUT_VERSION" \ + --arg description "Static assets for the ComfyUI Desktop UI" \ + --arg license "$ROOT_LICENSE" \ + --arg repository "$REPO" \ + '{ + name: $name, + version: $version, + description: $description, + license: $license, + repository: $repository, + type: "module", + private: false, + files: ["dist"], + publishConfig: { access: "public" } + }' > "$PUBLISH_DIR/package.json" + + if [ -f apps/desktop-ui/README.md ]; then + cp apps/desktop-ui/README.md "$PUBLISH_DIR/README.md" + fi + + echo "publish_dir=$PUBLISH_DIR" >> "$GITHUB_OUTPUT" + echo "name=$NAME" >> "$GITHUB_OUTPUT" + + - name: Pack (preview only) + shell: bash + working-directory: ${{ steps.pkg.outputs.publish_dir }} + run: | + set -euo pipefail + npm pack --json | tee pack-result.json + + - name: Upload package tarball artifact + uses: actions/upload-artifact@v4 + with: + name: desktop-ui-npm-tarball-${{ inputs.version }} + path: ${{ steps.pkg.outputs.publish_dir }}/*.tgz + if-no-files-found: error + + - name: Check if version already on npm + id: check_npm + env: + NAME: ${{ steps.pkg.outputs.name }} + VER: ${{ inputs.version }} + shell: bash + run: | + set -euo pipefail + STATUS=0 + OUTPUT=$(npm view "${NAME}@${VER}" --json 2>&1) || STATUS=$? + if [ "$STATUS" -eq 0 ]; then + echo "exists=true" >> "$GITHUB_OUTPUT" + echo "::warning title=Already published::${NAME}@${VER} already exists on npm. Skipping publish." + else + if echo "$OUTPUT" | grep -q "E404"; then + echo "exists=false" >> "$GITHUB_OUTPUT" + else + echo "::error title=Registry lookup failed::$OUTPUT" >&2 + exit "$STATUS" + fi + fi + + - name: Publish package + if: steps.check_npm.outputs.exists == 'false' + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + DIST_TAG: ${{ inputs.dist_tag }} + run: pnpm publish --access public --tag "$DIST_TAG" --no-git-checks --ignore-scripts + working-directory: ${{ steps.pkg.outputs.publish_dir }} diff --git a/.github/workflows/storybook-and-chromatic-ci.yaml b/.github/workflows/storybook-and-chromatic-ci.yaml new file mode 100644 index 000000000..bfac96530 --- /dev/null +++ b/.github/workflows/storybook-and-chromatic-ci.yaml @@ -0,0 +1,231 @@ +name: Storybook and Chromatic CI + +# - [Automate Chromatic with GitHub Actions • Chromatic docs]( https://www.chromatic.com/docs/github-actions/ ) + +on: + workflow_dispatch: # Allow manual triggering + pull_request: + branches: [main] + +jobs: + # Post starting comment for non-forked PRs + comment-on-pr-start: + runs-on: ubuntu-latest + if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == false + permissions: + pull-requests: write + steps: + - name: Checkout repository + uses: actions/checkout@v5 + + - name: Post starting comment + env: + GITHUB_TOKEN: ${{ github.token }} + run: | + chmod +x scripts/cicd/pr-storybook-deploy-and-comment.sh + ./scripts/cicd/pr-storybook-deploy-and-comment.sh \ + "${{ github.event.pull_request.number }}" \ + "${{ github.head_ref }}" \ + "starting" \ + "$(date -u '+%m/%d/%Y, %I:%M:%S %p')" + + # Build Storybook for all PRs (free Cloudflare deployment) + storybook-build: + runs-on: ubuntu-latest + if: github.event_name == 'pull_request' + outputs: + conclusion: ${{ steps.job-status.outputs.conclusion }} + workflow-url: ${{ steps.workflow-url.outputs.url }} + steps: + - name: Checkout code + uses: actions/checkout@v5 + + - name: Install pnpm + uses: pnpm/action-setup@v4 + with: + version: 10 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'pnpm' + + - name: Cache tool outputs + uses: actions/cache@v4 + with: + path: | + .cache + storybook-static + tsconfig.tsbuildinfo + key: storybook-cache-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}-${{ hashFiles('src/**/*.{ts,vue,js}', '*.config.*', '.storybook/**/*') }} + restore-keys: | + storybook-cache-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}- + storybook-cache-${{ runner.os }}- + storybook-tools-cache-${{ runner.os }}- + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Build Storybook + run: pnpm build-storybook + + - name: Set job status + id: job-status + if: always() + run: | + echo "conclusion=${{ job.status }}" >> $GITHUB_OUTPUT + + - name: Get workflow URL + id: workflow-url + if: always() + run: | + echo "url=${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" >> $GITHUB_OUTPUT + + - name: Upload Storybook build + if: success() && github.event.pull_request.head.repo.fork == false + uses: actions/upload-artifact@v4 + with: + name: storybook-static + path: storybook-static/ + retention-days: 7 + + # Chromatic deployment only for version-bump-* branches or manual triggers + chromatic-deployment: + runs-on: ubuntu-latest + if: github.event_name == 'workflow_dispatch' || (github.event_name == 'pull_request' && startsWith(github.head_ref, 'version-bump-')) + outputs: + conclusion: ${{ steps.job-status.outputs.conclusion }} + workflow-url: ${{ steps.workflow-url.outputs.url }} + chromatic-build-url: ${{ steps.chromatic.outputs.buildUrl }} + chromatic-storybook-url: ${{ steps.chromatic.outputs.storybookUrl }} + steps: + - name: Checkout code + uses: actions/checkout@v5 + with: + fetch-depth: 0 # Required for Chromatic baseline + + - name: Install pnpm + uses: pnpm/action-setup@v4 + with: + version: 10 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'pnpm' + + - name: Cache tool outputs + uses: actions/cache@v4 + with: + path: | + .cache + storybook-static + tsconfig.tsbuildinfo + key: storybook-cache-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}-${{ hashFiles('src/**/*.{ts,vue,js}', '*.config.*', '.storybook/**/*') }} + restore-keys: | + storybook-cache-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}- + storybook-cache-${{ runner.os }}- + storybook-tools-cache-${{ runner.os }}- + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Build Storybook and run Chromatic + id: chromatic + uses: chromaui/action@latest + with: + projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }} + buildScriptName: build-storybook + autoAcceptChanges: 'main' # Auto-accept changes on main branch + exitOnceUploaded: true # Don't wait for UI tests to complete + onlyChanged: true # Only capture changed stories + + - name: Set job status + id: job-status + if: always() + run: | + echo "conclusion=${{ job.status }}" >> $GITHUB_OUTPUT + + - name: Get workflow URL + id: workflow-url + if: always() + run: | + echo "url=${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" >> $GITHUB_OUTPUT + + # Deploy and comment for non-forked PRs only + deploy-and-comment: + needs: [storybook-build] + runs-on: ubuntu-latest + if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == false && always() + permissions: + pull-requests: write + contents: read + steps: + - name: Checkout repository + uses: actions/checkout@v5 + + - name: Download Storybook build + if: needs.storybook-build.outputs.conclusion == 'success' + uses: actions/download-artifact@v4 + with: + name: storybook-static + path: storybook-static + + - name: Make deployment script executable + run: chmod +x scripts/cicd/pr-storybook-deploy-and-comment.sh + + - name: Deploy Storybook and comment on PR + env: + CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} + CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + GITHUB_TOKEN: ${{ github.token }} + WORKFLOW_CONCLUSION: ${{ needs.storybook-build.outputs.conclusion }} + WORKFLOW_URL: ${{ needs.storybook-build.outputs.workflow-url }} + run: | + ./scripts/cicd/pr-storybook-deploy-and-comment.sh \ + "${{ github.event.pull_request.number }}" \ + "${{ github.head_ref }}" \ + "completed" + + # Update comment with Chromatic URLs for version-bump branches + update-comment-with-chromatic: + needs: [chromatic-deployment, deploy-and-comment] + runs-on: ubuntu-latest + if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == false && startsWith(github.head_ref, 'version-bump-') && needs.chromatic-deployment.outputs.chromatic-build-url != '' + permissions: + pull-requests: write + steps: + - name: Update comment with Chromatic URLs + uses: actions/github-script@v7 + with: + script: | + const buildUrl = '${{ needs.chromatic-deployment.outputs.chromatic-build-url }}'; + const storybookUrl = '${{ needs.chromatic-deployment.outputs.chromatic-storybook-url }}'; + + // Find the existing Storybook comment + const { data: comments } = await github.rest.issues.listComments({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: ${{ github.event.pull_request.number }} + }); + + const storybookComment = comments.find(comment => + comment.body.includes('') + ); + + if (storybookComment && buildUrl && storybookUrl) { + // Append Chromatic info to existing comment + const updatedBody = storybookComment.body.replace( + /---\n(.*)$/s, + `---\n### 🎨 Chromatic Visual Tests\n- 📊 [View Chromatic Build](${buildUrl})\n- 📚 [View Chromatic Storybook](${storybookUrl})\n\n$1` + ); + + await github.rest.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: storybookComment.id, + body: updatedBody + }); + } diff --git a/.github/workflows/test-ui.yaml b/.github/workflows/tests-ci.yaml similarity index 81% rename from .github/workflows/test-ui.yaml rename to .github/workflows/tests-ci.yaml index 640615d99..1e069ea11 100644 --- a/.github/workflows/test-ui.yaml +++ b/.github/workflows/tests-ci.yaml @@ -12,17 +12,16 @@ jobs: runs-on: ubuntu-latest outputs: cache-key: ${{ steps.cache-key.outputs.key }} - playwright-version: ${{ steps.playwright-version.outputs.PLAYWRIGHT_VERSION }} steps: - name: Checkout ComfyUI - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: repository: 'comfyanonymous/ComfyUI' path: 'ComfyUI' ref: master - name: Checkout ComfyUI_frontend - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: repository: 'Comfy-Org/ComfyUI_frontend' path: 'ComfyUI_frontend' @@ -65,12 +64,6 @@ jobs: id: cache-key run: echo "key=$(date +%s)" >> $GITHUB_OUTPUT - - name: Playwright Version - id: playwright-version - run: | - PLAYWRIGHT_VERSION=$(pnpm ls @playwright/test --json | jq --raw-output '.[0].devDependencies["@playwright/test"].version') - echo "PLAYWRIGHT_VERSION=$PLAYWRIGHT_VERSION" >> $GITHUB_OUTPUT - working-directory: ComfyUI_frontend - name: Save cache uses: actions/cache/save@5a3ec84eff668545956fd18022155c47e93e2684 @@ -96,7 +89,7 @@ jobs: run: sleep 10 - name: Restore cached setup - uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 + uses: actions/cache/restore@v4 with: fail-on-cache-miss: true path: | @@ -123,22 +116,8 @@ jobs: working-directory: ComfyUI - - name: Cache Playwright Browsers - uses: actions/cache@v4 - id: cache-playwright-browsers - with: - path: '~/.cache/ms-playwright' - key: '${{ runner.os }}-playwright-browsers-${{ needs.setup.outputs.playwright-version }}' - - - name: Install Playwright Browsers - if: steps.cache-playwright-browsers.outputs.cache-hit != 'true' - run: pnpm exec playwright install chromium --with-deps - working-directory: ComfyUI_frontend - - - name: Install Playwright Browsers (operating system dependencies) - if: steps.cache-playwright-browsers.outputs.cache-hit == 'true' - run: pnpm exec playwright install-deps - working-directory: ComfyUI_frontend + - name: Setup Playwright + uses: ./ComfyUI_frontend/.github/actions/setup-playwright - name: Start ComfyUI server run: | @@ -176,7 +155,7 @@ jobs: run: sleep 10 - name: Restore cached setup - uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 + uses: actions/cache/restore@v4 with: fail-on-cache-miss: true path: | @@ -202,22 +181,8 @@ jobs: pip install wait-for-it working-directory: ComfyUI - - name: Cache Playwright Browsers - uses: actions/cache@v4 - id: cache-playwright-browsers - with: - path: '~/.cache/ms-playwright' - key: '${{ runner.os }}-playwright-browsers-${{ needs.setup.outputs.playwright-version }}' - - - name: Install Playwright Browsers - if: steps.cache-playwright-browsers.outputs.cache-hit != 'true' - run: pnpm exec playwright install chromium --with-deps - working-directory: ComfyUI_frontend - - - name: Install Playwright Browsers (operating system dependencies) - if: steps.cache-playwright-browsers.outputs.cache-hit == 'true' - run: pnpm exec playwright install-deps - working-directory: ComfyUI_frontend + - name: Setup Playwright + uses: ./ComfyUI_frontend/.github/actions/setup-playwright - name: Start ComfyUI server run: | @@ -250,7 +215,7 @@ jobs: if: ${{ !cancelled() }} steps: - name: Checkout ComfyUI_frontend - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: repository: 'Comfy-Org/ComfyUI_frontend' path: 'ComfyUI_frontend' @@ -306,7 +271,7 @@ jobs: pull-requests: write steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Get start time id: start-time @@ -333,7 +298,7 @@ jobs: contents: read steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Download all playwright reports uses: actions/download-artifact@v4 @@ -354,4 +319,4 @@ jobs: "${{ github.event.pull_request.number }}" \ "${{ github.head_ref }}" \ "completed" - #### END Deployment and commenting (non-forked PRs only) \ No newline at end of file + #### END Deployment and commenting (non-forked PRs only) diff --git a/.github/workflows/update-registry-types.yaml b/.github/workflows/update-comfy-registry-api-types.yaml similarity index 85% rename from .github/workflows/update-registry-types.yaml rename to .github/workflows/update-comfy-registry-api-types.yaml index 4a84e9f43..41a4db9ab 100644 --- a/.github/workflows/update-registry-types.yaml +++ b/.github/workflows/update-comfy-registry-api-types.yaml @@ -16,7 +16,7 @@ jobs: pull-requests: write steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Install pnpm uses: pnpm/action-setup@v4 @@ -50,7 +50,7 @@ jobs: comfy-api-repo-${{ runner.os }}- - name: Checkout comfy-api repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: repository: Comfy-Org/comfy-api path: comfy-api @@ -68,17 +68,18 @@ jobs: - name: Generate API types run: | echo "Generating TypeScript types from comfy-api@${{ steps.api-info.outputs.commit }}..." - pnpm dlx openapi-typescript ./comfy-api/openapi.yml --output ./src/types/comfyRegistryTypes.ts + mkdir -p ./packages/registry-types/src + pnpm dlx openapi-typescript ./comfy-api/openapi.yml --output ./packages/registry-types/src/comfyRegistryTypes.ts - name: Validate generated types run: | - if [ ! -f ./src/types/comfyRegistryTypes.ts ]; then + if [ ! -f ./packages/registry-types/src/comfyRegistryTypes.ts ]; then echo "Error: Types file was not generated." exit 1 fi # Check if file is not empty - if [ ! -s ./src/types/comfyRegistryTypes.ts ]; then + if [ ! -s ./packages/registry-types/src/comfyRegistryTypes.ts ]; then echo "Error: Generated types file is empty." exit 1 fi @@ -86,12 +87,12 @@ jobs: - name: Lint generated types run: | echo "Linting generated Comfy Registry API types..." - pnpm lint:fix:no-cache -- ./src/types/comfyRegistryTypes.ts + pnpm lint:fix:no-cache -- ./packages/registry-types/src/comfyRegistryTypes.ts - name: Check for changes id: check-changes run: | - if [[ -z $(git status --porcelain ./src/types/comfyRegistryTypes.ts) ]]; then + if [[ -z $(git status --porcelain ./packages/registry-types/src/comfyRegistryTypes.ts) ]]; then echo "No changes to Comfy Registry API types detected." echo "changed=false" >> $GITHUB_OUTPUT exit 0 @@ -121,4 +122,4 @@ jobs: labels: CNR delete-branch: true add-paths: | - src/types/comfyRegistryTypes.ts + packages/registry-types/src/comfyRegistryTypes.ts diff --git a/.github/workflows/update-manager-types.yaml b/.github/workflows/update-comfyui-manager-api-types.yaml similarity index 98% rename from .github/workflows/update-manager-types.yaml rename to .github/workflows/update-comfyui-manager-api-types.yaml index de5b799da..7e307dfda 100644 --- a/.github/workflows/update-manager-types.yaml +++ b/.github/workflows/update-comfyui-manager-api-types.yaml @@ -17,7 +17,7 @@ jobs: pull-requests: write steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Install pnpm uses: pnpm/action-setup@v4 @@ -51,7 +51,7 @@ jobs: comfyui-manager-repo-${{ runner.os }}- - name: Checkout ComfyUI-Manager repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: repository: Comfy-Org/ComfyUI-Manager path: ComfyUI-Manager diff --git a/.github/workflows/update-electron-types.yaml b/.github/workflows/update-electron-types.yaml index 96f85f6b0..45d959b86 100644 --- a/.github/workflows/update-electron-types.yaml +++ b/.github/workflows/update-electron-types.yaml @@ -12,7 +12,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Install pnpm uses: pnpm/action-setup@v4 diff --git a/.github/workflows/i18n-custom-nodes.yaml b/.github/workflows/update-locales-for-given-custom-node-repository.yaml similarity index 96% rename from .github/workflows/i18n-custom-nodes.yaml rename to .github/workflows/update-locales-for-given-custom-node-repository.yaml index 959d01739..ec085eab5 100644 --- a/.github/workflows/i18n-custom-nodes.yaml +++ b/.github/workflows/update-locales-for-given-custom-node-repository.yaml @@ -22,13 +22,13 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout ComfyUI - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: repository: comfyanonymous/ComfyUI path: ComfyUI ref: master - name: Checkout ComfyUI_frontend - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: repository: Comfy-Org/ComfyUI_frontend path: ComfyUI_frontend @@ -37,7 +37,7 @@ jobs: mkdir -p ComfyUI/custom_nodes/ComfyUI_devtools cp -r ComfyUI_frontend/tools/devtools/* ComfyUI/custom_nodes/ComfyUI_devtools/ - name: Checkout custom node repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: repository: ${{ inputs.owner }}/${{ inputs.repository }} path: 'ComfyUI/custom_nodes/${{ inputs.repository }}' @@ -77,9 +77,8 @@ jobs: python main.py --cpu --multi-user & wait-for-it --service 127.0.0.1:8188 -t 600 working-directory: ComfyUI - - name: Install Playwright Browsers - run: pnpm exec playwright install chromium --with-deps - working-directory: ComfyUI_frontend + - name: Setup Playwright + uses: ./ComfyUI_frontend/.github/actions/setup-playwright - name: Start dev server # Run electron dev server as it is a superset of the web dev server # We do want electron specific UIs to be translated. diff --git a/.github/workflows/i18n.yaml b/.github/workflows/update-locales.yaml similarity index 81% rename from .github/workflows/i18n.yaml rename to .github/workflows/update-locales.yaml index 566a335b5..3bf939b23 100644 --- a/.github/workflows/i18n.yaml +++ b/.github/workflows/update-locales.yaml @@ -14,7 +14,8 @@ jobs: if: github.event_name == 'workflow_dispatch' || (github.event.pull_request.head.repo.full_name == github.repository && startsWith(github.head_ref, 'version-bump-')) runs-on: ubuntu-latest steps: - - uses: Comfy-Org/ComfyUI_frontend_setup_action@v3 + - name: Setup Frontend + uses: ./.github/actions/setup-frontend - name: Cache tool outputs uses: actions/cache@v4 @@ -25,16 +26,8 @@ jobs: key: i18n-tools-cache-${{ runner.os }}-${{ hashFiles('ComfyUI_frontend/pnpm-lock.yaml') }} restore-keys: | i18n-tools-cache-${{ runner.os }}- - - name: Cache Playwright browsers - uses: actions/cache@v4 - with: - path: ~/.cache/ms-playwright - key: playwright-browsers-${{ runner.os }}-${{ hashFiles('ComfyUI_frontend/pnpm-lock.yaml') }} - restore-keys: | - playwright-browsers-${{ runner.os }}- - - name: Install Playwright Browsers - run: pnpm exec playwright install chromium --with-deps - working-directory: ComfyUI_frontend + - name: Setup Playwright + uses: ./.github/actions/setup-playwright - name: Start dev server # Run electron dev server as it is a superset of the web dev server # We do want electron specific UIs to be translated. diff --git a/.github/workflows/i18n-node-defs.yaml b/.github/workflows/update-node-definitions-locales.yaml similarity index 91% rename from .github/workflows/i18n-node-defs.yaml rename to .github/workflows/update-node-definitions-locales.yaml index d9105a4ac..b063159dd 100644 --- a/.github/workflows/i18n-node-defs.yaml +++ b/.github/workflows/update-node-definitions-locales.yaml @@ -14,9 +14,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: Comfy-Org/ComfyUI_frontend_setup_action@v3 - - name: Install Playwright Browsers - run: pnpm exec playwright install chromium --with-deps - working-directory: ComfyUI_frontend + - name: Setup Playwright + uses: ./.github/actions/setup-playwright - name: Start dev server # Run electron dev server as it is a superset of the web dev server # We do want electron specific UIs to be translated. diff --git a/.github/workflows/test-browser-exp.yaml b/.github/workflows/update-playwright-expectations.yaml similarity index 68% rename from .github/workflows/test-browser-exp.yaml rename to .github/workflows/update-playwright-expectations.yaml index e174e89c3..cc0126b7f 100644 --- a/.github/workflows/test-browser-exp.yaml +++ b/.github/workflows/update-playwright-expectations.yaml @@ -10,17 +10,12 @@ jobs: runs-on: ubuntu-latest if: github.event.label.name == 'New Browser Test Expectations' steps: - - uses: Comfy-Org/ComfyUI_frontend_setup_action@v3 - - name: Cache Playwright browsers - uses: actions/cache@v4 - with: - path: ~/.cache/ms-playwright - key: playwright-browsers-${{ runner.os }}-${{ hashFiles('ComfyUI_frontend/pnpm-lock.yaml') }} - restore-keys: | - playwright-browsers-${{ runner.os }}- - - name: Install Playwright Browsers - run: pnpm exec playwright install chromium --with-deps - working-directory: ComfyUI_frontend + - name: Checkout workflow repo + uses: actions/checkout@v5 + - name: Setup Frontend + uses: ./.github/actions/setup-frontend + - name: Setup Playwright + uses: ./.github/actions/setup-playwright - name: Run Playwright tests and update snapshots id: playwright-tests run: pnpm exec playwright test --update-snapshots @@ -44,6 +39,6 @@ jobs: git fetch origin ${{ github.head_ref }} git checkout -B ${{ github.head_ref }} origin/${{ github.head_ref }} git add browser_tests - git commit -m "Update test expectations [skip ci]" + git commit -m "[automated] Update test expectations" git push origin HEAD:${{ github.head_ref }} working-directory: ComfyUI_frontend diff --git a/.github/workflows/validate-json.yaml b/.github/workflows/validate-json.yaml new file mode 100644 index 000000000..2986d23ed --- /dev/null +++ b/.github/workflows/validate-json.yaml @@ -0,0 +1,15 @@ +name: Validate JSON + +on: + push: + branches: + - main + pull_request: + +jobs: + json-lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v5 + - name: Validate JSON syntax + run: ./scripts/cicd/check-json.sh diff --git a/.github/workflows/version-bump-desktop-ui.yaml b/.github/workflows/version-bump-desktop-ui.yaml new file mode 100644 index 000000000..6d5d01c67 --- /dev/null +++ b/.github/workflows/version-bump-desktop-ui.yaml @@ -0,0 +1,71 @@ +name: Version Bump Desktop UI + +on: + workflow_dispatch: + inputs: + version_type: + description: 'Version increment type' + required: true + default: 'patch' + type: 'choice' + options: [patch, minor, major, prepatch, preminor, premajor, prerelease] + pre_release: + description: Pre-release ID (suffix) + required: false + default: '' + type: string + +jobs: + bump-version-desktop-ui: + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + + steps: + - name: Checkout repository + uses: actions/checkout@v5 + with: + persist-credentials: false + + - name: Install pnpm + uses: pnpm/action-setup@v4 + with: + version: 10 + + - name: Setup Node.js + uses: actions/setup-node@v5 + with: + node-version: '24.x' + cache: 'pnpm' + + - name: Bump desktop-ui version + id: bump-version + env: + VERSION_TYPE: ${{ github.event.inputs.version_type }} + PRE_RELEASE: ${{ github.event.inputs.pre_release }} + run: | + pnpm -C apps/desktop-ui version "$VERSION_TYPE" --preid "$PRE_RELEASE" --no-git-tag-version + NEW_VERSION=$(node -p "require('./apps/desktop-ui/package.json').version") + echo "NEW_VERSION=$NEW_VERSION" >> $GITHUB_OUTPUT + + - name: Format PR string + id: capitalised + env: + VERSION_TYPE: ${{ github.event.inputs.version_type }} + run: | + echo "capitalised=${VERSION_TYPE@u}" >> $GITHUB_OUTPUT + + - name: Create Pull Request + uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e + with: + token: ${{ secrets.PR_GH_TOKEN }} + commit-message: '[release] Increment desktop-ui to ${{ steps.bump-version.outputs.NEW_VERSION }}' + title: desktop-ui ${{ steps.bump-version.outputs.NEW_VERSION }} + body: | + ${{ steps.capitalised.outputs.capitalised }} version increment for @comfyorg/desktop-ui to ${{ steps.bump-version.outputs.NEW_VERSION }} + branch: desktop-ui-version-bump-${{ steps.bump-version.outputs.NEW_VERSION }} + base: main + labels: | + Release + diff --git a/.github/workflows/version-bump.yaml b/.github/workflows/version-bump.yaml index 77021e5c7..4073729db 100644 --- a/.github/workflows/version-bump.yaml +++ b/.github/workflows/version-bump.yaml @@ -24,7 +24,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Install pnpm uses: pnpm/action-setup@v4 diff --git a/.github/workflows/vitest-tests.yaml b/.github/workflows/vitest-tests.yaml new file mode 100644 index 000000000..46155d912 --- /dev/null +++ b/.github/workflows/vitest-tests.yaml @@ -0,0 +1,44 @@ +name: Vitest Tests + +on: + push: + branches: [main, master, dev*, core/*, desktop/*] + pull_request: + branches-ignore: [wip/*, draft/*, temp/*] + +jobs: + test: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v5 + + - name: Install pnpm + uses: pnpm/action-setup@v4 + with: + version: 10 + + - name: Use Node.js + uses: actions/setup-node@v4 + with: + node-version: "lts/*" + cache: "pnpm" + + - name: Cache tool outputs + uses: actions/cache@v4 + with: + path: | + .cache + coverage + .vitest-cache + key: vitest-cache-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}-${{ hashFiles('src/**/*.{ts,vue,js}', 'vitest.config.*', 'tsconfig.json') }} + restore-keys: | + vitest-cache-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}- + vitest-cache-${{ runner.os }}- + test-tools-cache-${{ runner.os }}- + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Run Vitest tests + run: pnpm test:unit diff --git a/.github/workflows/vitest.yaml b/.github/workflows/vitest.yaml deleted file mode 100644 index cba1dbe05..000000000 --- a/.github/workflows/vitest.yaml +++ /dev/null @@ -1,46 +0,0 @@ -name: Vitest Tests - -on: - push: - branches: [ main, master, dev*, core/*, desktop/* ] - pull_request: - branches-ignore: [ wip/*, draft/*, temp/* ] - -jobs: - test: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - - - name: Install pnpm - uses: pnpm/action-setup@v4 - with: - version: 10 - - - name: Use Node.js - uses: actions/setup-node@v4 - with: - node-version: 'lts/*' - cache: 'pnpm' - - - name: Cache tool outputs - uses: actions/cache@v4 - with: - path: | - .cache - coverage - .vitest-cache - key: vitest-cache-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}-${{ hashFiles('src/**/*.{ts,vue,js}', 'vitest.config.*', 'tsconfig.json') }} - restore-keys: | - vitest-cache-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}- - vitest-cache-${{ runner.os }}- - test-tools-cache-${{ runner.os }}- - - - name: Install dependencies - run: pnpm install --frozen-lockfile - - - name: Run Vitest tests - run: | - pnpm test:component - pnpm test:unit diff --git a/.gitignore b/.gitignore index e5bb5f107..8f69ce164 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,7 @@ yarn.lock # Cache files .eslintcache .prettiercache +.stylelintcache node_modules dist @@ -31,6 +32,7 @@ CLAUDE.local.md *.code-workspace !.vscode/extensions.json !.vscode/tailwind.json +!.vscode/custom-css.json !.vscode/settings.json.default !.vscode/launch.json.default .idea diff --git a/.npmrc b/.npmrc index ae90f7051..1b28e47ce 100644 --- a/.npmrc +++ b/.npmrc @@ -1 +1,2 @@ ignore-workspace-root-check=true +catalog-mode=prefer diff --git a/.prettierignore b/.prettierignore index cccae51c9..4403edd8e 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,2 +1,2 @@ -src/types/comfyRegistryTypes.ts -src/types/generatedManagerTypes.ts \ No newline at end of file +packages/registry-types/src/comfyRegistryTypes.ts +src/types/generatedManagerTypes.ts diff --git a/.storybook/CLAUDE.md b/.storybook/CLAUDE.md index 3877181a2..ca8248784 100644 --- a/.storybook/CLAUDE.md +++ b/.storybook/CLAUDE.md @@ -4,7 +4,7 @@ - `pnpm storybook`: Start Storybook development server - `pnpm build-storybook`: Build static Storybook -- `pnpm test:component`: Run component tests (includes Storybook components) +- `pnpm test:unit`: Run unit tests (includes Storybook components) ## Development Workflow for Storybook diff --git a/.storybook/main.ts b/.storybook/main.ts index e8021974b..d61f72eae 100644 --- a/.storybook/main.ts +++ b/.storybook/main.ts @@ -76,11 +76,6 @@ const config: StorybookConfig = { }, build: { rollupOptions: { - external: () => { - // Don't externalize any modules in Storybook build - // This ensures PrimeVue and other dependencies are bundled - return false - }, onwarn: (warning, warn) => { // Suppress specific warnings if ( diff --git a/.stylelintrc.json b/.stylelintrc.json new file mode 100644 index 000000000..e53789123 --- /dev/null +++ b/.stylelintrc.json @@ -0,0 +1,73 @@ +{ + "extends": [], + "overrides": [ + { + "files": ["*.vue", "**/*.vue"], + "customSyntax": "postcss-html" + } + ], + "rules": { + "import-notation": "url", + "font-family-no-missing-generic-family-keyword": true, + "declaration-block-no-redundant-longhand-properties": true, + "declaration-property-value-no-unknown": [ + true, + { + "ignoreProperties": { + "speak": ["none"], + "app-region": ["drag", "no-drag"] + } + } + ], + "color-function-notation": "modern", + "shorthand-property-no-redundant-values": true, + "selector-pseudo-element-colon-notation": "double", + "no-duplicate-selectors": true, + "font-weight-notation": "numeric", + "length-zero-no-unit": true, + "color-no-invalid-hex": true, + "number-max-precision": 4, + "property-no-vendor-prefix": true, + "value-no-vendor-prefix": true, + "selector-no-vendor-prefix": true, + "media-feature-name-no-vendor-prefix": true, + "selector-max-universal": 1, + "selector-max-type": 2, + "declaration-block-no-duplicate-properties": true, + "block-no-empty": true, + "no-descending-specificity": true, + "no-duplicate-at-import-rules": true, + "at-rule-no-unknown": [ + true, + { + "ignoreAtRules": [ + "tailwind", + "apply", + "layer", + "config", + "theme", + "reference", + "plugin", + "custom-variant", + "utility" + ] + } + ], + "function-no-unknown": [ + true, + { + "ignoreFunctions": [ + "theme" + ] + } + ] + }, + "ignoreFiles": [ + "node_modules/**", + "dist/**", + "playwright-report/**", + "public/**", + "src/lib/litegraph/**" + ], + "files": ["**/*.css", "**/*.vue"] +} diff --git a/.vscode/custom-css.json b/.vscode/custom-css.json new file mode 100644 index 000000000..67aa038b4 --- /dev/null +++ b/.vscode/custom-css.json @@ -0,0 +1,50 @@ +{ + "version": 1.1, + "properties": [ + { + "name": "app-region", + "description": "Electron-specific CSS property that defines draggable regions in custom title bar windows. Setting 'drag' marks a rectangular area as draggable for moving the window; 'no-drag' excludes areas from the draggable region.", + "values": [ + { + "name": "drag", + "description": "Marks the element as draggable for moving the Electron window" + }, + { + "name": "no-drag", + "description": "Excludes the element from being used to drag the Electron window" + } + ], + "references": [ + { + "name": "Electron Window Customization", + "url": "https://www.electronjs.org/docs/latest/tutorial/window-customization" + } + ] + }, + { + "name": "speak", + "description": "Deprecated CSS2 aural stylesheet property for controlling screen reader speech. Use ARIA attributes instead.", + "values": [ + { + "name": "auto", + "description": "Content is read aurally if element is not a block and is visible" + }, + { + "name": "never", + "description": "Content will not be read aurally" + }, + { + "name": "always", + "description": "Content will be read aurally regardless of display settings" + } + ], + "references": [ + { + "name": "CSS-Tricks Reference", + "url": "https://css-tricks.com/almanac/properties/s/speak/" + } + ], + "status": "obsolete" + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json.default b/.vscode/settings.json.default index f1ed5fba6..18a614290 100644 --- a/.vscode/settings.json.default +++ b/.vscode/settings.json.default @@ -1,5 +1,6 @@ { "css.customData": [ - ".vscode/tailwind.json" + ".vscode/tailwind.json", + ".vscode/custom-css.json" ] } diff --git a/.vscode/tailwind.json b/.vscode/tailwind.json index 4efd1d966..659c28859 100644 --- a/.vscode/tailwind.json +++ b/.vscode/tailwind.json @@ -7,7 +7,7 @@ "references": [ { "name": "Tailwind Documentation", - "url": "https://tailwindcss.com/docs/functions-and-directives#import" + "url": "https://tailwindcss.com/docs/functions-and-directives#import-directive" } ] }, @@ -17,7 +17,7 @@ "references": [ { "name": "Tailwind Documentation", - "url": "https://tailwindcss.com/docs/functions-and-directives#theme" + "url": "https://tailwindcss.com/docs/functions-and-directives#theme-directive" } ] }, @@ -27,17 +27,17 @@ "references": [ { "name": "Tailwind Documentation", - "url": "https://tailwindcss.com/docs/functions-and-directives#layer" + "url": "https://tailwindcss.com/docs/theme#layers" } ] }, { "name": "@apply", - "description": "Use the `@apply` directive to inline any existing utility classes into your own custom CSS. This is useful when you find a common utility pattern in your HTML that you’d like to extract to a new component.", + "description": "DO NOT USE. IF YOU ARE CAUGHT USING @apply YOU WILL FACE SEVERE CONSEQUENCES.", "references": [ { "name": "Tailwind Documentation", - "url": "https://tailwindcss.com/docs/functions-and-directives#apply" + "url": "https://tailwindcss.com/docs/functions-and-directives#apply-directive" } ] }, @@ -47,7 +47,7 @@ "references": [ { "name": "Tailwind Documentation", - "url": "https://tailwindcss.com/docs/functions-and-directives#config" + "url": "https://tailwindcss.com/docs/functions-and-directives#config-directive" } ] }, @@ -57,7 +57,7 @@ "references": [ { "name": "Tailwind Documentation", - "url": "https://tailwindcss.com/docs/functions-and-directives#reference" + "url": "https://tailwindcss.com/docs/functions-and-directives#reference-directive" } ] }, @@ -67,7 +67,27 @@ "references": [ { "name": "Tailwind Documentation", - "url": "https://tailwindcss.com/docs/functions-and-directives#plugin" + "url": "https://tailwindcss.com/docs/functions-and-directives#plugin-directive" + } + ] + }, + { + "name": "@custom-variant", + "description": "Use the `@custom-variant` directive to add a custom variant to your project. Custom variants can be used with utilities like `hover`, `focus`, and responsive breakpoints. Use `@slot` inside the variant to indicate where the utility's styles should be inserted.", + "references": [ + { + "name": "Tailwind Documentation", + "url": "https://tailwindcss.com/docs/adding-custom-styles#adding-custom-variants" + } + ] + }, + { + "name": "@utility", + "description": "Use the `@utility` directive to add custom utilities to your project. Custom utilities work with all variants like `hover`, `focus`, and responsive variants. Use `--value()` to create functional utilities that accept arguments.", + "references": [ + { + "name": "Tailwind Documentation", + "url": "https://tailwindcss.com/docs/adding-custom-styles#adding-custom-utilities" } ] } diff --git a/AGENTS.md b/AGENTS.md index 5cec6b810..59c9af1cd 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -12,8 +12,7 @@ - `pnpm dev:electron`: Dev server with Electron API mocks. - `pnpm build`: Type-check then production build to `dist/`. - `pnpm preview`: Preview the production build locally. -- `pnpm test:unit`: Run Vitest unit tests (`tests-ui/`). -- `pnpm test:component`: Run component tests (`src/components/`). +- `pnpm test:unit`: Run Vitest unit tests. - `pnpm test:browser`: Run Playwright E2E tests (`browser_tests/`). - `pnpm lint` / `pnpm lint:fix`: Lint (ESLint). `pnpm format` / `format:check`: Prettier. - `pnpm typecheck`: Vue TSC type checking. @@ -31,10 +30,9 @@ - Playwright: place tests in `browser_tests/`; optional tags like `@mobile`, `@2x` are respected by config. ## Commit & Pull Request Guidelines -- Commits: Prefer Conventional Commits (e.g., `feat(ui): add sidebar`), `refactor(litegraph): …`. Use `[skip ci]` for locale-only updates when appropriate. -- PRs: Include clear description, linked issues (`Fixes #123`), and screenshots/GIFs for UI changes. Add/adjust tests and i18n strings when applicable. +- Commits: Use `[skip ci]` for locale-only updates when appropriate. +- PRs: Include clear description, linked issues (`- Fixes #123`), and screenshots/GIFs for UI changes. - Quality gates: `pnpm lint`, `pnpm typecheck`, and relevant tests must pass. Keep PRs focused and small. ## Security & Configuration Tips - Secrets: Use `.env` (see `.env_example`); do not commit secrets. -- Backend: Dev server expects ComfyUI backend at `localhost:8188` by default; configure via `.env`. diff --git a/CLAUDE.md b/CLAUDE.md index 68be11a12..74e656f00 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -18,7 +18,6 @@ This bootstraps the monorepo with dependencies, builds, tests, and dev server ve - `pnpm build`: Build for production (via nx) - `pnpm lint`: Linting (via nx) - `pnpm format`: Prettier formatting -- `pnpm test:component`: Run component tests with browser environment - `pnpm test:unit`: Run all unit tests - `pnpm test:browser`: Run E2E tests via Playwright - `pnpm test:unit -- tests-ui/tests/example.test.ts`: Run single test file diff --git a/CODEOWNERS b/CODEOWNERS index cd1b4e508..d3517e2ab 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,12 +1,7 @@ # Desktop/Electron -/src/types/desktop/ @webfiltered -/src/constants/desktopDialogs.ts @webfiltered -/src/constants/desktopMaintenanceTasks.ts @webfiltered +/apps/desktop-ui/ @webfiltered /src/stores/electronDownloadStore.ts @webfiltered /src/extensions/core/electronAdapter.ts @webfiltered -/src/views/DesktopDialogView.vue @webfiltered -/src/components/install/ @webfiltered -/src/components/maintenance/ @webfiltered /vite.electron.config.mts @webfiltered # Common UI Components diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6614fe619..135a9db01 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -213,12 +213,6 @@ Here's how Claude Code can use the Playwright MCP server to inspect the interfac - `pnpm i` to install all dependencies - `pnpm test:unit` to execute all unit tests -### Component Tests - -Component tests verify Vue components in `src/components/`. - -- `pnpm test:component` to execute all component tests - ### Playwright Tests Playwright tests verify the whole app. See [browser_tests/README.md](browser_tests/README.md) for details. @@ -229,7 +223,6 @@ Before submitting a PR, ensure all tests pass: ```bash pnpm test:unit -pnpm test:component pnpm test:browser pnpm typecheck pnpm lint diff --git a/apps/desktop-ui/.storybook/main.ts b/apps/desktop-ui/.storybook/main.ts new file mode 100644 index 000000000..91c29eb7a --- /dev/null +++ b/apps/desktop-ui/.storybook/main.ts @@ -0,0 +1,103 @@ +import type { StorybookConfig } from '@storybook/vue3-vite' +import { FileSystemIconLoader } from 'unplugin-icons/loaders' +import IconsResolver from 'unplugin-icons/resolver' +import Icons from 'unplugin-icons/vite' +import Components from 'unplugin-vue-components/vite' +import type { InlineConfig } from 'vite' + +const config: StorybookConfig = { + stories: ['../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'], + addons: ['@storybook/addon-docs'], + framework: { + name: '@storybook/vue3-vite', + options: {} + }, + staticDirs: [{ from: '../public', to: '/' }], + async viteFinal(config) { + // Use dynamic import to avoid CJS deprecation warning + const { mergeConfig } = await import('vite') + const { default: tailwindcss } = await import('@tailwindcss/vite') + + // Filter out any plugins that might generate import maps + if (config.plugins) { + config.plugins = config.plugins + // Type guard: ensure we have valid plugin objects with names + .filter( + (plugin): plugin is NonNullable & { name: string } => { + return ( + plugin !== null && + plugin !== undefined && + typeof plugin === 'object' && + 'name' in plugin && + typeof plugin.name === 'string' + ) + } + ) + // Business logic: filter out import-map plugins + .filter((plugin) => !plugin.name.includes('import-map')) + } + + return mergeConfig(config, { + // Replace plugins entirely to avoid inheritance issues + plugins: [ + // Only include plugins we explicitly need for Storybook + tailwindcss(), + Icons({ + compiler: 'vue3', + customCollections: { + comfy: FileSystemIconLoader( + process.cwd() + '/../../packages/design-system/src/icons' + ) + } + }), + Components({ + dts: false, // Disable dts generation in Storybook + resolvers: [ + IconsResolver({ + customCollections: ['comfy'] + }) + ], + dirs: [ + process.cwd() + '/src/components', + process.cwd() + '/src/views' + ], + deep: true, + extensions: ['vue'], + directoryAsNamespace: true + }) + ], + server: { + allowedHosts: true + }, + resolve: { + alias: { + '@': process.cwd() + '/src', + '@frontend-locales': process.cwd() + '/../../src/locales' + } + }, + build: { + rollupOptions: { + onwarn: (warning, warn) => { + // Suppress specific warnings + if ( + warning.code === 'UNUSED_EXTERNAL_IMPORT' && + warning.message?.includes('resolveComponent') + ) { + return + } + // Suppress Storybook font asset warnings + if ( + warning.code === 'UNRESOLVED_IMPORT' && + warning.message?.includes('nunito-sans') + ) { + return + } + warn(warning) + } + }, + chunkSizeWarningLimit: 1000 + } + } satisfies InlineConfig) + } +} +export default config diff --git a/apps/desktop-ui/.storybook/preview.ts b/apps/desktop-ui/.storybook/preview.ts new file mode 100644 index 000000000..a0ead30cc --- /dev/null +++ b/apps/desktop-ui/.storybook/preview.ts @@ -0,0 +1,88 @@ +import { definePreset } from '@primevue/themes' +import Aura from '@primevue/themes/aura' +import { setup } from '@storybook/vue3' +import type { Preview, StoryContext, StoryFn } from '@storybook/vue3-vite' +import { createPinia } from 'pinia' +import 'primeicons/primeicons.css' +import PrimeVue from 'primevue/config' +import ConfirmationService from 'primevue/confirmationservice' +import ToastService from 'primevue/toastservice' +import Tooltip from 'primevue/tooltip' + +import '@/assets/css/style.css' +import { i18n } from '@/i18n' + +const ComfyUIPreset = definePreset(Aura, { + semantic: { + // @ts-expect-error prime type quirk + primary: Aura['primitive'].blue + } +}) + +setup((app) => { + app.directive('tooltip', Tooltip) + + const pinia = createPinia() + + app.use(pinia) + app.use(i18n) + app.use(PrimeVue, { + theme: { + preset: ComfyUIPreset, + options: { + prefix: 'p', + cssLayer: { name: 'primevue', order: 'primevue, tailwind-utilities' }, + darkModeSelector: '.dark-theme, :root:has(.dark-theme)' + } + } + }) + app.use(ConfirmationService) + app.use(ToastService) +}) + +export const withTheme = (Story: StoryFn, context: StoryContext) => { + const theme = context.globals.theme || 'light' + if (theme === 'dark') { + document.documentElement.classList.add('dark-theme') + document.body.classList.add('dark-theme') + } else { + document.documentElement.classList.remove('dark-theme') + document.body.classList.remove('dark-theme') + } + + return Story(context.args, context) +} + +const preview: Preview = { + parameters: { + controls: { + matchers: { color: /(background|color)$/i, date: /Date$/i } + }, + backgrounds: { + default: 'light', + values: [ + { name: 'light', value: '#ffffff' }, + { name: 'dark', value: '#0a0a0a' } + ] + } + }, + globalTypes: { + theme: { + name: 'Theme', + description: 'Global theme for components', + defaultValue: 'light', + toolbar: { + icon: 'circlehollow', + items: [ + { value: 'light', icon: 'sun', title: 'Light' }, + { value: 'dark', icon: 'moon', title: 'Dark' } + ], + showName: true, + dynamicTitle: true + } + } + }, + decorators: [withTheme] +} + +export default preview diff --git a/apps/desktop-ui/index.html b/apps/desktop-ui/index.html new file mode 100644 index 000000000..5cb34ffc2 --- /dev/null +++ b/apps/desktop-ui/index.html @@ -0,0 +1,12 @@ + + + + + ComfyUI Desktop + + + +
+ + + diff --git a/apps/desktop-ui/package.json b/apps/desktop-ui/package.json new file mode 100644 index 000000000..686d35233 --- /dev/null +++ b/apps/desktop-ui/package.json @@ -0,0 +1,117 @@ +{ + "name": "@comfyorg/desktop-ui", + "version": "0.0.1", + "type": "module", + "nx": { + "tags": [ + "scope:desktop", + "type:app" + ], + "targets": { + "dev": { + "executor": "nx:run-commands", + "continuous": true, + "options": { + "cwd": "apps/desktop-ui", + "command": "vite --config vite.config.mts" + } + }, + "serve": { + "executor": "nx:run-commands", + "continuous": true, + "options": { + "cwd": "apps/desktop-ui", + "command": "vite --config vite.config.mts" + } + }, + "build": { + "executor": "nx:run-commands", + "cache": true, + "dependsOn": [ + "^build" + ], + "options": { + "cwd": "apps/desktop-ui", + "command": "vite build --config vite.config.mts" + }, + "outputs": [ + "{projectRoot}/dist" + ] + }, + "preview": { + "executor": "nx:run-commands", + "continuous": true, + "dependsOn": [ + "build" + ], + "options": { + "cwd": "apps/desktop-ui", + "command": "vite preview --config vite.config.mts" + } + }, + "storybook": { + "executor": "nx:run-commands", + "continuous": true, + "options": { + "cwd": "apps/desktop-ui", + "command": "storybook dev -p 6007" + } + }, + "build-storybook": { + "executor": "nx:run-commands", + "cache": true, + "options": { + "cwd": "apps/desktop-ui", + "command": "storybook build -o dist/storybook" + }, + "outputs": [ + "{projectRoot}/dist/storybook" + ] + }, + "lint": { + "executor": "nx:run-commands", + "cache": true, + "options": { + "cwd": "apps/desktop-ui", + "command": "eslint src --cache" + } + }, + "typecheck": { + "executor": "nx:run-commands", + "cache": true, + "options": { + "cwd": "apps/desktop-ui", + "command": "vue-tsc --noEmit -p tsconfig.json" + } + } + } + }, + "scripts": { + "storybook": "storybook dev -p 6007", + "build-storybook": "storybook build -o dist/storybook" + }, + "dependencies": { + "@comfyorg/comfyui-electron-types": "0.4.73-0", + "@comfyorg/shared-frontend-utils": "workspace:*", + "@primevue/core": "catalog:", + "@primevue/themes": "catalog:", + "@vueuse/core": "catalog:", + "pinia": "catalog:", + "primeicons": "catalog:", + "primevue": "catalog:", + "vue": "catalog:", + "vue-i18n": "catalog:", + "vue-router": "catalog:" + }, + "devDependencies": { + "@tailwindcss/vite": "catalog:", + "@vitejs/plugin-vue": "catalog:", + "dotenv": "catalog:", + "unplugin-icons": "catalog:", + "unplugin-vue-components": "catalog:", + "vite": "catalog:", + "vite-plugin-html": "catalog:", + "vite-plugin-vue-devtools": "catalog:", + "vue-tsc": "catalog:" + } +} diff --git a/public/assets/images/Git-Logo-White.svg b/apps/desktop-ui/public/assets/images/Git-Logo-White.svg similarity index 100% rename from public/assets/images/Git-Logo-White.svg rename to apps/desktop-ui/public/assets/images/Git-Logo-White.svg diff --git a/public/assets/images/apple-mps-logo.png b/apps/desktop-ui/public/assets/images/apple-mps-logo.png similarity index 100% rename from public/assets/images/apple-mps-logo.png rename to apps/desktop-ui/public/assets/images/apple-mps-logo.png diff --git a/public/assets/images/comfy-brand-mark.svg b/apps/desktop-ui/public/assets/images/comfy-brand-mark.svg similarity index 100% rename from public/assets/images/comfy-brand-mark.svg rename to apps/desktop-ui/public/assets/images/comfy-brand-mark.svg diff --git a/public/assets/images/nvidia-logo-square.jpg b/apps/desktop-ui/public/assets/images/nvidia-logo-square.jpg similarity index 100% rename from public/assets/images/nvidia-logo-square.jpg rename to apps/desktop-ui/public/assets/images/nvidia-logo-square.jpg diff --git a/public/assets/images/sad_girl.png b/apps/desktop-ui/public/assets/images/sad_girl.png similarity index 100% rename from public/assets/images/sad_girl.png rename to apps/desktop-ui/public/assets/images/sad_girl.png diff --git a/apps/desktop-ui/src/App.vue b/apps/desktop-ui/src/App.vue new file mode 100644 index 000000000..a43d49c99 --- /dev/null +++ b/apps/desktop-ui/src/App.vue @@ -0,0 +1,7 @@ + + + diff --git a/apps/desktop-ui/src/assets/css/style.css b/apps/desktop-ui/src/assets/css/style.css new file mode 100644 index 000000000..0eef377ae --- /dev/null +++ b/apps/desktop-ui/src/assets/css/style.css @@ -0,0 +1,6 @@ +@import '@comfyorg/design-system/css/style.css'; + +#desktop-app { + position: absolute; + inset: 0; +} diff --git a/apps/desktop-ui/src/components/bottomPanel/tabs/terminal/BaseTerminal.vue b/apps/desktop-ui/src/components/bottomPanel/tabs/terminal/BaseTerminal.vue new file mode 100644 index 000000000..ca0dcf34e --- /dev/null +++ b/apps/desktop-ui/src/components/bottomPanel/tabs/terminal/BaseTerminal.vue @@ -0,0 +1,113 @@ + + + + + diff --git a/src/components/common/RefreshButton.vue b/apps/desktop-ui/src/components/common/RefreshButton.vue similarity index 100% rename from src/components/common/RefreshButton.vue rename to apps/desktop-ui/src/components/common/RefreshButton.vue diff --git a/src/components/common/StartupDisplay.vue b/apps/desktop-ui/src/components/common/StartupDisplay.vue similarity index 100% rename from src/components/common/StartupDisplay.vue rename to apps/desktop-ui/src/components/common/StartupDisplay.vue diff --git a/apps/desktop-ui/src/components/common/UrlInput.vue b/apps/desktop-ui/src/components/common/UrlInput.vue new file mode 100644 index 000000000..91f8cfe56 --- /dev/null +++ b/apps/desktop-ui/src/components/common/UrlInput.vue @@ -0,0 +1,129 @@ + + + diff --git a/src/components/install/DesktopSettingsConfiguration.vue b/apps/desktop-ui/src/components/install/DesktopSettingsConfiguration.vue similarity index 100% rename from src/components/install/DesktopSettingsConfiguration.vue rename to apps/desktop-ui/src/components/install/DesktopSettingsConfiguration.vue diff --git a/src/components/install/GpuPicker.vue b/apps/desktop-ui/src/components/install/GpuPicker.vue similarity index 100% rename from src/components/install/GpuPicker.vue rename to apps/desktop-ui/src/components/install/GpuPicker.vue diff --git a/src/components/install/HardwareOption.stories.ts b/apps/desktop-ui/src/components/install/HardwareOption.stories.ts similarity index 100% rename from src/components/install/HardwareOption.stories.ts rename to apps/desktop-ui/src/components/install/HardwareOption.stories.ts diff --git a/src/components/install/HardwareOption.vue b/apps/desktop-ui/src/components/install/HardwareOption.vue similarity index 100% rename from src/components/install/HardwareOption.vue rename to apps/desktop-ui/src/components/install/HardwareOption.vue diff --git a/src/components/install/InstallFooter.vue b/apps/desktop-ui/src/components/install/InstallFooter.vue similarity index 100% rename from src/components/install/InstallFooter.vue rename to apps/desktop-ui/src/components/install/InstallFooter.vue diff --git a/src/components/install/InstallLocationPicker.stories.ts b/apps/desktop-ui/src/components/install/InstallLocationPicker.stories.ts similarity index 100% rename from src/components/install/InstallLocationPicker.stories.ts rename to apps/desktop-ui/src/components/install/InstallLocationPicker.stories.ts diff --git a/src/components/install/InstallLocationPicker.vue b/apps/desktop-ui/src/components/install/InstallLocationPicker.vue similarity index 99% rename from src/components/install/InstallLocationPicker.vue rename to apps/desktop-ui/src/components/install/InstallLocationPicker.vue index 0e22f34a9..7d930d00e 100644 --- a/src/components/install/InstallLocationPicker.vue +++ b/apps/desktop-ui/src/components/install/InstallLocationPicker.vue @@ -106,6 +106,7 @@ diff --git a/apps/desktop-ui/src/views/templates/BaseViewTemplate.vue b/apps/desktop-ui/src/views/templates/BaseViewTemplate.vue new file mode 100644 index 000000000..bbd6132ba --- /dev/null +++ b/apps/desktop-ui/src/views/templates/BaseViewTemplate.vue @@ -0,0 +1,52 @@ + + + diff --git a/apps/desktop-ui/tsconfig.json b/apps/desktop-ui/tsconfig.json new file mode 100644 index 000000000..026fca248 --- /dev/null +++ b/apps/desktop-ui/tsconfig.json @@ -0,0 +1,20 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "noEmit": true, + "allowImportingTsExtensions": true, + "baseUrl": ".", + "paths": { + "@/*": ["src/*"], + "@frontend-locales/*": ["../../src/locales/*"] + } + }, + "include": [ + ".storybook/**/*", + "src/**/*.ts", + "src/**/*.vue", + "src/**/*.d.ts", + "vite.config.mts" + ], + "references": [] +} diff --git a/apps/desktop-ui/vite.config.mts b/apps/desktop-ui/vite.config.mts new file mode 100644 index 000000000..7cbc5307d --- /dev/null +++ b/apps/desktop-ui/vite.config.mts @@ -0,0 +1,72 @@ +import tailwindcss from '@tailwindcss/vite' +import vue from '@vitejs/plugin-vue' +import dotenv from 'dotenv' +import path from 'node:path' +import { fileURLToPath } from 'node:url' +import { FileSystemIconLoader } from 'unplugin-icons/loaders' +import IconsResolver from 'unplugin-icons/resolver' +import Icons from 'unplugin-icons/vite' +import Components from 'unplugin-vue-components/vite' +import { defineConfig } from 'vite' +import { createHtmlPlugin } from 'vite-plugin-html' +import vueDevTools from 'vite-plugin-vue-devtools' + +dotenv.config() + +const projectRoot = fileURLToPath(new URL('.', import.meta.url)) + +const SHOULD_MINIFY = process.env.ENABLE_MINIFY === 'true' +const VITE_REMOTE_DEV = process.env.VITE_REMOTE_DEV === 'true' +const DISABLE_VUE_PLUGINS = process.env.DISABLE_VUE_PLUGINS === 'true' + +export default defineConfig(() => { + return { + root: projectRoot, + base: '', + publicDir: path.resolve(projectRoot, 'public'), + server: { + port: 5174, + host: VITE_REMOTE_DEV ? '0.0.0.0' : undefined + }, + resolve: { + alias: { + '@': path.resolve(projectRoot, 'src'), + '@frontend-locales': path.resolve(projectRoot, '../../src/locales') + } + }, + plugins: [ + ...(!DISABLE_VUE_PLUGINS + ? [vueDevTools(), vue(), createHtmlPlugin({})] + : [vue()]), + tailwindcss(), + Icons({ + compiler: 'vue3', + customCollections: { + comfy: FileSystemIconLoader( + path.resolve(projectRoot, '../../packages/design-system/src/icons') + ) + } + }), + Components({ + dts: path.resolve(projectRoot, 'components.d.ts'), + resolvers: [ + IconsResolver({ + customCollections: ['comfy'] + }) + ], + dirs: [ + path.resolve(projectRoot, 'src/components'), + path.resolve(projectRoot, 'src/views') + ], + deep: true, + extensions: ['vue'], + directoryAsNamespace: true + }) + ], + build: { + minify: SHOULD_MINIFY ? ('esbuild' as const) : false, + target: 'es2022', + sourcemap: true + } + } +}) diff --git a/browser_tests/README.md b/browser_tests/README.md index 4954ba9fd..500d665c2 100644 --- a/browser_tests/README.md +++ b/browser_tests/README.md @@ -16,7 +16,7 @@ Without this flag, parallel tests will conflict and fail randomly. ### ComfyUI devtools -ComfyUI_devtools is now included in this repository under `tools/devtools/`. During CI/CD, these files are automatically copied to the `custom_nodes` directory. +ComfyUI_devtools is included in this repository under `tools/devtools/`. During CI/CD, these files are automatically copied to the `custom_nodes` directory. _ComfyUI_devtools adds additional API endpoints and nodes to ComfyUI for browser testing._ For local development, copy the devtools files to your ComfyUI installation: @@ -84,7 +84,7 @@ UI mode features: - **Console/Network Tabs**: View logs and API calls at each step - **Attachments Tab**: View all snapshots with expected and actual images -![Playwright UI Mode](https://github.com/user-attachments/assets/c158c93f-b39a-44c5-a1a1-e0cc975ee9f2) +![Playwright UI Mode](https://github.com/user-attachments/assets/9b9cb09f-6da7-4fa0-81df-2effceced755) For CI or headless testing: diff --git a/browser_tests/assets/widgets/all_load_widgets.json b/browser_tests/assets/widgets/all_load_widgets.json new file mode 100644 index 000000000..5f4552eeb --- /dev/null +++ b/browser_tests/assets/widgets/all_load_widgets.json @@ -0,0 +1,221 @@ +{ + "id": "e74f5af9-b886-4a21-abbf-ed535d12e2fb", + "revision": 0, + "last_node_id": 8, + "last_link_id": 0, + "nodes": [ + { + "id": 1, + "type": "LoadAudio", + "pos": [ + 41.52964782714844, + 16.930862426757812 + ], + "size": [ + 444, + 125 + ], + "flags": {}, + "order": 0, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "AUDIO", + "type": "AUDIO", + "links": null + } + ], + "properties": { + "Node name for S&R": "LoadAudio" + }, + "widgets_values": [ + null, + null, + "" + ] + }, + { + "id": 2, + "type": "LoadVideo", + "pos": [ + 502.28570556640625, + 16.857147216796875 + ], + "size": [ + 444, + 525 + ], + "flags": {}, + "order": 1, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "VIDEO", + "type": "VIDEO", + "links": null + } + ], + "properties": { + "Node name for S&R": "LoadVideo" + }, + "widgets_values": [ + null, + "image" + ] + }, + { + "id": 3, + "type": "DevToolsLoadAnimatedImageTest", + "pos": [ + 41.71427917480469, + 188.0000457763672 + ], + "size": [ + 444, + 553 + ], + "flags": {}, + "order": 2, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": null + }, + { + "name": "MASK", + "type": "MASK", + "links": null + } + ], + "properties": { + "Node name for S&R": "DevToolsLoadAnimatedImageTest" + }, + "widgets_values": [ + null, + "image" + ] + }, + { + "id": 5, + "type": "LoadImage", + "pos": [ + 958.285888671875, + 16.57145118713379 + ], + "size": [ + 444, + 553 + ], + "flags": {}, + "order": 3, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": null + }, + { + "name": "MASK", + "type": "MASK", + "links": null + } + ], + "properties": { + "Node name for S&R": "LoadImage" + }, + "widgets_values": [ + null, + "image" + ] + }, + { + "id": 6, + "type": "LoadImageMask", + "pos": [ + 503.4285888671875, + 588 + ], + "size": [ + 444, + 563 + ], + "flags": {}, + "order": 4, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "MASK", + "type": "MASK", + "links": null + } + ], + "properties": { + "Node name for S&R": "LoadImageMask" + }, + "widgets_values": [ + null, + "alpha", + "image" + ] + }, + { + "id": 7, + "type": "LoadImageOutput", + "pos": [ + 965.1429443359375, + 612 + ], + "size": [ + 444, + 553 + ], + "flags": {}, + "order": 5, + "mode": 0, + "inputs": [], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": null + }, + { + "name": "MASK", + "type": "MASK", + "links": null + } + ], + "properties": { + "Node name for S&R": "LoadImageOutput" + }, + "widgets_values": [ + null, + false, + "refresh", + "image" + ] + } + ], + "links": [], + "groups": [], + "config": {}, + "extra": { + "ds": { + "scale": 1, + "offset": [ + 0, + 0 + ] + }, + "frontendVersion": "1.28.3" + }, + "version": 0.4 +} diff --git a/browser_tests/fixtures/VueNodeHelpers.ts b/browser_tests/fixtures/VueNodeHelpers.ts index b51750299..bc4f32452 100644 --- a/browser_tests/fixtures/VueNodeHelpers.ts +++ b/browser_tests/fixtures/VueNodeHelpers.ts @@ -13,13 +13,18 @@ export class VueNodeHelpers { return this.page.locator('[data-node-id]') } + /** + * Get locator for a Vue node by its NodeId + */ + getNodeLocator(nodeId: string): Locator { + return this.page.locator(`[data-node-id="${nodeId}"]`) + } + /** * Get locator for selected Vue node components (using visual selection indicators) */ get selectedNodes(): Locator { - return this.page.locator( - '[data-node-id].outline-black, [data-node-id].outline-white' - ) + return this.page.locator('[data-node-id].outline-node-component-outline') } /** diff --git a/browser_tests/fixtures/utils/litegraphUtils.ts b/browser_tests/fixtures/utils/litegraphUtils.ts index 4becc999c..0449d05e4 100644 --- a/browser_tests/fixtures/utils/litegraphUtils.ts +++ b/browser_tests/fixtures/utils/litegraphUtils.ts @@ -151,7 +151,8 @@ class NodeSlotReference { const convertedPos = window['app'].canvas.ds.convertOffsetToCanvas(rawPos) - // Debug logging - convert Float32Arrays to regular arrays for visibility + // Debug logging - convert Float64Arrays to regular arrays for visibility + // eslint-disable-next-line no-console console.log( `NodeSlotReference debug for ${type} slot ${index} on node ${id}:`, { diff --git a/browser_tests/tests/colorPalette.spec.ts-snapshots/custom-color-palette-light-red-chromium-linux.png b/browser_tests/tests/colorPalette.spec.ts-snapshots/custom-color-palette-light-red-chromium-linux.png index 1ba61954e..a1503a8e3 100644 Binary files a/browser_tests/tests/colorPalette.spec.ts-snapshots/custom-color-palette-light-red-chromium-linux.png and b/browser_tests/tests/colorPalette.spec.ts-snapshots/custom-color-palette-light-red-chromium-linux.png differ diff --git a/browser_tests/tests/colorPalette.spec.ts-snapshots/node-lightened-colors-chromium-linux.png b/browser_tests/tests/colorPalette.spec.ts-snapshots/node-lightened-colors-chromium-linux.png index 1ba61954e..5467af1e7 100644 Binary files a/browser_tests/tests/colorPalette.spec.ts-snapshots/node-lightened-colors-chromium-linux.png and b/browser_tests/tests/colorPalette.spec.ts-snapshots/node-lightened-colors-chromium-linux.png differ diff --git a/browser_tests/tests/colorPalette.spec.ts-snapshots/node-opacity-0-3-color-changed-chromium-linux.png b/browser_tests/tests/colorPalette.spec.ts-snapshots/node-opacity-0-3-color-changed-chromium-linux.png index 3d490143e..520cf8a98 100644 Binary files a/browser_tests/tests/colorPalette.spec.ts-snapshots/node-opacity-0-3-color-changed-chromium-linux.png and b/browser_tests/tests/colorPalette.spec.ts-snapshots/node-opacity-0-3-color-changed-chromium-linux.png differ diff --git a/browser_tests/tests/colorPalette.spec.ts-snapshots/node-opacity-0-3-color-removed-chromium-linux.png b/browser_tests/tests/colorPalette.spec.ts-snapshots/node-opacity-0-3-color-removed-chromium-linux.png index f5eeaa61b..95f577069 100644 Binary files a/browser_tests/tests/colorPalette.spec.ts-snapshots/node-opacity-0-3-color-removed-chromium-linux.png and b/browser_tests/tests/colorPalette.spec.ts-snapshots/node-opacity-0-3-color-removed-chromium-linux.png differ diff --git a/browser_tests/tests/domWidget.spec.ts b/browser_tests/tests/domWidget.spec.ts index 6517b9170..02392f51d 100644 --- a/browser_tests/tests/domWidget.spec.ts +++ b/browser_tests/tests/domWidget.spec.ts @@ -53,6 +53,10 @@ test.describe('DOM Widget', () => { }) test('should reposition when layout changes', async ({ comfyPage }) => { + test.skip( + true, + 'Only recalculates when the Canvas size changes, need to recheck the logic' + ) // --- setup --- const textareaWidget = comfyPage.page diff --git a/browser_tests/tests/domWidget.spec.ts-snapshots/focus-mode-on-chromium-linux.png b/browser_tests/tests/domWidget.spec.ts-snapshots/focus-mode-on-chromium-linux.png index 2b89be5c5..1c29518e2 100644 Binary files a/browser_tests/tests/domWidget.spec.ts-snapshots/focus-mode-on-chromium-linux.png and b/browser_tests/tests/domWidget.spec.ts-snapshots/focus-mode-on-chromium-linux.png differ diff --git a/browser_tests/tests/interaction.spec.ts-snapshots/nodes-bypassed-chromium-linux.png b/browser_tests/tests/interaction.spec.ts-snapshots/nodes-bypassed-chromium-linux.png index 7181cdcfc..a290bd78f 100644 Binary files a/browser_tests/tests/interaction.spec.ts-snapshots/nodes-bypassed-chromium-linux.png and b/browser_tests/tests/interaction.spec.ts-snapshots/nodes-bypassed-chromium-linux.png differ diff --git a/browser_tests/tests/rerouteNode.spec.ts-snapshots/reroute-inserted-chromium-linux.png b/browser_tests/tests/rerouteNode.spec.ts-snapshots/reroute-inserted-chromium-linux.png index a9e9926bf..d32511f52 100644 Binary files a/browser_tests/tests/rerouteNode.spec.ts-snapshots/reroute-inserted-chromium-linux.png and b/browser_tests/tests/rerouteNode.spec.ts-snapshots/reroute-inserted-chromium-linux.png differ diff --git a/browser_tests/tests/rightClickMenu.spec.ts-snapshots/right-click-node-bypassed-chromium-linux.png b/browser_tests/tests/rightClickMenu.spec.ts-snapshots/right-click-node-bypassed-chromium-linux.png index 238946afa..a38379583 100644 Binary files a/browser_tests/tests/rightClickMenu.spec.ts-snapshots/right-click-node-bypassed-chromium-linux.png and b/browser_tests/tests/rightClickMenu.spec.ts-snapshots/right-click-node-bypassed-chromium-linux.png differ diff --git a/browser_tests/tests/rightClickMenu.spec.ts-snapshots/right-click-node-chromium-linux.png b/browser_tests/tests/rightClickMenu.spec.ts-snapshots/right-click-node-chromium-linux.png index 1635e4e89..ac2f2b066 100644 Binary files a/browser_tests/tests/rightClickMenu.spec.ts-snapshots/right-click-node-chromium-linux.png and b/browser_tests/tests/rightClickMenu.spec.ts-snapshots/right-click-node-chromium-linux.png differ diff --git a/browser_tests/tests/rightClickMenu.spec.ts-snapshots/right-click-pinned-node-chromium-linux.png b/browser_tests/tests/rightClickMenu.spec.ts-snapshots/right-click-pinned-node-chromium-linux.png index 4440ef029..562ec32e6 100644 Binary files a/browser_tests/tests/rightClickMenu.spec.ts-snapshots/right-click-pinned-node-chromium-linux.png and b/browser_tests/tests/rightClickMenu.spec.ts-snapshots/right-click-pinned-node-chromium-linux.png differ diff --git a/browser_tests/tests/rightClickMenu.spec.ts-snapshots/right-click-unpinned-node-chromium-linux.png b/browser_tests/tests/rightClickMenu.spec.ts-snapshots/right-click-unpinned-node-chromium-linux.png index 1635e4e89..ac2f2b066 100644 Binary files a/browser_tests/tests/rightClickMenu.spec.ts-snapshots/right-click-unpinned-node-chromium-linux.png and b/browser_tests/tests/rightClickMenu.spec.ts-snapshots/right-click-unpinned-node-chromium-linux.png differ diff --git a/browser_tests/tests/vueNodes/groups/groups.spec.ts-snapshots/vue-groups-create-group-chromium-linux.png b/browser_tests/tests/vueNodes/groups/groups.spec.ts-snapshots/vue-groups-create-group-chromium-linux.png index 446a50c99..f456f95dd 100644 Binary files a/browser_tests/tests/vueNodes/groups/groups.spec.ts-snapshots/vue-groups-create-group-chromium-linux.png and b/browser_tests/tests/vueNodes/groups/groups.spec.ts-snapshots/vue-groups-create-group-chromium-linux.png differ diff --git a/browser_tests/tests/vueNodes/groups/groups.spec.ts-snapshots/vue-groups-fit-to-contents-chromium-linux.png b/browser_tests/tests/vueNodes/groups/groups.spec.ts-snapshots/vue-groups-fit-to-contents-chromium-linux.png index 0302d8a8f..7c1fa01cc 100644 Binary files a/browser_tests/tests/vueNodes/groups/groups.spec.ts-snapshots/vue-groups-fit-to-contents-chromium-linux.png and b/browser_tests/tests/vueNodes/groups/groups.spec.ts-snapshots/vue-groups-fit-to-contents-chromium-linux.png differ diff --git a/browser_tests/tests/vueNodes/interactions/canvas/pan.spec.ts-snapshots/vue-nodes-paned-with-touch-mobile-chrome-linux.png b/browser_tests/tests/vueNodes/interactions/canvas/pan.spec.ts-snapshots/vue-nodes-paned-with-touch-mobile-chrome-linux.png index d0a0c000d..db7cb529e 100644 Binary files a/browser_tests/tests/vueNodes/interactions/canvas/pan.spec.ts-snapshots/vue-nodes-paned-with-touch-mobile-chrome-linux.png and b/browser_tests/tests/vueNodes/interactions/canvas/pan.spec.ts-snapshots/vue-nodes-paned-with-touch-mobile-chrome-linux.png differ diff --git a/browser_tests/tests/vueNodes/interactions/canvas/zoom.spec.ts-snapshots/zoomed-in-ctrl-shift-chromium-linux.png b/browser_tests/tests/vueNodes/interactions/canvas/zoom.spec.ts-snapshots/zoomed-in-ctrl-shift-chromium-linux.png index 1f47aab5c..2f7ffba64 100644 Binary files a/browser_tests/tests/vueNodes/interactions/canvas/zoom.spec.ts-snapshots/zoomed-in-ctrl-shift-chromium-linux.png and b/browser_tests/tests/vueNodes/interactions/canvas/zoom.spec.ts-snapshots/zoomed-in-ctrl-shift-chromium-linux.png differ diff --git a/browser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts b/browser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts index 7c0cd4c1d..a95f9cf19 100644 --- a/browser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts +++ b/browser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts @@ -1,10 +1,12 @@ -import type { Locator } from '@playwright/test' +import type { Locator, Page } from '@playwright/test' +import type { NodeId } from '../../../../../src/platform/workflow/validation/schemas/workflowSchema' import { getSlotKey } from '../../../../../src/renderer/core/layout/slots/slotIdentifier' import { comfyExpect as expect, comfyPageFixture as test } from '../../../../fixtures/ComfyPage' +import { getMiddlePoint } from '../../../../fixtures/utils/litegraphUtils' import { fitToViewInstant } from '../../../../helpers/fitToView' async function getCenter(locator: Locator): Promise<{ x: number; y: number }> { @@ -16,6 +18,87 @@ async function getCenter(locator: Locator): Promise<{ x: number; y: number }> { } } +async function getInputLinkDetails( + page: Page, + nodeId: NodeId, + slotIndex: number +) { + return await page.evaluate( + ([targetNodeId, targetSlot]) => { + const app = window['app'] + const graph = app?.canvas?.graph ?? app?.graph + if (!graph) return null + + const node = graph.getNodeById(targetNodeId) + if (!node) return null + + const input = node.inputs?.[targetSlot] + if (!input) return null + + const linkId = input.link + if (linkId == null) return null + + const link = graph.getLink?.(linkId) + if (!link) return null + + return { + id: link.id, + originId: link.origin_id, + originSlot: + typeof link.origin_slot === 'string' + ? Number.parseInt(link.origin_slot, 10) + : link.origin_slot, + targetId: link.target_id, + targetSlot: + typeof link.target_slot === 'string' + ? Number.parseInt(link.target_slot, 10) + : link.target_slot, + parentId: link.parentId ?? null + } + }, + [nodeId, slotIndex] as const + ) +} + +// Test helpers to reduce repetition across cases +function slotLocator( + page: Page, + nodeId: NodeId, + slotIndex: number, + isInput: boolean +) { + const key = getSlotKey(String(nodeId), slotIndex, isInput) + return page.locator(`[data-slot-key="${key}"]`) +} + +async function expectVisibleAll(...locators: Locator[]) { + await Promise.all(locators.map((l) => expect(l).toBeVisible())) +} + +async function getSlotCenter( + page: Page, + nodeId: NodeId, + slotIndex: number, + isInput: boolean +) { + const locator = slotLocator(page, nodeId, slotIndex, isInput) + await expect(locator).toBeVisible() + return await getCenter(locator) +} + +async function connectSlots( + page: Page, + from: { nodeId: NodeId; index: number }, + to: { nodeId: NodeId; index: number }, + nextFrame: () => Promise +) { + const fromLoc = slotLocator(page, from.nodeId, from.index, false) + const toLoc = slotLocator(page, to.nodeId, to.index, true) + await expectVisibleAll(fromLoc, toLoc) + await fromLoc.dragTo(toLoc) + await nextFrame() +} + test.describe('Vue Node Link Interaction', () => { test.beforeEach(async ({ comfyPage }) => { await comfyPage.setSetting('Comfy.UseNewMenu', 'Top') @@ -30,21 +113,13 @@ test.describe('Vue Node Link Interaction', () => { comfyPage, comfyMouse }) => { - const samplerNodes = await comfyPage.getNodeRefsByType('KSampler') - expect(samplerNodes.length).toBeGreaterThan(0) + const samplerNode = (await comfyPage.getNodeRefsByType('KSampler'))[0] + expect(samplerNode).toBeTruthy() - const samplerNode = samplerNodes[0] - const outputSlot = await samplerNode.getOutput(0) - await outputSlot.removeLinks() - await comfyPage.nextFrame() + const slot = slotLocator(comfyPage.page, samplerNode.id, 0, false) + await expect(slot).toBeVisible() - const slotKey = getSlotKey(String(samplerNode.id), 0, false) - const slotLocator = comfyPage.page.locator(`[data-slot-key="${slotKey}"]`) - await expect(slotLocator).toBeVisible() - - const start = await getCenter(slotLocator) - const canvasBox = await comfyPage.canvas.boundingBox() - if (!canvasBox) throw new Error('Canvas bounding box not available') + const start = await getCenter(slot) // Arbitrary value const dragTarget = { @@ -68,58 +143,24 @@ test.describe('Vue Node Link Interaction', () => { test('should create a link when dropping on a compatible slot', async ({ comfyPage }) => { - const samplerNodes = await comfyPage.getNodeRefsByType('KSampler') - expect(samplerNodes.length).toBeGreaterThan(0) - const samplerNode = samplerNodes[0] - - const vaeNodes = await comfyPage.getNodeRefsByType('VAEDecode') - expect(vaeNodes.length).toBeGreaterThan(0) - const vaeNode = vaeNodes[0] + const samplerNode = (await comfyPage.getNodeRefsByType('KSampler'))[0] + const vaeNode = (await comfyPage.getNodeRefsByType('VAEDecode'))[0] + expect(samplerNode && vaeNode).toBeTruthy() const samplerOutput = await samplerNode.getOutput(0) const vaeInput = await vaeNode.getInput(0) - const outputSlotKey = getSlotKey(String(samplerNode.id), 0, false) - const inputSlotKey = getSlotKey(String(vaeNode.id), 0, true) - - const outputSlot = comfyPage.page.locator( - `[data-slot-key="${outputSlotKey}"]` + await connectSlots( + comfyPage.page, + { nodeId: samplerNode.id, index: 0 }, + { nodeId: vaeNode.id, index: 0 }, + () => comfyPage.nextFrame() ) - const inputSlot = comfyPage.page.locator( - `[data-slot-key="${inputSlotKey}"]` - ) - - await expect(outputSlot).toBeVisible() - await expect(inputSlot).toBeVisible() - - await outputSlot.dragTo(inputSlot) - await comfyPage.nextFrame() expect(await samplerOutput.getLinkCount()).toBe(1) expect(await vaeInput.getLinkCount()).toBe(1) - const linkDetails = await comfyPage.page.evaluate((sourceId) => { - const app = window['app'] - const graph = app?.canvas?.graph - if (!graph) return null - - const source = graph.getNodeById(sourceId) - if (!source) return null - - const linkId = source.outputs[0]?.links?.[0] - if (linkId == null) return null - - const link = graph.links[linkId] - if (!link) return null - - return { - originId: link.origin_id, - originSlot: link.origin_slot, - targetId: link.target_id, - targetSlot: link.target_slot - } - }, samplerNode.id) - + const linkDetails = await getInputLinkDetails(comfyPage.page, vaeNode.id, 0) expect(linkDetails).not.toBeNull() expect(linkDetails).toMatchObject({ originId: samplerNode.id, @@ -132,29 +173,16 @@ test.describe('Vue Node Link Interaction', () => { test('should not create a link when slot types are incompatible', async ({ comfyPage }) => { - const samplerNodes = await comfyPage.getNodeRefsByType('KSampler') - expect(samplerNodes.length).toBeGreaterThan(0) - const samplerNode = samplerNodes[0] - - const clipNodes = await comfyPage.getNodeRefsByType('CLIPTextEncode') - expect(clipNodes.length).toBeGreaterThan(0) - const clipNode = clipNodes[0] + const samplerNode = (await comfyPage.getNodeRefsByType('KSampler'))[0] + const clipNode = (await comfyPage.getNodeRefsByType('CLIPTextEncode'))[0] + expect(samplerNode && clipNode).toBeTruthy() const samplerOutput = await samplerNode.getOutput(0) const clipInput = await clipNode.getInput(0) - const outputSlotKey = getSlotKey(String(samplerNode.id), 0, false) - const inputSlotKey = getSlotKey(String(clipNode.id), 0, true) - - const outputSlot = comfyPage.page.locator( - `[data-slot-key="${outputSlotKey}"]` - ) - const inputSlot = comfyPage.page.locator( - `[data-slot-key="${inputSlotKey}"]` - ) - - await expect(outputSlot).toBeVisible() - await expect(inputSlot).toBeVisible() + const outputSlot = slotLocator(comfyPage.page, samplerNode.id, 0, false) + const inputSlot = slotLocator(comfyPage.page, clipNode.id, 0, true) + await expectVisibleAll(outputSlot, inputSlot) await outputSlot.dragTo(inputSlot) await comfyPage.nextFrame() @@ -162,60 +190,602 @@ test.describe('Vue Node Link Interaction', () => { expect(await samplerOutput.getLinkCount()).toBe(0) expect(await clipInput.getLinkCount()).toBe(0) - const graphLinkCount = await comfyPage.page.evaluate((sourceId) => { - const app = window['app'] - const graph = app?.canvas?.graph - if (!graph) return 0 - - const source = graph.getNodeById(sourceId) - if (!source) return 0 - - return source.outputs[0]?.links?.length ?? 0 - }, samplerNode.id) - - expect(graphLinkCount).toBe(0) + const graphLinkDetails = await getInputLinkDetails( + comfyPage.page, + clipNode.id, + 0 + ) + expect(graphLinkDetails).toBeNull() }) test('should not create a link when dropping onto a slot on the same node', async ({ comfyPage }) => { - const samplerNodes = await comfyPage.getNodeRefsByType('KSampler') - expect(samplerNodes.length).toBeGreaterThan(0) - const samplerNode = samplerNodes[0] + const samplerNode = (await comfyPage.getNodeRefsByType('KSampler'))[0] + expect(samplerNode).toBeTruthy() const samplerOutput = await samplerNode.getOutput(0) const samplerInput = await samplerNode.getInput(3) - const outputSlotKey = getSlotKey(String(samplerNode.id), 0, false) - const inputSlotKey = getSlotKey(String(samplerNode.id), 3, true) - - const outputSlot = comfyPage.page.locator( - `[data-slot-key="${outputSlotKey}"]` - ) - const inputSlot = comfyPage.page.locator( - `[data-slot-key="${inputSlotKey}"]` - ) - - await expect(outputSlot).toBeVisible() - await expect(inputSlot).toBeVisible() + const outputSlot = slotLocator(comfyPage.page, samplerNode.id, 0, false) + const inputSlot = slotLocator(comfyPage.page, samplerNode.id, 3, true) + await expectVisibleAll(outputSlot, inputSlot) await outputSlot.dragTo(inputSlot) await comfyPage.nextFrame() expect(await samplerOutput.getLinkCount()).toBe(0) expect(await samplerInput.getLinkCount()).toBe(0) + }) - const graphLinkCount = await comfyPage.page.evaluate((sourceId) => { - const app = window['app'] - const graph = app?.canvas?.graph - if (!graph) return 0 + test('should reuse the existing origin when dragging an input link', async ({ + comfyPage, + comfyMouse + }) => { + const samplerNode = (await comfyPage.getNodeRefsByType('KSampler'))[0] + const vaeNode = (await comfyPage.getNodeRefsByType('VAEDecode'))[0] + expect(samplerNode && vaeNode).toBeTruthy() + const samplerOutputCenter = await getSlotCenter( + comfyPage.page, + samplerNode.id, + 0, + false + ) + const vaeInputCenter = await getSlotCenter( + comfyPage.page, + vaeNode.id, + 0, + true + ) - const source = graph.getNodeById(sourceId) - if (!source) return 0 + await comfyMouse.move(samplerOutputCenter) + await comfyMouse.drag(vaeInputCenter) + await comfyMouse.drop() - return source.outputs[0]?.links?.length ?? 0 - }, samplerNode.id) + const dragTarget = { + x: vaeInputCenter.x + 160, + y: vaeInputCenter.y - 100 + } - expect(graphLinkCount).toBe(0) + await comfyMouse.move(vaeInputCenter) + await comfyMouse.drag(dragTarget) + await expect(comfyPage.canvas).toHaveScreenshot( + 'vue-node-input-drag-reuses-origin.png' + ) + await comfyMouse.drop() + }) + + test('ctrl+alt drag from an input starts a fresh link', async ({ + comfyPage, + comfyMouse + }) => { + const samplerNode = (await comfyPage.getNodeRefsByType('KSampler'))[0] + const vaeNode = (await comfyPage.getNodeRefsByType('VAEDecode'))[0] + expect(samplerNode && vaeNode).toBeTruthy() + + const samplerOutput = await samplerNode.getOutput(0) + const vaeInput = await vaeNode.getInput(0) + + const samplerOutputCenter = await getSlotCenter( + comfyPage.page, + samplerNode.id, + 0, + false + ) + const vaeInputCenter = await getSlotCenter( + comfyPage.page, + vaeNode.id, + 0, + true + ) + + await comfyMouse.move(samplerOutputCenter) + await comfyMouse.drag(vaeInputCenter) + await comfyMouse.drop() + + await comfyPage.nextFrame() + + const dragTarget = { + x: vaeInputCenter.x + 140, + y: vaeInputCenter.y - 110 + } + + await comfyMouse.move(vaeInputCenter) + await comfyPage.page.keyboard.down('Control') + await comfyPage.page.keyboard.down('Alt') + + try { + await comfyMouse.drag(dragTarget) + await expect(comfyPage.canvas).toHaveScreenshot( + 'vue-node-input-drag-ctrl-alt.png' + ) + } finally { + await comfyMouse.drop().catch(() => {}) + await comfyPage.page.keyboard.up('Alt').catch(() => {}) + await comfyPage.page.keyboard.up('Control').catch(() => {}) + } + + await comfyPage.nextFrame() + + // Tcehnically intended to disconnect existing as well + expect(await vaeInput.getLinkCount()).toBe(0) + expect(await samplerOutput.getLinkCount()).toBe(0) + }) + + test('dropping an input link back on its slot restores the original connection', async ({ + comfyPage, + comfyMouse + }) => { + const samplerNode = (await comfyPage.getNodeRefsByType('KSampler'))[0] + const vaeNode = (await comfyPage.getNodeRefsByType('VAEDecode'))[0] + expect(samplerNode && vaeNode).toBeTruthy() + + const samplerOutput = await samplerNode.getOutput(0) + const vaeInput = await vaeNode.getInput(0) + + const samplerOutputCenter = await getSlotCenter( + comfyPage.page, + samplerNode.id, + 0, + false + ) + const vaeInputCenter = await getSlotCenter( + comfyPage.page, + vaeNode.id, + 0, + true + ) + + await comfyMouse.move(samplerOutputCenter) + try { + await comfyMouse.drag(vaeInputCenter) + } finally { + await comfyMouse.drop() + } + + await comfyPage.nextFrame() + + const originalLink = await getInputLinkDetails( + comfyPage.page, + vaeNode.id, + 0 + ) + expect(originalLink).not.toBeNull() + + const dragTarget = { + x: vaeInputCenter.x + 150, + y: vaeInputCenter.y - 100 + } + + // To prevent needing a screenshot expectation for whether the link's off + const vaeInputLocator = slotLocator(comfyPage.page, vaeNode.id, 0, true) + const inputBox = await vaeInputLocator.boundingBox() + if (!inputBox) throw new Error('Input slot bounding box not available') + const isOutsideX = + dragTarget.x < inputBox.x || dragTarget.x > inputBox.x + inputBox.width + const isOutsideY = + dragTarget.y < inputBox.y || dragTarget.y > inputBox.y + inputBox.height + expect(isOutsideX || isOutsideY).toBe(true) + + await comfyMouse.move(vaeInputCenter) + await comfyMouse.drag(dragTarget) + await comfyMouse.move(vaeInputCenter) + await comfyMouse.drop() + + await comfyPage.nextFrame() + + const restoredLink = await getInputLinkDetails( + comfyPage.page, + vaeNode.id, + 0 + ) + + expect(restoredLink).not.toBeNull() + if (!restoredLink || !originalLink) { + throw new Error('Expected both original and restored links to exist') + } + expect(restoredLink).toMatchObject({ + originId: originalLink.originId, + originSlot: originalLink.originSlot, + targetId: originalLink.targetId, + targetSlot: originalLink.targetSlot, + parentId: originalLink.parentId + }) + expect(await samplerOutput.getLinkCount()).toBe(1) + expect(await vaeInput.getLinkCount()).toBe(1) + }) + + test('rerouted input drag preview remains anchored to reroute', async ({ + comfyPage, + comfyMouse + }) => { + const samplerNode = (await comfyPage.getNodeRefsByType('KSampler'))[0] + const vaeNode = (await comfyPage.getNodeRefsByType('VAEDecode'))[0] + + const samplerOutput = await samplerNode.getOutput(0) + const vaeInput = await vaeNode.getInput(0) + + await connectSlots( + comfyPage.page, + { nodeId: samplerNode.id, index: 0 }, + { nodeId: vaeNode.id, index: 0 }, + () => comfyPage.nextFrame() + ) + + const outputPosition = await samplerOutput.getPosition() + const inputPosition = await vaeInput.getPosition() + const reroutePoint = getMiddlePoint(outputPosition, inputPosition) + + // Insert a reroute programmatically on the existing link between sampler output[0] and VAE input[0]. + // This avoids relying on an exact path hit-test position. + await comfyPage.page.evaluate( + ([targetNodeId, targetSlot, clientPoint]) => { + const app = (window as any)['app'] + const graph = app?.canvas?.graph ?? app?.graph + if (!graph) throw new Error('Graph not available') + const node = graph.getNodeById(targetNodeId) + if (!node) throw new Error('Target node not found') + const input = node.inputs?.[targetSlot] + if (!input) throw new Error('Target input slot not found') + + const linkId = input.link + if (linkId == null) throw new Error('Expected existing link on input') + const link = graph.getLink(linkId) + if (!link) throw new Error('Link not found') + + // Convert the client/canvas pixel coordinates to graph space + const pos = app.canvas.ds.convertCanvasToOffset([ + clientPoint.x, + clientPoint.y + ]) + graph.createReroute(pos, link) + }, + [vaeNode.id, 0, reroutePoint] as const + ) + + await comfyPage.nextFrame() + + const vaeInputCenter = await getSlotCenter( + comfyPage.page, + vaeNode.id, + 0, + true + ) + const dragTarget = { + x: vaeInputCenter.x + 160, + y: vaeInputCenter.y - 120 + } + + let dropped = false + try { + await comfyMouse.move(vaeInputCenter) + await comfyMouse.drag(dragTarget) + await expect(comfyPage.canvas).toHaveScreenshot( + 'vue-node-reroute-input-drag.png' + ) + await comfyMouse.move(vaeInputCenter) + await comfyMouse.drop() + dropped = true + } finally { + if (!dropped) { + await comfyMouse.drop().catch(() => {}) + } + } + + await comfyPage.nextFrame() + + const linkDetails = await getInputLinkDetails(comfyPage.page, vaeNode.id, 0) + expect(linkDetails).not.toBeNull() + expect(linkDetails?.originId).toBe(samplerNode.id) + expect(linkDetails?.parentId).not.toBeNull() + }) + + test('rerouted output shift-drag preview remains anchored to reroute', async ({ + comfyPage, + comfyMouse + }) => { + const samplerNode = (await comfyPage.getNodeRefsByType('KSampler'))[0] + const vaeNode = (await comfyPage.getNodeRefsByType('VAEDecode'))[0] + expect(samplerNode && vaeNode).toBeTruthy() + + const samplerOutput = await samplerNode.getOutput(0) + const vaeInput = await vaeNode.getInput(0) + + await connectSlots( + comfyPage.page, + { nodeId: samplerNode.id, index: 0 }, + { nodeId: vaeNode.id, index: 0 }, + () => comfyPage.nextFrame() + ) + + const outputPosition = await samplerOutput.getPosition() + const inputPosition = await vaeInput.getPosition() + const reroutePoint = getMiddlePoint(outputPosition, inputPosition) + + // Insert a reroute programmatically on the existing link between sampler output[0] and VAE input[0]. + // This avoids relying on an exact path hit-test position. + await comfyPage.page.evaluate( + ([targetNodeId, targetSlot, clientPoint]) => { + const app = (window as any)['app'] + const graph = app?.canvas?.graph ?? app?.graph + if (!graph) throw new Error('Graph not available') + const node = graph.getNodeById(targetNodeId) + if (!node) throw new Error('Target node not found') + const input = node.inputs?.[targetSlot] + if (!input) throw new Error('Target input slot not found') + + const linkId = input.link + if (linkId == null) throw new Error('Expected existing link on input') + const link = graph.getLink(linkId) + if (!link) throw new Error('Link not found') + + // Convert the client/canvas pixel coordinates to graph space + const pos = app.canvas.ds.convertCanvasToOffset([ + clientPoint.x, + clientPoint.y + ]) + graph.createReroute(pos, link) + }, + [vaeNode.id, 0, reroutePoint] as const + ) + + await comfyPage.nextFrame() + + const outputCenter = await getSlotCenter( + comfyPage.page, + samplerNode.id, + 0, + false + ) + const dragTarget = { + x: outputCenter.x + 150, + y: outputCenter.y - 140 + } + + let dropPending = false + let shiftHeld = false + try { + await comfyMouse.move(outputCenter) + await comfyPage.page.keyboard.down('Shift') + shiftHeld = true + dropPending = true + await comfyMouse.drag(dragTarget) + await expect(comfyPage.canvas).toHaveScreenshot( + 'vue-node-reroute-output-shift-drag.png' + ) + await comfyMouse.move(outputCenter) + await comfyMouse.drop() + dropPending = false + } finally { + if (dropPending) await comfyMouse.drop().catch(() => {}) + if (shiftHeld) await comfyPage.page.keyboard.up('Shift').catch(() => {}) + } + + await comfyPage.nextFrame() + + const linkDetails = await getInputLinkDetails(comfyPage.page, vaeNode.id, 0) + expect(linkDetails).not.toBeNull() + expect(linkDetails?.originId).toBe(samplerNode.id) + expect(linkDetails?.parentId).not.toBeNull() + }) + + test('dragging input to input drags existing link', async ({ + comfyPage, + comfyMouse + }) => { + const clipNode = (await comfyPage.getNodeRefsByType('CLIPTextEncode'))[0] + const samplerNode = (await comfyPage.getNodeRefsByType('KSampler'))[0] + expect(clipNode && samplerNode).toBeTruthy() + + // Step 1: Connect CLIP's only output (index 0) to KSampler's second input (index 1) + await connectSlots( + comfyPage.page, + { nodeId: clipNode.id, index: 0 }, + { nodeId: samplerNode.id, index: 1 }, + () => comfyPage.nextFrame() + ) + + // Verify initial link exists between CLIP -> KSampler input[1] + const initialLink = await getInputLinkDetails( + comfyPage.page, + samplerNode.id, + 1 + ) + expect(initialLink).not.toBeNull() + expect(initialLink).toMatchObject({ + originId: clipNode.id, + targetId: samplerNode.id, + targetSlot: 1 + }) + + // Step 2: Drag from KSampler's second input to its third input (index 2) + const input2Center = await getSlotCenter( + comfyPage.page, + samplerNode.id, + 1, + true + ) + const input3Center = await getSlotCenter( + comfyPage.page, + samplerNode.id, + 2, + true + ) + + await comfyMouse.move(input2Center) + await comfyMouse.drag(input3Center) + await comfyMouse.drop() + await comfyPage.nextFrame() + + // Expect old link removed from input[1] + const afterSecondInput = await getInputLinkDetails( + comfyPage.page, + samplerNode.id, + 1 + ) + expect(afterSecondInput).toBeNull() + + // Expect new link exists at input[2] from CLIP + const afterThirdInput = await getInputLinkDetails( + comfyPage.page, + samplerNode.id, + 2 + ) + expect(afterThirdInput).not.toBeNull() + expect(afterThirdInput).toMatchObject({ + originId: clipNode.id, + targetId: samplerNode.id, + targetSlot: 2 + }) + }) + + test('shift-dragging an output with multiple links should drag all links', async ({ + comfyPage, + comfyMouse + }) => { + const clipNode = (await comfyPage.getNodeRefsByType('CLIPTextEncode'))[0] + const samplerNode = (await comfyPage.getNodeRefsByType('KSampler'))[0] + expect(clipNode && samplerNode).toBeTruthy() + + const clipOutput = await clipNode.getOutput(0) + + // Connect output[0] -> inputs[1] and [2] + await connectSlots( + comfyPage.page, + { nodeId: clipNode.id, index: 0 }, + { nodeId: samplerNode.id, index: 1 }, + () => comfyPage.nextFrame() + ) + await connectSlots( + comfyPage.page, + { nodeId: clipNode.id, index: 0 }, + { nodeId: samplerNode.id, index: 2 }, + () => comfyPage.nextFrame() + ) + + expect(await clipOutput.getLinkCount()).toBe(2) + + const outputCenter = await getSlotCenter( + comfyPage.page, + clipNode.id, + 0, + false + ) + const dragTarget = { + x: outputCenter.x + 40, + y: outputCenter.y - 140 + } + + let dropPending = false + let shiftHeld = false + try { + await comfyMouse.move(outputCenter) + await comfyPage.page.keyboard.down('Shift') + shiftHeld = true + await comfyMouse.drag(dragTarget) + dropPending = true + + await expect(comfyPage.canvas).toHaveScreenshot( + 'vue-node-shift-output-multi-link.png' + ) + } finally { + if (dropPending) await comfyMouse.drop().catch(() => {}) + if (shiftHeld) await comfyPage.page.keyboard.up('Shift').catch(() => {}) + } + }) + + test('should snap to node center while dragging and link on drop', async ({ + comfyPage, + comfyMouse + }) => { + const clipNode = (await comfyPage.getNodeRefsByType('CLIPTextEncode'))[0] + const samplerNode = (await comfyPage.getNodeRefsByType('KSampler'))[0] + expect(clipNode && samplerNode).toBeTruthy() + + // Start drag from CLIP output[0] + const clipOutputCenter = await getSlotCenter( + comfyPage.page, + clipNode.id, + 0, + false + ) + + // Drag to the visual center of the KSampler Vue node (not a slot) + const samplerVue = comfyPage.vueNodes.getNodeLocator(String(samplerNode.id)) + await expect(samplerVue).toBeVisible() + const samplerCenter = await getCenter(samplerVue) + + await comfyMouse.move(clipOutputCenter) + await comfyMouse.drag(samplerCenter) + + // During drag, the preview should snap/highlight a compatible input on KSampler + await expect(comfyPage.canvas).toHaveScreenshot('vue-node-snap-to-node.png') + + // Drop to create the link + await comfyMouse.drop() + await comfyPage.nextFrame() + + // Validate a link was created to one of KSampler's compatible inputs (1 or 2) + const linkOnInput1 = await getInputLinkDetails( + comfyPage.page, + samplerNode.id, + 1 + ) + const linkOnInput2 = await getInputLinkDetails( + comfyPage.page, + samplerNode.id, + 2 + ) + + const linked = linkOnInput1 ?? linkOnInput2 + expect(linked).not.toBeNull() + expect(linked?.originId).toBe(clipNode.id) + expect(linked?.targetId).toBe(samplerNode.id) + }) + + test('should snap to a specific compatible slot when targeting it', async ({ + comfyPage, + comfyMouse + }) => { + const clipNode = (await comfyPage.getNodeRefsByType('CLIPTextEncode'))[0] + const samplerNode = (await comfyPage.getNodeRefsByType('KSampler'))[0] + expect(clipNode && samplerNode).toBeTruthy() + + // Drag from CLIP output[0] to KSampler input[2] (third slot) which is the + // second compatible input for CLIP + const clipOutputCenter = await getSlotCenter( + comfyPage.page, + clipNode.id, + 0, + false + ) + const samplerInput3Center = await getSlotCenter( + comfyPage.page, + samplerNode.id, + 2, + true + ) + + await comfyMouse.move(clipOutputCenter) + await comfyMouse.drag(samplerInput3Center) + + // Expect the preview to show snapping to the targeted slot + await expect(comfyPage.canvas).toHaveScreenshot('vue-node-snap-to-slot.png') + + // Finish the connection + await comfyMouse.drop() + await comfyPage.nextFrame() + + const linkDetails = await getInputLinkDetails( + comfyPage.page, + samplerNode.id, + 2 + ) + expect(linkDetails).not.toBeNull() + expect(linkDetails).toMatchObject({ + originId: clipNode.id, + targetId: samplerNode.id, + targetSlot: 2 + }) }) }) diff --git a/browser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts-snapshots/vue-node-dragging-link-chromium-linux.png b/browser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts-snapshots/vue-node-dragging-link-chromium-linux.png index a30e4b2c0..11259d974 100644 Binary files a/browser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts-snapshots/vue-node-dragging-link-chromium-linux.png and b/browser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts-snapshots/vue-node-dragging-link-chromium-linux.png differ diff --git a/browser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts-snapshots/vue-node-input-drag-ctrl-alt-chromium-linux.png b/browser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts-snapshots/vue-node-input-drag-ctrl-alt-chromium-linux.png new file mode 100644 index 000000000..fccd20a78 Binary files /dev/null and b/browser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts-snapshots/vue-node-input-drag-ctrl-alt-chromium-linux.png differ diff --git a/browser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts-snapshots/vue-node-input-drag-reuses-origin-chromium-linux.png b/browser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts-snapshots/vue-node-input-drag-reuses-origin-chromium-linux.png new file mode 100644 index 000000000..99012d4bb Binary files /dev/null and b/browser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts-snapshots/vue-node-input-drag-reuses-origin-chromium-linux.png differ diff --git a/browser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts-snapshots/vue-node-reroute-input-drag-chromium-linux.png b/browser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts-snapshots/vue-node-reroute-input-drag-chromium-linux.png new file mode 100644 index 000000000..6b4030ac3 Binary files /dev/null and b/browser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts-snapshots/vue-node-reroute-input-drag-chromium-linux.png differ diff --git a/browser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts-snapshots/vue-node-reroute-output-shift-drag-chromium-linux.png b/browser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts-snapshots/vue-node-reroute-output-shift-drag-chromium-linux.png new file mode 100644 index 000000000..2c163f1f3 Binary files /dev/null and b/browser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts-snapshots/vue-node-reroute-output-shift-drag-chromium-linux.png differ diff --git a/browser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts-snapshots/vue-node-shift-output-multi-link-chromium-linux.png b/browser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts-snapshots/vue-node-shift-output-multi-link-chromium-linux.png new file mode 100644 index 000000000..be9d370f4 Binary files /dev/null and b/browser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts-snapshots/vue-node-shift-output-multi-link-chromium-linux.png differ diff --git a/browser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts-snapshots/vue-node-snap-to-node-chromium-linux.png b/browser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts-snapshots/vue-node-snap-to-node-chromium-linux.png new file mode 100644 index 000000000..7ede9d449 Binary files /dev/null and b/browser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts-snapshots/vue-node-snap-to-node-chromium-linux.png differ diff --git a/browser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts-snapshots/vue-node-snap-to-slot-chromium-linux.png b/browser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts-snapshots/vue-node-snap-to-slot-chromium-linux.png new file mode 100644 index 000000000..4b549b2e4 Binary files /dev/null and b/browser_tests/tests/vueNodes/interactions/links/linkInteraction.spec.ts-snapshots/vue-node-snap-to-slot-chromium-linux.png differ diff --git a/browser_tests/tests/vueNodes/interactions/node/move.spec.ts b/browser_tests/tests/vueNodes/interactions/node/move.spec.ts new file mode 100644 index 000000000..ac4759934 --- /dev/null +++ b/browser_tests/tests/vueNodes/interactions/node/move.spec.ts @@ -0,0 +1,67 @@ +import { + type ComfyPage, + comfyExpect as expect, + comfyPageFixture as test +} from '../../../../fixtures/ComfyPage' +import type { Position } from '../../../../fixtures/types' + +test.describe('Vue Node Moving', () => { + test.beforeEach(async ({ comfyPage }) => { + await comfyPage.setSetting('Comfy.VueNodes.Enabled', true) + await comfyPage.vueNodes.waitForNodes() + }) + + const getLoadCheckpointHeaderPos = async (comfyPage: ComfyPage) => { + const loadCheckpointHeaderPos = await comfyPage.page + .getByText('Load Checkpoint') + .boundingBox() + + if (!loadCheckpointHeaderPos) + throw new Error('Load Checkpoint header not found') + + return loadCheckpointHeaderPos + } + + const expectPosChanged = async (pos1: Position, pos2: Position) => { + const diffX = Math.abs(pos2.x - pos1.x) + const diffY = Math.abs(pos2.y - pos1.y) + expect(diffX).toBeGreaterThan(0) + expect(diffY).toBeGreaterThan(0) + } + + test('should allow moving nodes by dragging', async ({ comfyPage }) => { + const loadCheckpointHeaderPos = await getLoadCheckpointHeaderPos(comfyPage) + await comfyPage.dragAndDrop(loadCheckpointHeaderPos, { + x: 256, + y: 256 + }) + + const newHeaderPos = await getLoadCheckpointHeaderPos(comfyPage) + await expectPosChanged(loadCheckpointHeaderPos, newHeaderPos) + + await expect(comfyPage.canvas).toHaveScreenshot('vue-node-moved-node.png') + }) + + test('@mobile should allow moving nodes by dragging on touch devices', async ({ + comfyPage + }) => { + // Disable minimap (gets in way of the node on small screens) + await comfyPage.setSetting('Comfy.Minimap.Visible', false) + + const loadCheckpointHeaderPos = await getLoadCheckpointHeaderPos(comfyPage) + await comfyPage.panWithTouch( + { + x: 64, + y: 64 + }, + loadCheckpointHeaderPos + ) + + const newHeaderPos = await getLoadCheckpointHeaderPos(comfyPage) + await expectPosChanged(loadCheckpointHeaderPos, newHeaderPos) + + await expect(comfyPage.canvas).toHaveScreenshot( + 'vue-node-moved-node-touch.png' + ) + }) +}) diff --git a/browser_tests/tests/vueNodes/interactions/node/move.spec.ts-snapshots/vue-node-moved-node-chromium-linux.png b/browser_tests/tests/vueNodes/interactions/node/move.spec.ts-snapshots/vue-node-moved-node-chromium-linux.png new file mode 100644 index 000000000..6636b9672 Binary files /dev/null and b/browser_tests/tests/vueNodes/interactions/node/move.spec.ts-snapshots/vue-node-moved-node-chromium-linux.png differ diff --git a/browser_tests/tests/vueNodes/interactions/node/move.spec.ts-snapshots/vue-node-moved-node-touch-mobile-chrome-linux.png b/browser_tests/tests/vueNodes/interactions/node/move.spec.ts-snapshots/vue-node-moved-node-touch-mobile-chrome-linux.png new file mode 100644 index 000000000..172c373fc Binary files /dev/null and b/browser_tests/tests/vueNodes/interactions/node/move.spec.ts-snapshots/vue-node-moved-node-touch-mobile-chrome-linux.png differ diff --git a/browser_tests/tests/vueNodes/nodeStates/collapse.spec.ts b/browser_tests/tests/vueNodes/nodeStates/collapse.spec.ts index a339a0a25..fb5fc3c17 100644 --- a/browser_tests/tests/vueNodes/nodeStates/collapse.spec.ts +++ b/browser_tests/tests/vueNodes/nodeStates/collapse.spec.ts @@ -50,17 +50,17 @@ test.describe('Vue Node Collapse', () => { // Check initial expanded state icon let iconClass = await vueNode.getCollapseIconClass() - expect(iconClass).toContain('pi-chevron-down') + expect(iconClass).not.toContain('-rotate-90') // Collapse and check icon await vueNode.toggleCollapse() iconClass = await vueNode.getCollapseIconClass() - expect(iconClass).toContain('pi-chevron-right') + expect(iconClass).toContain('-rotate-90') // Expand and check icon await vueNode.toggleCollapse() iconClass = await vueNode.getCollapseIconClass() - expect(iconClass).toContain('pi-chevron-down') + expect(iconClass).not.toContain('-rotate-90') }) test('should preserve title when collapsing/expanding', async ({ diff --git a/browser_tests/tests/vueNodes/nodeStates/colors.spec.ts-snapshots/vue-node-custom-color-blue-chromium-linux.png b/browser_tests/tests/vueNodes/nodeStates/colors.spec.ts-snapshots/vue-node-custom-color-blue-chromium-linux.png index 64898a216..e167fe5df 100644 Binary files a/browser_tests/tests/vueNodes/nodeStates/colors.spec.ts-snapshots/vue-node-custom-color-blue-chromium-linux.png and b/browser_tests/tests/vueNodes/nodeStates/colors.spec.ts-snapshots/vue-node-custom-color-blue-chromium-linux.png differ diff --git a/browser_tests/tests/vueNodes/nodeStates/colors.spec.ts-snapshots/vue-node-custom-colors-dark-all-colors-chromium-linux.png b/browser_tests/tests/vueNodes/nodeStates/colors.spec.ts-snapshots/vue-node-custom-colors-dark-all-colors-chromium-linux.png index ac6a841ae..5eee0b056 100644 Binary files a/browser_tests/tests/vueNodes/nodeStates/colors.spec.ts-snapshots/vue-node-custom-colors-dark-all-colors-chromium-linux.png and b/browser_tests/tests/vueNodes/nodeStates/colors.spec.ts-snapshots/vue-node-custom-colors-dark-all-colors-chromium-linux.png differ diff --git a/browser_tests/tests/vueNodes/nodeStates/colors.spec.ts-snapshots/vue-node-custom-colors-light-all-colors-chromium-linux.png b/browser_tests/tests/vueNodes/nodeStates/colors.spec.ts-snapshots/vue-node-custom-colors-light-all-colors-chromium-linux.png index c89b8b240..f68a50ce6 100644 Binary files a/browser_tests/tests/vueNodes/nodeStates/colors.spec.ts-snapshots/vue-node-custom-colors-light-all-colors-chromium-linux.png and b/browser_tests/tests/vueNodes/nodeStates/colors.spec.ts-snapshots/vue-node-custom-colors-light-all-colors-chromium-linux.png differ diff --git a/browser_tests/tests/vueNodes/nodeStates/lod.spec.ts-snapshots/vue-nodes-default-chromium-linux.png b/browser_tests/tests/vueNodes/nodeStates/lod.spec.ts-snapshots/vue-nodes-default-chromium-linux.png index cf8384a03..89173c640 100644 Binary files a/browser_tests/tests/vueNodes/nodeStates/lod.spec.ts-snapshots/vue-nodes-default-chromium-linux.png and b/browser_tests/tests/vueNodes/nodeStates/lod.spec.ts-snapshots/vue-nodes-default-chromium-linux.png differ diff --git a/browser_tests/tests/vueNodes/nodeStates/lod.spec.ts-snapshots/vue-nodes-lod-active-chromium-linux.png b/browser_tests/tests/vueNodes/nodeStates/lod.spec.ts-snapshots/vue-nodes-lod-active-chromium-linux.png index ee051f5df..e6281d325 100644 Binary files a/browser_tests/tests/vueNodes/nodeStates/lod.spec.ts-snapshots/vue-nodes-lod-active-chromium-linux.png and b/browser_tests/tests/vueNodes/nodeStates/lod.spec.ts-snapshots/vue-nodes-lod-active-chromium-linux.png differ diff --git a/browser_tests/tests/vueNodes/nodeStates/lod.spec.ts-snapshots/vue-nodes-lod-inactive-chromium-linux.png b/browser_tests/tests/vueNodes/nodeStates/lod.spec.ts-snapshots/vue-nodes-lod-inactive-chromium-linux.png index cf8384a03..f05e4f68b 100644 Binary files a/browser_tests/tests/vueNodes/nodeStates/lod.spec.ts-snapshots/vue-nodes-lod-inactive-chromium-linux.png and b/browser_tests/tests/vueNodes/nodeStates/lod.spec.ts-snapshots/vue-nodes-lod-inactive-chromium-linux.png differ diff --git a/browser_tests/tests/vueNodes/widgets/load/uploadWidgets.spec.ts b/browser_tests/tests/vueNodes/widgets/load/uploadWidgets.spec.ts new file mode 100644 index 000000000..8fcc3360d --- /dev/null +++ b/browser_tests/tests/vueNodes/widgets/load/uploadWidgets.spec.ts @@ -0,0 +1,21 @@ +import { + comfyExpect as expect, + comfyPageFixture as test +} from '../../../../fixtures/ComfyPage' + +test.describe('Vue Upload Widgets', () => { + test.beforeEach(async ({ comfyPage }) => { + await comfyPage.setSetting('Comfy.VueNodes.Enabled', true) + await comfyPage.vueNodes.waitForNodes() + }) + + test('should hide canvas-only upload buttons', async ({ comfyPage }) => { + await comfyPage.setup() + await comfyPage.loadWorkflow('widgets/all_load_widgets') + await comfyPage.vueNodes.waitForNodes() + + await expect(comfyPage.canvas).toHaveScreenshot( + 'vue-nodes-upload-widgets.png' + ) + }) +}) diff --git a/browser_tests/tests/vueNodes/widgets/load/uploadWidgets.spec.ts-snapshots/vue-nodes-upload-widgets-chromium-linux.png b/browser_tests/tests/vueNodes/widgets/load/uploadWidgets.spec.ts-snapshots/vue-nodes-upload-widgets-chromium-linux.png new file mode 100644 index 000000000..bce3e7dea Binary files /dev/null and b/browser_tests/tests/vueNodes/widgets/load/uploadWidgets.spec.ts-snapshots/vue-nodes-upload-widgets-chromium-linux.png differ diff --git a/eslint.config.ts b/eslint.config.ts index 9c14f17b4..e1746010b 100644 --- a/eslint.config.ts +++ b/eslint.config.ts @@ -18,7 +18,7 @@ export default defineConfig([ 'src/scripts/*', 'src/extensions/core/*', 'src/types/vue-shim.d.ts', - 'src/types/comfyRegistryTypes.ts', + 'packages/registry-types/src/comfyRegistryTypes.ts', 'src/types/generatedManagerTypes.ts', '**/vite.config.*.timestamp*', '**/vitest.config.*.timestamp*', @@ -52,8 +52,10 @@ export default defineConfig([ projectService: { allowDefaultProject: [ 'vite.config.mts', + 'vite.electron.config.mts', 'vite.types.config.mts', - 'vitest.litegraph.config.ts' + 'playwright.config.ts', + 'playwright.i18n.config.ts' ] }, tsConfigRootDir: import.meta.dirname, @@ -106,6 +108,7 @@ export default defineConfig([ } ], 'unused-imports/no-unused-imports': 'error', + 'no-console': ['error', { allow: ['warn', 'error'] }], 'vue/no-v-html': 'off', // Enforce dark-theme: instead of dark: prefix 'vue/no-restricted-class': ['error', '/^dark:/'], @@ -223,5 +226,11 @@ export default defineConfig([ } ] } + }, + { + files: ['**/*.{test,spec,stories}.ts', '**/*.stories.vue'], + rules: { + 'no-console': 'off' + } } ]) diff --git a/knip.config.ts b/knip.config.ts index 3022a0af5..3b44579fd 100644 --- a/knip.config.ts +++ b/knip.config.ts @@ -18,8 +18,13 @@ const config: KnipConfig = { 'packages/design-system': { entry: ['src/**/*.ts'], project: ['src/**/*.{js,ts}', '*.{js,ts,mts}'] + }, + 'packages/registry-types': { + entry: ['src/comfyRegistryTypes.ts'], + project: ['src/**/*.{js,ts}'] } }, + ignoreBinaries: ['python3'], ignoreDependencies: [ // Weird importmap things '@iconify/json', @@ -33,7 +38,7 @@ const config: KnipConfig = { ignore: [ // Auto generated manager types 'src/workbench/extensions/manager/types/generatedManagerTypes.ts', - 'src/types/comfyRegistryTypes.ts', + 'packages/registry-types/src/comfyRegistryTypes.ts', // Used by a custom node (that should move off of this) 'src/scripts/ui/components/splitButton.ts' ], diff --git a/package.json b/package.json index da9b83ebe..171caf9f7 100644 --- a/package.json +++ b/package.json @@ -1,121 +1,126 @@ { "name": "@comfyorg/comfyui-frontend", "private": true, - "version": "1.28.3", + "version": "1.28.6", "type": "module", "repository": "https://github.com/Comfy-Org/ComfyUI_frontend", "homepage": "https://comfy.org", "description": "Official front-end implementation of ComfyUI", "license": "GPL-3.0-only", "scripts": { - "dev": "nx serve", - "dev:electron": "nx serve --config vite.electron.config.mts", - "build": "pnpm typecheck && nx build", + "build:desktop": "nx build @comfyorg/desktop-ui", + "build-storybook": "storybook build", "build:types": "nx build --config vite.types.config.mts && node scripts/prepare-types.js", - "zipdist": "node scripts/zipdist.js", - "typecheck": "vue-tsc --noEmit", - "format": "prettier --write './**/*.{js,ts,tsx,vue,mts}' --cache --list-different", + "build": "pnpm typecheck && nx build", + "collect-i18n": "pnpm exec playwright test --config=playwright.i18n.config.ts", + "dev:desktop": "nx dev @comfyorg/desktop-ui", + "dev:electron": "nx serve --config vite.electron.config.mts", + "dev": "nx serve", + "devtools:pycheck": "python3 -m compileall -q tools/devtools", + "format:check:no-cache": "prettier --check './**/*.{js,ts,tsx,vue,mts}'", "format:check": "prettier --check './**/*.{js,ts,tsx,vue,mts}' --cache", "format:no-cache": "prettier --write './**/*.{js,ts,tsx,vue,mts}' --list-different", - "format:check:no-cache": "prettier --check './**/*.{js,ts,tsx,vue,mts}'", - "test:all": "nx run test", - "test:browser": "pnpm exec nx e2e", - "test:component": "nx run test src/components/", - "test:litegraph": "vitest run --config vitest.litegraph.config.ts", - "test:unit": "nx run test tests-ui/tests", + "format": "prettier --write './**/*.{js,ts,tsx,vue,mts}' --cache --list-different", + "json-schema": "tsx scripts/generate-json-schema.ts", + "knip:no-cache": "knip", + "knip": "knip --cache", + "lint:fix:no-cache": "eslint src --fix", + "lint:fix": "eslint src --cache --fix", + "lint:no-cache": "eslint src", + "lint:unstaged:fix": "git diff --name-only HEAD | grep -E '\\.(js|ts|vue|mts)$' | xargs -r eslint --cache --fix", + "lint:unstaged": "git diff --name-only HEAD | grep -E '\\.(js|ts|vue|mts)$' | xargs -r eslint --cache", + "lint": "eslint src --cache", + "locale": "lobe-i18n locale", "preinstall": "pnpm dlx only-allow pnpm", "prepare": "husky || true && git config blame.ignoreRevsFile .git-blame-ignore-revs || true", "preview": "nx preview", - "lint": "eslint src --cache", - "lint:fix": "eslint src --cache --fix", - "lint:unstaged": "git diff --name-only HEAD | grep -E '\\.(js|ts|vue|mts)$' | xargs -r eslint --cache", - "lint:unstaged:fix": "git diff --name-only HEAD | grep -E '\\.(js|ts|vue|mts)$' | xargs -r eslint --cache --fix", - "lint:no-cache": "eslint src", - "lint:fix:no-cache": "eslint src --fix", - "knip": "knip --cache", - "knip:no-cache": "knip", - "locale": "lobe-i18n locale", - "collect-i18n": "pnpm exec playwright test --config=playwright.i18n.config.ts", - "json-schema": "tsx scripts/generate-json-schema.ts", "storybook": "nx storybook -p 6006", - "build-storybook": "storybook build" + "stylelint:fix": "stylelint --cache --fix", + "stylelint": "stylelint --cache", + "test:browser": "pnpm exec nx e2e", + "test:unit": "nx run test", + "typecheck": "vue-tsc --noEmit", + "zipdist": "node scripts/zipdist.js" }, "devDependencies": { - "@eslint/js": "^9.35.0", - "@intlify/eslint-plugin-vue-i18n": "^4.1.0", - "@lobehub/i18n-cli": "^1.25.1", - "@nx/eslint": "21.4.1", - "@nx/playwright": "21.4.1", - "@nx/storybook": "21.4.1", - "@nx/vite": "21.4.1", - "@pinia/testing": "^0.1.5", - "@playwright/test": "^1.52.0", - "@storybook/addon-docs": "^9.1.1", - "@storybook/vue3": "^9.1.1", - "@storybook/vue3-vite": "^9.1.1", - "@tailwindcss/vite": "^4.1.12", - "@trivago/prettier-plugin-sort-imports": "^5.2.0", - "@types/fs-extra": "^11.0.4", - "@types/jsdom": "^21.1.7", - "@types/node": "^20.14.8", - "@types/semver": "^7.7.0", - "@types/three": "^0.169.0", - "@vitejs/plugin-vue": "^5.1.4", - "@vitest/coverage-v8": "^3.2.4", - "@vitest/ui": "^3.0.0", - "@vue/test-utils": "^2.4.6", - "eslint": "^9.34.0", - "eslint-config-prettier": "^10.1.8", - "eslint-plugin-prettier": "^5.5.4", - "eslint-plugin-storybook": "^9.1.6", - "eslint-plugin-unused-imports": "^4.2.0", - "eslint-plugin-vue": "^10.4.0", + "@eslint/js": "catalog:", + "@intlify/eslint-plugin-vue-i18n": "catalog:", + "@lobehub/i18n-cli": "catalog:", + "@nx/eslint": "catalog:", + "@nx/playwright": "catalog:", + "@nx/storybook": "catalog:", + "@nx/vite": "catalog:", + "@pinia/testing": "catalog:", + "@playwright/test": "catalog:", + "@storybook/addon-docs": "catalog:", + "@storybook/vue3": "catalog:", + "@storybook/vue3-vite": "catalog:", + "@tailwindcss/vite": "catalog:", + "@trivago/prettier-plugin-sort-imports": "catalog:", + "@types/fs-extra": "catalog:", + "@types/jsdom": "catalog:", + "@types/node": "catalog:", + "@types/semver": "catalog:", + "@types/three": "catalog:", + "@vitejs/plugin-vue": "catalog:", + "@vitest/coverage-v8": "catalog:", + "@vitest/ui": "catalog:", + "@vue/test-utils": "catalog:", + "eslint": "catalog:", + "eslint-config-prettier": "catalog:", + "eslint-plugin-prettier": "catalog:", + "eslint-plugin-storybook": "catalog:", + "eslint-plugin-unused-imports": "catalog:", + "eslint-plugin-vue": "catalog:", "fs-extra": "^11.2.0", - "globals": "^15.9.0", - "happy-dom": "^15.11.0", - "husky": "^9.0.11", - "jiti": "2.4.2", - "jsdom": "^26.1.0", - "knip": "^5.62.0", - "lint-staged": "^15.2.7", - "nx": "21.4.1", - "prettier": "^3.3.2", - "storybook": "^9.1.6", - "tailwindcss": "^4.1.12", - "tailwindcss-primeui": "^0.6.1", - "tsx": "^4.15.6", - "tw-animate-css": "^1.3.8", - "typescript": "^5.4.5", - "typescript-eslint": "^8.44.0", - "unplugin-icons": "^0.22.0", - "unplugin-vue-components": "^0.28.0", + "globals": "catalog:", + "happy-dom": "catalog:", + "husky": "catalog:", + "jiti": "catalog:", + "jsdom": "catalog:", + "knip": "catalog:", + "lint-staged": "catalog:", + "nx": "catalog:", + "postcss-html": "catalog:", + "prettier": "catalog:", + "storybook": "catalog:", + "stylelint": "catalog:", + "tailwindcss": "catalog:", + "tailwindcss-primeui": "catalog:", + "tsx": "catalog:", + "tw-animate-css": "catalog:", + "typescript": "catalog:", + "typescript-eslint": "catalog:", + "unplugin-icons": "catalog:", + "unplugin-vue-components": "catalog:", "uuid": "^11.1.0", - "vite": "^5.4.19", - "vite-plugin-dts": "^4.5.4", - "vite-plugin-html": "^3.2.2", - "vite-plugin-vue-devtools": "^7.7.6", - "vitest": "^3.2.4", - "vue-component-type-helpers": "^3.0.7", - "vue-eslint-parser": "^10.2.0", - "vue-tsc": "^3.0.7", + "vite": "catalog:", + "vite-plugin-dts": "catalog:", + "vite-plugin-html": "catalog:", + "vite-plugin-vue-devtools": "catalog:", + "vitest": "catalog:", + "vue-component-type-helpers": "catalog:", + "vue-eslint-parser": "catalog:", + "vue-tsc": "catalog:", "zip-dir": "^2.0.0", - "zod-to-json-schema": "^3.24.1" + "zod-to-json-schema": "catalog:" }, "dependencies": { - "@alloc/quick-lru": "^5.2.0", + "@alloc/quick-lru": "catalog:", "@atlaskit/pragmatic-drag-and-drop": "^1.3.1", "@comfyorg/comfyui-electron-types": "0.4.73-0", "@comfyorg/design-system": "workspace:*", + "@comfyorg/registry-types": "workspace:*", "@comfyorg/tailwind-utils": "workspace:*", - "@iconify/json": "^2.2.380", - "@primeuix/forms": "0.0.2", - "@primeuix/styled": "0.3.2", - "@primeuix/utils": "^0.3.2", - "@primevue/core": "^4.2.5", - "@primevue/forms": "^4.2.5", - "@primevue/icons": "4.2.5", - "@primevue/themes": "^4.2.5", - "@sentry/vue": "^8.48.0", + "@iconify/json": "catalog:", + "@primeuix/forms": "catalog:", + "@primeuix/styled": "catalog:", + "@primeuix/utils": "catalog:", + "@primevue/core": "catalog:", + "@primevue/forms": "catalog:", + "@primevue/icons": "catalog:", + "@primevue/themes": "catalog:", + "@sentry/vue": "catalog:", "@tiptap/core": "^2.10.4", "@tiptap/extension-link": "^2.10.4", "@tiptap/extension-table": "^2.10.4", @@ -123,39 +128,39 @@ "@tiptap/extension-table-header": "^2.10.4", "@tiptap/extension-table-row": "^2.10.4", "@tiptap/starter-kit": "^2.10.4", - "@vueuse/core": "^11.0.0", - "@vueuse/integrations": "^13.9.0", + "@vueuse/core": "catalog:", + "@vueuse/integrations": "catalog:", "@xterm/addon-fit": "^0.10.0", "@xterm/addon-serialize": "^0.13.0", "@xterm/xterm": "^5.5.0", - "algoliasearch": "^5.21.0", - "axios": "^1.8.2", + "algoliasearch": "catalog:", + "axios": "catalog:", "chart.js": "^4.5.0", "dompurify": "^3.2.5", - "dotenv": "^16.4.5", + "dotenv": "catalog:", "es-toolkit": "^1.39.9", "extendable-media-recorder": "^9.2.27", "extendable-media-recorder-wav-encoder": "^7.0.129", "fast-glob": "^3.3.3", - "firebase": "^11.6.0", + "firebase": "catalog:", "fuse.js": "^7.0.0", "glob": "^11.0.3", "jsondiffpatch": "^0.6.0", "loglevel": "^1.9.2", "marked": "^15.0.11", - "pinia": "^2.1.7", - "primeicons": "^7.0.0", - "primevue": "^4.2.5", + "pinia": "catalog:", + "primeicons": "catalog:", + "primevue": "catalog:", "reka-ui": "^2.5.0", "semver": "^7.7.2", "three": "^0.170.0", "tiptap-markdown": "^0.8.10", - "vue": "^3.5.13", - "vue-i18n": "^9.14.3", - "vue-router": "^4.4.3", - "vuefire": "^3.2.1", - "yjs": "^13.6.27", - "zod": "^3.23.8", - "zod-validation-error": "^3.3.0" + "vue": "catalog:", + "vue-i18n": "catalog:", + "vue-router": "catalog:", + "vuefire": "catalog:", + "yjs": "catalog:", + "zod": "catalog:", + "zod-validation-error": "catalog:" } } diff --git a/packages/design-system/package.json b/packages/design-system/package.json index e2868d054..94aabcc89 100644 --- a/packages/design-system/package.json +++ b/packages/design-system/package.json @@ -4,10 +4,7 @@ "description": "Shared design system for ComfyUI Frontend", "type": "module", "exports": { - "./tailwind-config": { - "import": "./tailwind.config.ts", - "types": "./tailwind.config.ts" - }, + "./tailwind-config": "./tailwind.config.ts", "./css/*": "./src/css/*" }, "scripts": { @@ -20,12 +17,12 @@ ] }, "dependencies": { - "@iconify-json/lucide": "^1.1.178", - "@iconify/tailwind": "^1.1.3" + "@iconify-json/lucide": "catalog:", + "@iconify/tailwind": "catalog:" }, "devDependencies": { - "tailwindcss": "^3.4.17", - "typescript": "^5.4.5" + "tailwindcss": "catalog:", + "typescript": "catalog:" }, "packageManager": "pnpm@10.17.1" } diff --git a/packages/design-system/src/css/style.css b/packages/design-system/src/css/style.css index 0f2bca812..fcadf31de 100644 --- a/packages/design-system/src/css/style.css +++ b/packages/design-system/src/css/style.css @@ -68,8 +68,8 @@ --color-neutral-550: #636363; - --color-stone-100: #444444; - --color-stone-200: #828282; + --color-stone-100: #828282; + --color-stone-200: #444444; --color-stone-300: #bbbbbb; --color-ivory-100: #fdfbfa; @@ -128,12 +128,90 @@ --color-dark-elevation-2: rgba(from white r g b / 0.03); } +:root { + --backdrop: var(--color-white); + --dialog-surface: var(--color-neutral-200); + --node-component-border: var(--color-gray-400); + --node-component-executing: var(--color-blue-500); + --node-component-header: var(--fg-color); + --node-component-header-icon: var(--color-stone-200); + --node-component-header-surface: var(--color-white); + --node-component-outline: var(--color-black); + --node-component-ring: rgb(from var(--color-gray-500) r g b / 50%); + --node-component-slot-dot-outline-opacity-mult: 1; + --node-component-slot-dot-outline-opacity: 5%; + --node-component-slot-dot-outline: var(--color-black); + --node-component-slot-text: var(--color-stone-200); + --node-component-surface-highlight: var(--color-stone-100); + --node-component-surface-hovered: var(--color-charcoal-400); + --node-component-surface-selected: var(--color-charcoal-200); + --node-component-surface: var(--color-white); + --node-component-tooltip: var(--color-charcoal-700); + --node-component-tooltip-border: var(--color-sand-100); + --node-component-tooltip-surface: var(--color-white); + --node-component-widget-input: var(--fg-color); + --node-component-widget-input-surface: rgb(from var(--color-zinc-500) r g b / 10%); + --node-component-widget-skeleton-surface: var(--color-zinc-300); + --node-stroke: var(--color-stone-100); +} + +.dark-theme { + --backdrop: var(--color-neutral-900); + --dialog-surface: var(--color-neutral-700); + --node-component-border: var(--color-stone-200); + --node-component-header-icon: var(--color-slate-300); + --node-component-header-surface: var(--color-charcoal-800); + --node-component-outline: var(--color-white); + --node-component-ring: rgb(var(--color-gray-500) / 20%); + --node-component-slot-dot-outline-opacity: 10%; + --node-component-slot-dot-outline: var(--color-white); + --node-component-slot-text: var(--color-slate-200); + --node-component-surface-highlight: var(--color-slate-100); + --node-component-surface-hovered: var(--color-charcoal-400); + --node-component-surface-selected: var(--color-charcoal-200); + --node-component-surface: var(--color-charcoal-800); + --node-component-tooltip: var(--color-white); + --node-component-tooltip-border: var(--color-slate-300); + --node-component-tooltip-surface: var(--color-charcoal-800); + --node-component-widget-skeleton-surface: var(--color-zinc-800); + --node-stroke: var(--color-slate-100); +} + @theme inline { - --color-node-component-surface: var(--color-charcoal-600); - --color-node-component-surface-highlight: var(--color-slate-100); - --color-node-component-surface-hovered: var(--color-charcoal-400); - --color-node-component-surface-selected: var(--color-charcoal-200); - --color-node-stroke: var(--color-stone-100); + --color-backdrop: var(--backdrop); + --color-dialog-surface: var(--dialog-surface); + --color-node-component-border: var(--node-component-border); + --color-node-component-executing: var(--node-component-executing); + --color-node-component-header: var(--node-component-header); + --color-node-component-header-icon: var(--node-component-header-icon); + --color-node-component-header-surface: var(--node-component-header-surface); + --color-node-component-outline: var(--node-component-outline); + --color-node-component-ring: var(--node-component-ring); + --color-node-component-slot-dot-outline: rgb( + from var(--node-component-slot-dot-outline) r g b / + calc( + var(--node-component-slot-dot-outline-opacity) * + var(--node-component-slot-dot-outline-opacity-mult) + ) + ); + --color-node-component-slot-text: var(--node-component-slot-text); + --color-node-component-surface-highlight: var( + --node-component-surface-highlight + ); + --color-node-component-surface-hovered: var(--node-component-surface-hovered); + --color-node-component-surface-selected: var(--component-surface-selected); + --color-node-component-surface: var(--node-component-surface); + --color-node-component-tooltip: var(--node-component-tooltip); + --color-node-component-tooltip-border: var(--node-component-tooltip-border); + --color-node-component-tooltip-surface: var(--node-component-tooltip-surface); + --color-node-component-widget-input: var(--node-component-widget-input); + --color-node-component-widget-input-surface: var( + --node-component-widget-input-surface + ); + --color-node-component-widget-skeleton-surface: var( + --node-component-widget-skeleton-surface + ); + --color-node-stroke: var(--node-stroke); } @custom-variant dark-theme { @@ -152,7 +230,7 @@ } } -/* Everthing below here to be cleaned up over time. */ +/* Everything below here to be cleaned up over time. */ body { width: 100vw; diff --git a/packages/registry-types/package.json b/packages/registry-types/package.json new file mode 100644 index 000000000..bdc63b122 --- /dev/null +++ b/packages/registry-types/package.json @@ -0,0 +1,16 @@ +{ + "name": "@comfyorg/registry-types", + "version": "1.0.0", + "description": "Comfy Registry API TypeScript types", + "packageManager": "pnpm@10.17.1", + "type": "module", + "exports": { + ".": "./src/comfyRegistryTypes.ts" + }, + "nx": { + "tags": [ + "scope:shared", + "type:types" + ] + } +} diff --git a/packages/registry-types/src/comfyRegistryTypes.ts b/packages/registry-types/src/comfyRegistryTypes.ts new file mode 100644 index 000000000..32dc4f675 --- /dev/null +++ b/packages/registry-types/src/comfyRegistryTypes.ts @@ -0,0 +1,19469 @@ +/** + * This file was auto-generated by openapi-typescript. + * Do not make direct changes to the file. + */ + +export interface paths { + '/users': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** Get information about the calling user. */ + get: operations['getUser'] + put?: never + post?: never + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/customers': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** + * Search for customers + * @description Search for customers by email, name, Stripe ID, or Metronome ID. + */ + get: operations['searchCustomers'] + put?: never + /** + * Create a new customer + * @description Creates a new customer using the provided token. No request body is needed as user information is extracted from the token. + */ + post: operations['createCustomer'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/customers/me': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** + * Get authenticated customer details + * @description Returns details about the currently authenticated customer based on their JWT token. + */ + get: operations['getAuthenticatedCustomer'] + put?: never + post?: never + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/customers/{customer_id}': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** + * Get a customer by ID + * @description Returns details about a customer by their ID. + */ + get: operations['getCustomerById'] + put?: never + post?: never + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/customers/api-keys': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** List all API keys for a customer */ + get: operations['listCustomerAPIKeys'] + put?: never + /** Create a new API key for a customer */ + post: operations['createCustomerAPIKey'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/customers/api-keys/{api_key_id}': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + post?: never + /** Delete an API key for a customer */ + delete: operations['deleteCustomerAPIKey'] + options?: never + head?: never + patch?: never + trace?: never + } + '/customers/credit': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** Initiates a Credit Purchase. */ + post: operations['InitiateCreditPurchase'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/customers/billing': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** + * Access customer billing portal + * @description Creates a session for the customer to access their billing portal where they can manage subscriptions, payment methods, and view invoices. + */ + post: operations['AccessBillingPortal'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/customers/usage': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** + * Get customer's usage + * @description Returns the customer's as a dashboard URL. + */ + post: operations['GetCustomerUsage'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/customers/balance': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** + * Get customer's remaining balance + * @description Returns the customer's current remaining balance in microamount and its currency. + */ + get: operations['GetCustomerBalance'] + put?: never + post?: never + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/customers/{customer_id}/balance': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** + * Get customer's remaining balance by ID + * @description Returns the specified customer's current remaining balance in microamount and its currency. + */ + get: operations['GetCustomerBalanceById'] + put?: never + post?: never + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/customers/storage': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** + * Store a resource for a customer + * @description Store a resource for a customer. Resource will have a 24 hour expiry. The signed URL will be generated for the specified file path. + */ + post: operations['createCustomerStorageResource'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/customers/{customer_id}/events': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** Get events related to customer */ + get: operations['GetCustomerEventsById'] + put?: never + post?: never + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/customers/events': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** Get events related to customer */ + get: operations['GetCustomerEvents'] + put?: never + post?: never + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/upload-artifact': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** + * Receive artifacts (output files) from the ComfyUI GitHub Action + * @description Receive artifacts (output files) from the ComfyUI GitHub Action + */ + post: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody: { + content: { + 'application/json': { + /** @description Repository name */ + repo: string + /** @description Unique identifier for the job */ + job_id: string + /** @description Unique identifier for the run */ + run_id: string + /** @description Operating system used in the run */ + os: string + /** @description Cuda version. */ + cuda_version?: string + /** @description The name of the bucket where the output files are stored */ + bucket_name?: string + /** @description A comma separated string that contains GCS path(s) to output files. eg. gs://bucket-name/output, gs://bucket-name/output2 */ + output_files_gcs_paths?: string + /** @description The path to ComfyUI logs. eg. gs://bucket-name/logs */ + comfy_logs_gcs_path?: string + /** @description The flags used in the comfy run */ + comfy_run_flags?: string + commit_hash: string + /** @description The time of the commit in the format of "YYYY-MM-DDTHH:MM:SSZ" (2016-10-10T00:00:00Z) */ + commit_time: string + /** @description The commit message */ + commit_message: string + /** @description The name of the workflow */ + workflow_name: string + branch_name: string + /** + * Format: int64 + * @description The start time of the job as a Unix timestamp. + */ + start_time: number + /** + * Format: int64 + * @description The end time of the job as a Unix timestamp. + */ + end_time: number + /** @description The average amount of VRAM used in the run. */ + avg_vram?: number + /** @description The peak amount of VRAM used in the run. */ + peak_vram?: number + /** @description The pull request number */ + pr_number: string + /** @description The author of the commit */ + author: string + /** @description The user who triggered the job */ + job_trigger_user: string + /** @description The python version used in the run */ + python_version: string + /** @description The pytorch version used in the run */ + pytorch_version?: string + machine_stats?: components['schemas']['MachineStats'] + status: components['schemas']['WorkflowRunStatus'] + } + } + } + responses: { + /** @description Successfully received the artifact details */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': { + message?: string + } + } + } + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content?: never + } + } + } + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/gitcommit': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** + * Retrieve CI data for a given commit + * @description Returns all runs, jobs, job results, and storage files associated with a given commit. + */ + get: { + parameters: { + query?: { + /** @description The ID of the commit to fetch data for. */ + commitId?: string + /** @description The operating system to filter the CI data by. */ + operatingSystem?: string + /** @description The name of the workflow to filter the CI data by. */ + workflowName?: string + /** @description The branch of the gitcommit to filter the CI data by. */ + branch?: string + /** @description The page number to retrieve. */ + page?: number + /** @description The number of items to include per page. */ + pageSize?: number + /** @description The repo to filter by. */ + repoName?: string + } + header?: never + path?: never + cookie?: never + } + requestBody?: never + responses: { + /** @description An object containing runs, jobs, job results, and storage files */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': { + jobResults?: components['schemas']['ActionJobResult'][] + totalNumberOfPages?: number + } + } + } + /** @description Commit not found */ + 404: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content?: never + } + } + } + put?: never + post?: never + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/gitcommitsummary': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** + * Retrieve a summary of git commits + * @description Returns a summary of git commits, including status, start time, and end time. + */ + get: { + parameters: { + query?: { + /** @description The repository name to filter the git commits by. */ + repoName?: string + /** @description The branch name to filter the git commits by. */ + branchName?: string + /** @description The page number to retrieve. */ + page?: number + /** @description The number of items to include per page. */ + pageSize?: number + } + header?: never + path?: never + cookie?: never + } + requestBody?: never + responses: { + /** @description Successfully retrieved git commit summaries */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': { + commitSummaries?: components['schemas']['GitCommitSummary'][] + totalNumberOfPages?: number + } + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': { + message?: string + } + } + } + } + } + put?: never + post?: never + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/workflowresult/{workflowResultId}': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** Retrieve a specific commit by ID */ + get: operations['getWorkflowResult'] + put?: never + post?: never + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/branch': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** + * Retrieve all distinct branches for a given repo + * @description Returns all branches for a given repo. + */ + get: { + parameters: { + query: { + /** @description The repo to filter by. */ + repo_name: string + } + header?: never + path?: never + cookie?: never + } + requestBody?: never + responses: { + /** @description An array of branches */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': { + branches?: string[] + } + } + } + /** @description Repo not found */ + 404: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content?: never + } + } + } + put?: never + post?: never + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/users/publishers/': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** Retrieve all publishers for a given user */ + get: operations['listPublishersForUser'] + put?: never + post?: never + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/publishers/{publisherId}/permissions': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** Retrieve permissions the user has for a given publisher */ + get: operations['getPermissionOnPublisher'] + put?: never + post?: never + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/publishers/validate': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** + * Validate if a publisher username is available + * @description Checks if the publisher username is already taken. + */ + get: operations['validatePublisher'] + put?: never + post?: never + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/publishers': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** Retrieve all publishers */ + get: operations['listPublishers'] + put?: never + /** Create a new publisher */ + post: operations['createPublisher'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/publishers/{publisherId}': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** Retrieve a publisher by ID */ + get: operations['getPublisher'] + /** Update a publisher */ + put: operations['updatePublisher'] + post?: never + /** Delete a publisher */ + delete: operations['deletePublisher'] + options?: never + head?: never + patch?: never + trace?: never + } + '/publishers/{publisherId}/ban': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** Ban a publisher */ + post: operations['BanPublisher'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/publishers/{publisherId}/nodes/{nodeId}/claim-my-node': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** + * Claim nodeId into publisherId for the authenticated publisher + * @description This endpoint allows a publisher to claim an unclaimed node that they own the repo, which is identified by the nodeId. The unclaimed node's repository must be owned by the authenticated user. + * + */ + post: operations['claimMyNode'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/publishers/{publisherId}/nodes/v2': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** Retrieve all nodes */ + get: operations['listNodesForPublisherV2'] + put?: never + post?: never + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/publishers/{publisherId}/nodes': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** Retrieve all nodes */ + get: operations['listNodesForPublisher'] + put?: never + /** Create a new custom node */ + post: operations['createNode'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/publishers/{publisherId}/nodes/{nodeId}': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + /** Update a specific node */ + put: operations['updateNode'] + post?: never + /** Delete a specific node */ + delete: operations['deleteNode'] + options?: never + head?: never + patch?: never + trace?: never + } + '/publishers/{publisherId}/nodes/{nodeId}/permissions': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** Retrieve permissions the user has for a given publisher */ + get: operations['getPermissionOnPublisherNodes'] + put?: never + post?: never + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/publishers/{publisherId}/nodes/{nodeId}/versions': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** Publish a new version of a node */ + post: operations['publishNodeVersion'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/publishers/{publisherId}/nodes/{nodeId}/versions/{versionId}': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + /** + * Update changelog and deprecation status of a node version + * @description Update only the changelog and deprecated status of a specific version of a node. + */ + put: operations['updateNodeVersion'] + post?: never + /** Unpublish (delete) a specific version of a node */ + delete: operations['deleteNodeVersion'] + options?: never + head?: never + patch?: never + trace?: never + } + '/publishers/{publisherId}/nodes/{nodeId}/ban': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** Ban a publisher's Node */ + post: operations['BanPublisherNode'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/publishers/{publisherId}/tokens': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** Retrieve all personal access tokens for a publisher */ + get: operations['listPersonalAccessTokens'] + put?: never + /** Create a new personal access token */ + post: operations['createPersonalAccessToken'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/publishers/{publisherId}/tokens/{tokenId}': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + post?: never + /** Delete a specific personal access token */ + delete: operations['deletePersonalAccessToken'] + options?: never + head?: never + patch?: never + trace?: never + } + '/nodes/search': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** + * Retrieves a list of nodes + * @description Returns a paginated list of nodes across all publishers. + */ + get: operations['searchNodes'] + put?: never + post?: never + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/nodes/reindex': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** Reindex all nodes for searching. */ + post: operations['reindexNodes'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/nodes/update-github-stars': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** Update GitHub stars for nodes */ + post: operations['updateGithubStars'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/nodes': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** + * Retrieves a list of nodes + * @description Returns a paginated list of nodes across all publishers. + */ + get: operations['listAllNodes'] + put?: never + post?: never + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/comfy-nodes/{comfyNodeName}/node': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** + * Retrieve a node by ComfyUI node name + * @description Returns the node that contains a ComfyUI node with the specified name + */ + get: operations['getNodeByComfyNodeName'] + put?: never + post?: never + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/nodes/{nodeId}': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** + * Retrieve a specific node by ID + * @description Returns the details of a specific node. + */ + get: operations['getNode'] + put?: never + post?: never + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/nodes/{nodeId}/reviews': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** Add review to a specific version of a node */ + post: operations['postNodeReview'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/nodes/{nodeId}/install': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** + * Returns a node version to be installed. + * @description Retrieves the node data for installation, either the latest or a specific version. + */ + get: operations['installNode'] + put?: never + post?: never + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/nodes/{nodeId}/translations': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** Create Node Translations */ + post: operations['CreateNodeTranslations'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/nodes/{nodeId}/versions': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** List all versions of a node */ + get: operations['listNodeVersions'] + put?: never + post?: never + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/nodes/{nodeId}/versions/{versionId}': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** Retrieve a specific version of a node */ + get: operations['getNodeVersion'] + put?: never + post?: never + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/bulk/nodes/versions': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** Retrieve multiple node versions in a single request */ + post: operations['getBulkNodeVersions'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/versions': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** List all node versions given some filters. */ + get: operations['listAllNodeVersions'] + put?: never + post?: never + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/admin/nodes': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** Create a new custom node using admin privilege */ + post: operations['adminCreateNode'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/admin/nodes/{nodeId}': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + /** + * Admin Update Node + * @description Only admins can update a node with admin privileges. + */ + put: operations['adminUpdateNode'] + post?: never + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/admin/nodes/{nodeId}/versions/{versionNumber}': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + /** + * Admin Update Node Version Status + * @description Only admins can approve a node version. + */ + put: operations['adminUpdateNodeVersion'] + post?: never + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/releases': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** + * Get release notes + * @description Fetch release notes from Strapi with caching + */ + get: operations['getReleaseNotes'] + put?: never + /** + * Process Github release webhook + * @description Webhook endpoint to process Github release events and generate release notes + */ + post: operations['processReleaseWebhook'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/security-scan': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** + * Security Scan + * @description Pull all pending node versions and conduct security scans. + */ + get: operations['securityScan'] + put?: never + post?: never + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/nodes/{nodeId}/versions/{version}/comfy-nodes': { + parameters: { + query?: never + header?: never + path: { + nodeId: string + version: string + } + cookie?: never + } + /** list comfy-nodes for certain node */ + get: operations['ListComfyNodes'] + put?: never + /** create comfy-nodes for certain node */ + post: operations['CreateComfyNodes'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/nodes/{nodeId}/versions/{version}/comfy-nodes/{comfyNodeName}': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** get specify comfy-node based on its id */ + get: operations['GetComfyNode'] + put?: never + post?: never + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/comfy-nodes/backfill': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** trigger comfy nodes backfill */ + post: operations['ComfyNodesBackfill'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/dummy': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** + * Dummy proxy + * @description Dummy proxy endpoint that returns a simple string + */ + post: operations['dummyProxy'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/minimax/video_generation': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** + * Proxy request to Minimax for video generation + * @description Forwards video generation requests to Minimax's API and returns the task ID for asynchronous processing. + */ + post: operations['minimaxVideoGeneration'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/minimax/query/video_generation': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** + * Query status of a Minimax video generation task + * @description Proxies a request to Minimax to check the status of a video generation task + */ + get: operations['getMinimaxVideoGeneration'] + put?: never + post?: never + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/minimax/files/retrieve': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** + * Retrieve download URL for a Minimax file + * @description Proxies a request to Minimax to get the download URL for a file + */ + post: operations['retrieveMinimaxFile'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/ideogram/generate': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** + * Proxy request to Ideogram for image generation + * @description Forwards image generation requests to Ideogram's API and returns the results. + */ + post: operations['ideogramGenerate'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/ideogram/ideogram-v3/generate': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** + * Proxy request to Ideogram for image generation + * @description Forwards image generation requests to Ideogram's API and returns the results. + */ + post: operations['ideogramV3Generate'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/ideogram/ideogram-v3/edit': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** + * Proxy request to Ideogram for image editing + * @description Forwards image editing requests to Ideogram's API and returns the results. + */ + post: operations['ideogramV3Edit'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/ideogram/ideogram-v3/remix': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** Remix an image using a prompt */ + post: operations['ideogramV3Remix'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/ideogram/ideogram-v3/reframe': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** Reframe an image to a chosen resolution */ + post: operations['ideogramV3Reframe'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/ideogram/ideogram-v3/replace-background': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** Replace background of an image using a prompt */ + post: operations['ideogramV3ReplaceBackground'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/kling/v1/account/costs': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** KlingAI Query Resource Package Information */ + get: operations['klingQueryResourcePackages'] + put?: never + post?: never + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/kling/v1/videos/text2video': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** KlingAI Query Task List */ + get: operations['klingText2VideoQueryTaskList'] + put?: never + /** KlingAI Create Video from Text */ + post: operations['klingCreateVideoFromText'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/kling/v1/videos/text2video/{id}': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** KlingAI Query Single Task */ + get: operations['klingText2VideoQuerySingleTask'] + put?: never + post?: never + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/kling/v1/videos/image2video': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** KlingAI Query Image2Video Task List */ + get: operations['klingImage2VideoQueryTaskList'] + put?: never + /** KlingAI Create Video from Image */ + post: operations['klingCreateVideoFromImage'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/kling/v1/videos/image2video/{id}': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** KlingAI Query Single Image2Video Task */ + get: operations['klingImage2VideoQuerySingleTask'] + put?: never + post?: never + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/kling/v1/videos/video-extend': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** KlingAI Query Video-Extend Task List */ + get: operations['klingVideoExtendQueryTaskList'] + put?: never + /** KlingAI Extend Video Duration */ + post: operations['klingExtendVideo'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/kling/v1/videos/video-extend/{id}': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** KlingAI Query Single Video-Extend Task */ + get: operations['klingVideoExtendQuerySingleTask'] + put?: never + post?: never + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/kling/v1/videos/lip-sync': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** KlingAI Query Lip-Sync Task List */ + get: operations['klingLipSyncQueryTaskList'] + put?: never + /** KlingAI Create Lip-Sync Video */ + post: operations['klingCreateLipSyncVideo'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/kling/v1/videos/lip-sync/{id}': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** KlingAI Query Single Lip-Sync Task */ + get: operations['klingLipSyncQuerySingleTask'] + put?: never + post?: never + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/kling/v1/videos/effects': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** KlingAI Query Video Effects Task List */ + get: operations['klingVideoEffectsQueryTaskList'] + put?: never + /** KlingAI Create Video Effects Task */ + post: operations['klingCreateVideoEffects'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/kling/v1/videos/effects/{id}': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** KlingAI Query Single Video Effects Task */ + get: operations['klingVideoEffectsQuerySingleTask'] + put?: never + post?: never + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/kling/v1/images/generations': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** KlingAI Query Image Generation Task List */ + get: operations['klingImageGenerationsQueryTaskList'] + put?: never + /** KlingAI Create Image Generation Task */ + post: operations['klingCreateImageGeneration'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/kling/v1/images/generations/{id}': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** KlingAI Query Single Image Generation Task */ + get: operations['klingImageGenerationsQuerySingleTask'] + put?: never + post?: never + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/kling/v1/images/kolors-virtual-try-on': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** KlingAI Query Virtual Try-On Task List */ + get: operations['klingVirtualTryOnQueryTaskList'] + put?: never + /** KlingAI Create Virtual Try-On Task */ + post: operations['klingCreateVirtualTryOn'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/kling/v1/images/kolors-virtual-try-on/{id}': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** KlingAI Query Single Virtual Try-On Task */ + get: operations['klingVirtualTryOnQuerySingleTask'] + put?: never + post?: never + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/bfl/flux-kontext-pro/generate': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** + * Proxy request to BFL Flux Kontext Pro for image editing + * @description Forwards image editing requests to BFL's Flux Kontext Pro API and returns the results. + */ + post: operations['bflFluxKontextProGenerate'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/bfl/flux-kontext-max/generate': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** + * Proxy request to BFL Flux Kontext Max for image editing + * @description Forwards image editing requests to BFL's Flux Kontext Max API and returns the results. + */ + post: operations['bflFluxKontextMaxGenerate'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/bfl/flux-pro-1.1/generate': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** + * Proxy request to BFL Flux Pro 1.1 for image generation + * @description Forwards image generation requests to BFL's Flux Pro 1.1 API and returns the results. + */ + post: operations['bflFluxPro1_1Generate'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/bfl/flux-pro-1.1-ultra/generate': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** + * Proxy request to BFL Flux Pro 1.1 Ultra for image generation + * @description Forwards image generation requests to BFL's Flux Pro 1.1 Ultra API and returns the results. + */ + post: operations['bflFluxProGenerate'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/bfl/flux-pro-1.0-expand/generate': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** + * Expand an image by adding pixels on any side. + * @description Submits an image expansion task that adds the specified number of pixels to any combination of sides (top, bottom, left, right) while maintaining context. + */ + post: operations['BFLExpand_v1_flux_pro_1_0_expand_post'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/bfl/flux-pro-1.0-fill/generate': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** + * Generate an image with FLUX.1 Fill [pro] using an input image and mask. + * @description Submits an image generation task with the FLUX.1 Fill [pro] model using an input image and mask. Mask can be applied to alpha channel or submitted as a separate image. + */ + post: operations['BFLFill_v1_flux_pro_1_0_fill_post'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/bfl/flux-pro-1.0-canny/generate': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** + * Generate an image with FLUX.1 Canny [pro] using a control image. + * @description Submits an image generation task with FLUX.1 Canny [pro]. + */ + post: operations['BFLPro_canny_v1_flux_pro_1_0_canny_post'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/bfl/flux-pro-1.0-depth/generate': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** + * Generate an image with FLUX.1 Depth [pro] using a control image. + * @description Submits an image generation task with FLUX.1 Depth [pro]. + */ + post: operations['BFLPro_depth_v1_flux_pro_1_0_depth_post'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/luma/generations': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** + * Create a generation + * @description Initiate a new generation with the provided prompt + */ + post: operations['lumaCreateGeneration'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/luma/generations/{id}': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** + * Get a generation + * @description Retrieve details of a specific generation by its ID + */ + get: operations['lumaGetGeneration'] + put?: never + post?: never + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/luma/generations/image': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** + * Generate an image + * @description Generate an image with the provided prompt + */ + post: operations['lumaGenerateImage'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/pixverse/video/text/generate': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** Generate video from text prompt. */ + post: operations['PixverseGenerateTextVideo'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/pixverse/video/img/generate': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** Generate video from image. */ + post: operations['PixverseGenerateImageVideo'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/pixverse/video/transition/generate': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** Generate transition video between two images. */ + post: operations['PixverseGenerateTransitionVideo'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/pixverse/image/upload': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** Upload an image to the server. */ + post: operations['PixverseUploadImage'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/pixverse/video/result/{id}': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** Get the result of a video generation. */ + get: operations['PixverseGetVideoResult'] + put?: never + post?: never + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/webhook/metronome/zero-balance': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** receive alert on remaining balance is 0 */ + post: operations['metronomeZeroBalance'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/webhook/stripe/invoice-status': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** Handle Stripe checkout.session.completed webhook event */ + post: operations['StripeInvoiceStatus'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/recraft/image_generation': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** + * Proxy request to Recraft for image generation + * @description Forwards image generation requests to Recraft's API and returns the generated images. + */ + post: operations['recraftImageGeneration'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/recraft/images/vectorize': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** Vectorize an image */ + post: operations['recraftVectorize'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/recraft/images/crispUpscale': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** Upscale an image */ + post: operations['recraftCrispUpscale'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/recraft/images/removeBackground': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** Remove background from an image */ + post: operations['recraftRemoveBackground'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/recraft/images/imageToImage': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** Generate image from image and prompt */ + post: operations['RecraftImageToImage'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/recraft/images/inpaint': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** Inpaint Image */ + post: operations['RecraftInpaintImage'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/recraft/images/replaceBackground': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** Replace Background */ + post: operations['RecraftReplaceBackground'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/recraft/images/creativeUpscale': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** Creative Upscale */ + post: operations['RecraftCreativeUpscale'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/runway/image_to_video': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** + * Runway Image to Video Generation + * @description Converts an image to a video using Runway's API + */ + post: operations['runwayImageToVideo'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/runway/tasks/{task_id}': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** + * Get Runway Task Status + * @description Get the status and output of a Runway task + */ + get: operations['runwayGetTaskStatus'] + put?: never + post?: never + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/runway/text_to_image': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** + * Runway Text to Image Generation + * @description Generates an image from text using Runway's API + */ + post: operations['runwayTextToImage'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/veo/generate': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** Generate a video from a text prompt and optional image. Deprecated. Use /proxy/veo/{modelId}/generate instead. */ + post: operations['veoGenerate'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/veo/poll': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** Poll the status of a Veo prediction operation. Deprecated. Use /proxy/veo/{modelId}/generate instead. */ + post: operations['veoPoll'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/veo/{modelId}/generate': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** Generate a video from a text prompt and optional image */ + post: operations['veoGenerateNew'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/veo/{modelId}/poll': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** Poll the status of a Veo prediction operation */ + post: operations['veoPollNew'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/openai/v1/responses': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + post: operations['createOpenAIResponse'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/openai/v1/responses/{id}': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** Retrieves a model response with the given ID. + * */ + get: operations['getOpenAIResponse'] + put?: never + post?: never + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/openai/images/generations': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** Generate an image using OpenAI's models */ + post: operations['openAIGenerateImage'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/openai/images/edits': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** Edit an image using OpenAI's DALL-E model */ + post: operations['openAIEditImage'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/pika/generate/pikadditions': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** Generate Pikadditions */ + post: operations['PikaGenerate_pikadditions_generate_pikadditions_post'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/pika/generate/pikaswaps': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** + * Generate Pikaswaps + * @description Exactly one of `modifyRegionMask` and `modifyRegionRoi` must be provided. + */ + post: operations['PikaGenerate_pikaswaps_generate_pikaswaps_post'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/pika/generate/pikaffects': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** + * Generate Pikaffects + * @description Generate a video with a specific Pikaffect. Supported Pikaffects: Cake-ify, Crumble, Crush, Decapitate, Deflate, Dissolve, Explode, Eye-pop, Inflate, Levitate, Melt, Peel, Poke, Squish, Ta-da, Tear + */ + post: operations['PikaGenerate_pikaffects_generate_pikaffects_post'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/pika/generate/2.2/t2v': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** Generate 2 2 T2V */ + post: operations['PikaGenerate_2_2_t2v_generate_2_2_t2v_post'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/pika/generate/2.2/pikaframes': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** Generate 2 2 Keyframe */ + post: operations['PikaGenerate_2_2_keyframe_generate_2_2_pikaframes_post'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/pika/generate/2.2/pikascenes': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** Generate 2 2 C2V */ + post: operations['PikaGenerate_2_2_c2v_generate_2_2_pikascenes_post'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/pika/generate/2.2/i2v': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** Generate 2 2 I2V */ + post: operations['PikaGenerate_2_2_i2v_generate_2_2_i2v_post'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/pika/videos/{video_id}': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** Get Video */ + get: operations['PikaGet_video_videos__video_id__get'] + put?: never + post?: never + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/stability/v2beta/stable-image/generate/ultra': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** + * Stable Image Ultra + * @description Our most advanced text to image generation service, Stable Image Ultra creates the highest quality images with unprecedented prompt understanding. Ultra excels in typography, complex compositions, dynamic lighting, vibrant hues, and overall cohesion and structure of an art piece. Made from the most advanced models, including Stable Diffusion 3.5, Ultra offers the best of the Stable Diffusion ecosystem. ### Try it out Grab your [API key](https://platform.stability.ai/account/keys) and head over to [![Open Google Colab](https://platform.stability.ai/svg/google-colab.svg)](https://colab.research.google.com/github/stability-ai/stability-sdk/blob/main/nbs/Stable_Image_API_Public.ipynb#scrollTo=yXhs626oZdr1) ### How to use Please invoke this endpoint with a `POST` request. The headers of the request must include an API key in the `authorization` field. The body of the request must be `multipart/form-data`. The accept header should be set to one of the following: - `image/*` to receive the image in the format specified by the `output_format` parameter. - `application/json` to receive the image in the format specified by the `output_format` parameter, but encoded to base64 in a JSON response. The only required parameter is the `prompt` field, which should contain the text prompt for the image generation. The body of the request should include: - `prompt` - text to generate the image from The body may optionally include: - `image` - the image to use as the starting point for the generation - `strength` - controls how much influence the `image` parameter has on the output image - `aspect_ratio` - the aspect ratio of the output image - `negative_prompt` - keywords of what you **do not** wish to see in the output image - `seed` - the randomness seed to use for the generation - `output_format` - the the format of the output image > **Note:** for the full list of optional parameters, please see the request schema below. ### Output The resolution of the generated image will be 1 megapixel. The default resolution is 1024x1024. ### Credits The Ultra service uses 8 credits per successful result. You will not be charged for failed results. + */ + post: operations['StabilityImageGenrationUltra'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/stability/v2beta/stable-image/generate/sd3': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** + * Stable Diffusion 3.5 + * @description Generate using Stable Diffusion 3.5 models, Stability AI latest base model: + * + * - **Stable Diffusion 3.5 Large**: At 8 billion parameters, with superior quality and + * + * + * + * prompt adherence, this base model is the most powerful in the Stable Diffusion + * family. This model is ideal for professional use cases at 1 megapixel resolution. + * + * - **Stable Diffusion 3.5 Large Turbo**: A distilled version of Stable Diffusion 3.5 Large. + * + * + * + * SD3.5 Large Turbo generates high-quality images with exceptional prompt adherence + * in just 4 steps, making it considerably faster than Stable Diffusion 3.5 Large. + * + * - **Stable Diffusion 3.5 Medium**: With 2.5 billion parameters, the model delivers an + * + * + * + * optimal balance between prompt accuracy and image quality, making it an efficient + * choice for fast high-performance image generation. + * + * Read more about the model capabilities [here](https://stability.ai/news/introducing-stable-diffusion-3-5). + * + * As of April 17, 2025, we have deprecated the Stable Diffusion 3.0 APIs and will be automatically + * re-routing calls to Stable Diffusion 3.0 models to Stable Diffusion 3.5 APIs at no extra cost. + * You can read more in the [release notes](/docs/release-notes#api-deprecation-notice). + * + * ### Try it out + * Grab your [API key](https://platform.stability.ai/account/keys) and head over to [![Open Google Colab](https://platform.stability.ai/svg/google-colab.svg)](https://colab.research.google.com/github/stability-ai/stability-sdk/blob/main/nbs/SD3_API.ipynb) + * + * ### How to use + * Please invoke this endpoint with a `POST` request. + * + * The headers of the request must include an API key in the `authorization` field. The body of the request must be + * `multipart/form-data`. The accept header should be set to one of the following: + * - `image/*` to receive the image in the format specified by the `output_format` parameter. + * - `application/json` to receive the image encoded as base64 in a JSON response. + * + * #### **Generating with a prompt** + * Commonly referred to as **text-to-image**, this mode generates an image from text alone. While the only required + * parameter is the `prompt`, it also supports an `aspect_ratio` parameter which can be used to control the + * aspect ratio of the generated image. + * + * #### **Generating with a prompt *and* an image** + * Commonly referred to as **image-to-image**, this mode also generates an image from text but uses an existing image as the + * starting point. The required parameters are: + * - `prompt` - text to generate the image from + * - `image` - the image to use as the starting point for the generation + * - `strength` - controls how much influence the `image` parameter has on the output image + * - `mode` - must be set to `image-to-image` + * + * > **Note:** maximum request size is 10MiB. + * + * #### **Optional Parameters:** + * Both modes support the following optional parameters: + * - `model` - the model to use (SD3.5 Large, SD3.5 Large Turbo, SD3.5 Medium) + * - `output_format` - the the format of the output image + * - `seed` - the randomness seed to use for the generation + * - `negative_prompt` - keywords of what you **do not** wish to see in the output image + * - `cfg_scale` - controls how strictly the diffusion process adheres to the prompt text + * - `style_preset` - guides the image model towards a particular style + * + * > **Note:** for more details about these parameters please see the request schema below. + * + * ### Output + * The resolution of the generated image will be 1MP. The default resolution is 1024x1024. + * + * ### Credits + * - **SD 3.5 Large**: Flat rate of 6.5 credits per successful generation. + * - **SD 3.5 Large Turbo**: Flat rate of 4 credits per successful generation. + * - **SD 3.5 Medium**: Flat rate of 3.5 credits per successful generation. + * + * As always, you will not be charged for failed generations. + */ + post: operations['StabilityImageGenrationSD3'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/stability/v2beta/stable-image/upscale/conservative': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** + * Conservative + * @description Takes images between 64x64 and 1 megapixel and upscales them all the way to 4K resolution. Put more generally, it can upscale images ~20-40x times while preserving all aspects. Conservative Upscale minimizes alterations to the image and should not be used to reimagine an image. + * + * ### Try it out + * Grab your [API key](https://platform.stability.ai/account/keys) and head over to [![Open Google Colab](https://platform.stability.ai/svg/google-colab.svg)](https://colab.research.google.com/github/stability-ai/stability-sdk/blob/main/nbs/Stable_Image_API_Public.ipynb#scrollTo=t1Q4w2uvvza0) + * + * ### How to use + * + * Please invoke this endpoint with a `POST` request. + * + * The headers of the request must include an API key in the `authorization` field. The body of the request must be + * `multipart/form-data`, and the `accept` header should be set to one of the following: + * + * + * + * - `image/*` to receive the image in the format specified by the `output_format` parameter. + * - `application/json` to receive the image encoded as base64 in a JSON response. + * + * The body of the request must include: + * - `image` + * - `prompt` + * + * Optionally, the body of the request may also include: + * - `negative_prompt` + * - `seed` + * - `output_format` + * - `creativity` + * + * > **Note:** for more details about these parameters please see the request schema below. + * + * ### Output + * The resolution of the generated image will be 4 megapixels. + * + * ### Credits + * Flat rate of 25 credits per successful generation. You will not be charged for failed generations. + */ + post: operations['StabilityImageGenrationUpscaleConservative'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/stability/v2beta/stable-image/upscale/creative': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** + * Creative Upscale (async) + * @description Takes images between 64x64 and 1 megapixel and upscales them all the way to **4K** resolution. Put more + * generally, it can upscale images ~20-40x times while preserving, and often enhancing, quality. + * Creative Upscale **works best on highly degraded images and is not for photos of 1mp or above** as it performs + * heavy reimagining (controlled by creativity scale). + * + * ### Try it out + * Grab your [API key](https://platform.stability.ai/account/keys) and head over to [![Open Google Colab](https://platform.stability.ai/svg/google-colab.svg)](https://colab.research.google.com/github/stability-ai/stability-sdk/blob/main/nbs/Stable_Image_API_Public.ipynb#scrollTo=QXxi9tfI425t) + * + * + * ### How to use + * Please invoke this endpoint with a `POST` request. + * + * The headers of the request must include an API key in the `authorization` field. The body of the request must be + * `multipart/form-data`. + * + * The body of the request should include: + * - `image` + * - `prompt` + * + * The body may optionally include: + * - `seed` + * - `negative_prompt` + * - `output_format` + * - `creativity` + * - `style_preset` + * + * > **Note:** for more details about these parameters please see the request schema below. + * + * ### Results + * After invoking this endpoint with the required parameters, use the `id` in the response to poll for results at the + * [results/{id} endpoint](#tag/Results/paths/~1v2beta~1results~1%7Bid%7D/get). Rate-limiting or other errors may occur if you poll more than once every 10 seconds. + * + * ### Credits + * Flat rate of 25 credits per successful generation. You will not be charged for failed generations. + */ + post: operations['StabilityImageGenrationUpscaleCreative'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/stability/v2beta/stable-image/upscale/fast': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** + * Fast + * @description Our Fast Upscaler service enhances image resolution by 4x using predictive and generative AI. This lightweight and fast service (processing in ~1 second) is ideal for enhancing the quality of compressed images, making it suitable for social media posts and other applications. + * + * ### Try it out + * Grab your [API key](https://platform.stability.ai/account/keys) and head over to [![Open Google Colab](https://platform.stability.ai/svg/google-colab.svg)](https://colab.research.google.com/github/stability-ai/stability-sdk/blob/main/nbs/Stable_Image_API_Public.ipynb#scrollTo=t1Q4w2uvvza0) + * + * ### How to use + * + * Please invoke this endpoint with a `POST` request. + * + * The headers of the request must include an API key in the `authorization` field. The body of the request must be + * `multipart/form-data`, and the `accept` header should be set to one of the following: + * + * + * + * - `image/*` to receive the image in the format specified by the `output_format` parameter. + * - `application/json` to receive the image encoded as base64 in a JSON response. + * + * The body of the request must include: + * - `image` + * + * Optionally, the body of the request may also include: + * - `output_format` + * + * > **Note:** for more details about these parameters please see the request schema below. + * + * ### Output + * The resolution of the generated image is 4 times that of the input image with a maximum size of 16 megapixels. + * + * ### Credits + * Flat rate of 1 credit per successful generation. You will not be charged for failed generations. + */ + post: operations['StabilityImageGenerationUpscaleFast'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/stability/v2beta/results/{id}': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** + * Get Result + * @description Get the result of a generation + */ + get: operations['StabilityGetResult'] + put?: never + post?: never + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/vertexai/gemini/{model}': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** Generate content using a specified model. */ + post: operations['GeminiGenerateContent'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/vertexai/imagen/{model}': { + parameters: { + query?: never + header?: never + path: { + /** @description image generation model */ + model: + | 'imagen-3.0-generate-002' + | 'imagen-3.0-generate-001' + | 'imagen-3.0-fast-generate-001' + | 'imagegeneration@006' + | 'imagegeneration@005' + | 'imagegeneration@002' + } + cookie?: never + } + get?: never + put?: never + /** Generate images from a text prompt */ + post: operations['ImagenGenerateImages'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/tripo/v2/openapi/task/{task_id}': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** Get Task Status */ + get: operations['tripoGetTask'] + put?: never + post?: never + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/tripo/v2/openapi/upload': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** Upload File for 3D Generation */ + post: operations['tripoUploadFile'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/tripo/v2/openapi/task': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** Create 3D Generation Task */ + post: operations['tripoCreateTask'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/tripo/v2/openapi/user/balance': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** Query Account Balance */ + get: operations['tripoGetBalance'] + put?: never + post?: never + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/rodin/api/v2/rodin': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** Create 3D generate Task using Rodin API. */ + post: operations['rodinGenerate3DAsset'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/rodin/api/v2/status': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** Check Rodin 3D Generate Status. */ + post: operations['rodinCheckStatus'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/rodin/api/v2/download': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** Get rodin 3D Assets download list. */ + post: operations['rodinDownload'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/moonvalley/prompts/{prompt_id}': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** Get Prompt Details */ + get: operations['MoonvalleyGetPrompt'] + put?: never + post?: never + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/moonvalley/prompts/text-to-video': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** Create Text to Video Prompt */ + post: operations['MoonvalleyTextToVideo'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/moonvalley/prompts/text-to-image': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** Create Text to Image Prompt */ + post: operations['MoonvalleyTextToImage'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/moonvalley/prompts/image-to-video': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** Create Image to Video Prompt */ + post: operations['MoonvalleyImageToVideo'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/moonvalley/prompts/video-to-video': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** Create Video to Video Prompt */ + post: operations['MoonvalleyVideoToVideo'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/moonvalley/prompts/video-to-video/resize': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** Resize a video */ + post: operations['MoonvalleyVideoToVideoResize'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } + '/proxy/moonvalley/uploads': { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + get?: never + put?: never + /** Upload Files */ + post: operations['MoonvalleyUpload'] + delete?: never + options?: never + head?: never + patch?: never + trace?: never + } +} +export type webhooks = Record +export interface components { + schemas: { + ClaimMyNodeRequest: { + /** @description GitHub token to verify if the user owns the repo of the node */ + GH_TOKEN: string + } + BulkNodeVersionsRequest: { + /** @description List of node ID and version pairs to retrieve */ + node_versions: components['schemas']['NodeVersionIdentifier'][] + } + NodeVersionIdentifier: { + /** @description The unique identifier of the node */ + node_id: string + /** @description The version of the node */ + version: string + } + BulkNodeVersionsResponse: { + /** @description List of retrieved node versions with their status */ + node_versions: components['schemas']['BulkNodeVersionResult'][] + } + BulkNodeVersionResult: { + /** @description The node and version identifier */ + identifier: components['schemas']['NodeVersionIdentifier'] + /** + * @description Status of the retrieval operation + * @enum {string} + */ + status: 'success' | 'not_found' | 'error' + /** @description The retrieved node version data (only present if status is success) */ + node_version?: components['schemas']['NodeVersion'] + /** @description Error message if retrieval failed (only present if status is error) */ + error_message?: string + } + PersonalAccessToken: { + /** + * Format: uuid + * @description Unique identifier for the GitCommit + */ + id?: string + /** @description Required. The name of the token. Can be a simple description. */ + name?: string + /** @description Optional. A more detailed description of the token's intended use. */ + description?: string + /** + * Format: date-time + * @description [Output Only]The date and time the token was created. + */ + createdAt?: string + /** @description [Output Only]. The personal access token. Only returned during creation. */ + token?: string + } + GitCommit: { + /** + * Format: uuid + * @description Unique identifier for the GitCommit + */ + id?: string + /** @description The hash of the commit */ + commit_hash?: string + /** @description The name of the commit */ + commit_name?: string + /** @description The branch where the commit was made */ + branch_name?: string + /** @description The author of the commit */ + author?: string + /** + * Format: date-time + * @description The timestamp when the commit was made + */ + timestamp?: string + } + GitCommitSummary: { + /** @description The hash of the commit */ + commit_hash?: string + /** @description The name of the commit */ + commit_name?: string + /** @description The branch where the commit was made */ + branch_name?: string + /** @description The author of the commit */ + author?: string + /** + * Format: date-time + * @description The timestamp when the commit was made + */ + timestamp?: string + /** @description A map of operating system to status pairs */ + status_summary?: { + [key: string]: string + } + } + User: { + /** @description The unique id for this user. */ + id?: string + /** @description The email address for this user. */ + email?: string + /** @description The name for this user. */ + name?: string + /** @description Indicates if the user is approved. */ + isApproved?: boolean + /** @description Indicates if the user has admin privileges. */ + isAdmin?: boolean + } + PublisherUser: { + /** @description The unique id for this user. */ + id?: string + /** @description The email address for this user. */ + email?: string + /** @description The name for this user. */ + name?: string + } + ErrorResponse: { + error: string + message: string + } + RunwayTextToImageRequest: { + /** @description Text prompt for the image generation */ + promptText: string + /** + * @description Model to use for generation + * @enum {string} + */ + model: 'gen4_image' + /** @description The resolution (aspect ratio) of the output image */ + ratio: components['schemas']['RunwayTextToImageAspectRatioEnum'] + /** @description Array of reference images to guide the generation */ + referenceImages?: { + /** @description A HTTPS URL or data URI containing an encoded image */ + uri?: string + }[] + } + ActionJobResult: { + /** + * Format: uuid + * @description Unique identifier for the job result + */ + id?: string + /** @description Name of the workflow */ + workflow_name?: string + /** @description Operating system used */ + operating_system?: string + /** @description PyTorch version used */ + python_version?: string + /** @description PyTorch version used */ + pytorch_version?: string + /** @description Identifier of the run this result belongs to */ + action_run_id?: string + /** @description Identifier of the job this result belongs to */ + action_job_id?: string + /** @description CUDA version used */ + cuda_version?: string + /** @description Name of the relevant git branch */ + branch_name?: string + /** @description The hash of the commit */ + commit_hash?: string + /** @description The ID of the commit */ + commit_id?: string + /** + * Format: int64 + * @description The Unix timestamp when the commit was made + */ + commit_time?: number + /** @description The message of the commit */ + commit_message?: string + /** @description The comfy run flags. E.g. `--low-vram` */ + comfy_run_flags?: string + /** @description The repository name */ + git_repo?: string + /** @description The pull request number */ + pr_number?: string + /** + * Format: int64 + * @description The start time of the job as a Unix timestamp. + */ + start_time?: number + /** + * Format: int64 + * @description The end time of the job as a Unix timestamp. + */ + end_time?: number + /** @description The average VRAM used by the job */ + avg_vram?: number + /** @description The peak VRAM used by the job */ + peak_vram?: number + /** @description The user who triggered the job. */ + job_trigger_user?: string + /** @description The author of the commit */ + author?: string + machine_stats?: components['schemas']['MachineStats'] + status?: components['schemas']['WorkflowRunStatus'] + storage_file?: components['schemas']['StorageFile'] + } + StorageFile: { + /** + * Format: uuid + * @description Unique identifier for the storage file + */ + id?: string + /** @description Path to the file in storage */ + file_path?: string + /** @description Public URL */ + public_url?: string + } + Publisher: { + name?: string + /** @description The unique identifier for the publisher. It's akin to a username. Should be lowercase. */ + id?: string + description?: string + website?: string + support?: string + source_code_repo?: string + /** @description URL to the publisher's logo. */ + logo?: string + /** + * Format: date-time + * @description The date and time the publisher was created. + */ + createdAt?: string + /** @description A list of members in the publisher. */ + members?: components['schemas']['PublisherMember'][] + /** @description The status of the publisher. */ + status?: components['schemas']['PublisherStatus'] + } + PublisherMember: { + /** @description The unique identifier for the publisher member. */ + id?: string + /** @description The user associated with this publisher member. */ + user?: components['schemas']['PublisherUser'] + /** @description The role of the user in the publisher. */ + role?: string + } + Node: { + /** @description The unique identifier of the node. */ + id?: string + /** @description The display name of the node. */ + name?: string + /** @description The category of the node. */ + category?: string + description?: string + author?: string + /** @description The path to the LICENSE file in the node's repository. */ + license?: string + /** @description URL to the node's icon. */ + icon?: string + /** @description URL to the node's repository. */ + repository?: string + tags?: string[] + /** @description List of operating systems that this node supports */ + supported_os?: string[] + /** @description List of accelerators (e.g. CUDA, DirectML, ROCm) that this node supports */ + supported_accelerators?: string[] + /** @description Supported versions of ComfyUI */ + supported_comfyui_version?: string + /** @description Supported versions of ComfyUI frontend */ + supported_comfyui_frontend_version?: string + /** @description The latest version of the node. */ + latest_version?: components['schemas']['NodeVersion'] + /** @description The average rating of the node. */ + rating?: number + /** @description The number of downloads of the node. */ + downloads?: number + /** @description The publisher of the node. */ + publisher?: components['schemas']['Publisher'] + /** @description The status of the node. */ + status?: components['schemas']['NodeStatus'] + /** @description The status detail of the node. */ + status_detail?: string + /** @description Translations of node metadata in different languages. */ + translations?: { + [key: string]: { + [key: string]: unknown + } + } + /** @description A numerical value representing the node's search ranking, used for sorting search results. */ + search_ranking?: number + /** @description A list of Comfy node names that are preempted by this node. */ + preempted_comfy_node_names?: string[] + /** @description URL to the node's banner. */ + banner_url?: string + /** @description Number of stars on the GitHub repository. */ + github_stars?: number + /** + * Format: date-time + * @description The date and time when the node was created + */ + created_at?: string + } + NodeVersion: { + id?: string + /** @description The version identifier, following semantic versioning. Must be unique for the node. */ + version?: string + /** + * Format: date-time + * @description The date and time the version was created. + */ + createdAt?: string + /** @description Summary of changes made in this version */ + changelog?: string + /** @description A list of pip dependencies required by the node. */ + dependencies?: string[] + /** @description [Output Only] URL to download this version of the node */ + downloadUrl?: string + /** @description Indicates if this version is deprecated. */ + deprecated?: boolean + /** @description The status of the node version. */ + status?: components['schemas']['NodeVersionStatus'] + /** @description The reason for the status change. */ + status_reason?: string + /** @description The unique identifier of the node. */ + node_id?: string + /** @description The status of comfy node extraction process. */ + comfy_node_extract_status?: string + /** @description Supported versions of ComfyUI */ + supported_comfyui_version?: string + /** @description Supported versions of ComfyUI frontend */ + supported_comfyui_frontend_version?: string + /** @description List of operating systems that this node supports */ + supported_os?: string[] + /** @description List of accelerators (e.g. CUDA, DirectML, ROCm) that this node supports */ + supported_accelerators?: string[] + } + ComfyNode: { + /** @description Unique identifier for the node */ + comfy_node_name?: string + /** @description UI category where the node is listed, used for grouping nodes. */ + category?: string + /** @description Brief description of the node's functionality or purpose. */ + description?: string + /** @description Defines input parameters */ + input_types?: string + /** @description Indicates if the node is deprecated. Deprecated nodes are hidden in the UI. */ + deprecated?: boolean + /** @description Indicates if the node is experimental, subject to changes or removal. */ + experimental?: boolean + /** @description Boolean values indicating if each output is a list. */ + output_is_list?: boolean[] + /** @description Names of the outputs for clarity in workflows. */ + return_names?: string + /** @description Specifies the types of outputs produced by the node. */ + return_types?: string + /** @description Name of the entry-point function to execute the node. */ + function?: string + } + ComfyNodeCloudBuildInfo: { + project_id?: string + project_number?: string + location?: string + build_id?: string + } + Error: { + /** @description A clear and concise description of the error. */ + message?: string + /** @description Optional detailed information about the error or hints for resolving it. */ + details?: string[] + } + NodeVersionUpdateRequest: { + /** @description The changelog describing the version changes. */ + changelog?: string + /** @description Whether the version is deprecated. */ + deprecated?: boolean + } + /** @enum {string} */ + NodeStatus: 'NodeStatusActive' | 'NodeStatusDeleted' | 'NodeStatusBanned' + /** @enum {string} */ + NodeVersionStatus: + | 'NodeVersionStatusActive' + | 'NodeVersionStatusDeleted' + | 'NodeVersionStatusBanned' + | 'NodeVersionStatusPending' + | 'NodeVersionStatusFlagged' + /** @enum {string} */ + PublisherStatus: 'PublisherStatusActive' | 'PublisherStatusBanned' + /** @enum {string} */ + WorkflowRunStatus: + | 'WorkflowRunStatusStarted' + | 'WorkflowRunStatusFailed' + | 'WorkflowRunStatusCompleted' + MachineStats: { + /** @description Name of the machine. */ + machine_name?: string + /** @description The operating system version. eg. Ubuntu Linux 20.04 */ + os_version?: string + /** @description The GPU type. eg. NVIDIA Tesla K80 */ + gpu_type?: string + /** @description Total CPU on the machine. */ + cpu_capacity?: string + /** @description Initial CPU available before the job starts. */ + initial_cpu?: string + /** @description Total memory on the machine. */ + memory_capacity?: string + /** @description Initial RAM available before the job starts. */ + initial_ram?: string + /** @description Time series of VRAM usage. */ + vram_time_series?: Record + /** @description Total disk capacity on the machine. */ + disk_capacity?: string + /** @description Initial disk available before the job starts. */ + initial_disk?: string + /** @description The pip freeze output */ + pip_freeze?: string + } + Customer: { + /** @description The firebase UID of the user */ + id: string + /** @description The email address for this user */ + email?: string + /** @description The name for this user */ + name?: string + /** + * Format: date-time + * @description The date and time the user was created + */ + createdAt?: string + /** + * Format: date-time + * @description The date and time the user was last updated + */ + updatedAt?: string + /** @description Whether the user is an admin */ + is_admin?: boolean + /** @description The Stripe customer ID */ + stripe_id?: string + /** @description The Metronome customer ID */ + metronome_id?: string + /** @description Whether the user has funds */ + has_fund?: boolean + } + AuditLog: { + /** @description the type of the event */ + event_type?: string + /** @description the id of the event */ + event_id?: string + /** @description data related to the event */ + params?: { + [key: string]: unknown + } + /** + * Format: date-time + * @description The date and time the event was created + */ + createdAt?: string + } + IdeogramV3Request: { + /** @description The text prompt for image generation */ + prompt: string + /** @description Seed value for reproducible generation */ + seed?: number + /** + * @description Image resolution in format WxH + * @example 1280x800 + */ + resolution?: string + /** + * @description Aspect ratio in format WxH + * @example 1x3 + */ + aspect_ratio?: string + rendering_speed: components['schemas']['RenderingSpeed'] + /** + * @description Whether to enable magic prompt enhancement + * @enum {string} + */ + magic_prompt?: 'ON' | 'OFF' + /** @description Text prompt specifying what to avoid in the generation */ + negative_prompt?: string + /** @description Number of images to generate */ + num_images?: number + color_palette?: { + /** + * @description Name of the color palette + * @example PASTEL + */ + name: string + } + /** @description Array of style codes in hexadecimal format */ + style_codes?: string[] + /** + * @description The type of style to apply + * @enum {string} + */ + style_type?: 'GENERAL' + /** @description Array of reference image URLs or identifiers */ + style_reference_images?: string[] + } + IdeogramV3EditRequest: { + /** + * Format: binary + * @description The image being edited (max size 10MB); only JPEG, WebP and PNG formats are supported at this time. + */ + image?: string + /** + * Format: binary + * @description A black and white image of the same size as the image being edited (max size 10MB). Black regions in the mask should match up with the regions of the image that you would like to edit; only JPEG, WebP and PNG formats are supported at this time. + */ + mask?: string + /** @description The prompt used to describe the edited result. */ + prompt: string + /** @description Determine if MagicPrompt should be used in generating the request or not. */ + magic_prompt?: string + /** @description The number of images to generate. */ + num_images?: number + /** @description Random seed. Set for reproducible generation. */ + seed?: number + rendering_speed: components['schemas']['RenderingSpeed'] + /** @description A color palette for generation, must EITHER be specified via one of the presets (name) or explicitly via hexadecimal representations of the color with optional weights (members). Not supported by V_1, V_1_TURBO, V_2A and V_2A_TURBO models. */ + color_palette?: components['schemas']['IdeogramColorPalette'] + /** @description A list of 8 character hexadecimal codes representing the style of the image. Cannot be used in conjunction with style_reference_images or style_type. */ + style_codes?: string[] + /** @description A set of images to use as style references (maximum total size 10MB across all style references). The images should be in JPEG, PNG or WebP format. */ + style_reference_images?: string[] + } + /** @description A color palette specification that can either use a preset name or explicit color definitions with weights */ + IdeogramColorPalette: + | { + /** @description Name of the preset color palette */ + name: string + } + | { + /** @description Array of color definitions with optional weights */ + members: { + /** @description Hexadecimal color code */ + color?: string + /** @description Optional weight for the color (0-1) */ + weight?: number + }[] + } + /** @description Parameters for the Ideogram generation proxy request. Based on Ideogram's API. */ + IdeogramGenerateRequest: { + /** @description The image generation request parameters. */ + image_request: { + /** @description Required. The prompt to use to generate the image. */ + prompt: string + /** @description Optional. The aspect ratio (e.g., 'ASPECT_16_9', 'ASPECT_1_1'). Cannot be used with resolution. Defaults to 'ASPECT_1_1' if unspecified. */ + aspect_ratio?: string + /** @description The model used (e.g., 'V_2', 'V_2A_TURBO') */ + model: string + /** @description Optional. MagicPrompt usage ('AUTO', 'ON', 'OFF'). */ + magic_prompt_option?: string + /** + * Format: int64 + * @description Optional. A number between 0 and 2147483647. + */ + seed?: number + /** @description Optional. Style type ('AUTO', 'GENERAL', 'REALISTIC', 'DESIGN', 'RENDER_3D', 'ANIME'). Only for models V_2 and above. */ + style_type?: string + /** @description Optional. Description of what to exclude. Only for V_1, V_1_TURBO, V_2, V_2_TURBO. */ + negative_prompt?: string + /** + * @description Optional. Number of images to generate (1-8). Defaults to 1. + * @default 1 + */ + num_images: number + /** @description Optional. Resolution (e.g., 'RESOLUTION_1024_1024'). Only for model V_2. Cannot be used with aspect_ratio. */ + resolution?: string + /** @description Optional. Color palette object. Only for V_2, V_2_TURBO. */ + color_palette?: { + [key: string]: unknown + } + } + } + /** @description Response from the Ideogram image generation API. */ + IdeogramGenerateResponse: { + /** + * Format: date-time + * @description Timestamp when the generation was created. + */ + created?: string + /** @description Array of generated image information. */ + data?: { + /** @description The prompt used to generate this image. */ + prompt?: string + /** @description The resolution of the generated image (e.g., '1024x1024'). */ + resolution?: string + /** @description Indicates whether the image is considered safe. */ + is_image_safe?: boolean + /** @description The seed value used for this generation. */ + seed?: number + /** @description URL to the generated image. */ + url?: string + /** @description The style type used for generation (e.g., 'REALISTIC', 'ANIME'). */ + style_type?: string + }[] + } + IdeogramV3RemixRequest: { + /** Format: binary */ + image?: string + prompt: string + /** @default 50 */ + image_weight: number + seed?: number + resolution?: string + aspect_ratio?: string + /** @enum {string} */ + rendering_speed?: 'TURBO' | 'DEFAULT' | 'QUALITY' + /** @enum {string} */ + magic_prompt?: 'AUTO' | 'ON' | 'OFF' + negative_prompt?: string + num_images?: number + color_palette?: Record + style_codes?: string[] + /** @enum {string} */ + style_type?: 'AUTO' | 'GENERAL' | 'REALISTIC' | 'DESIGN' + style_reference_images?: string[] + } + IdeogramV3IdeogramResponse: { + /** Format: date-time */ + created?: string + data?: { + prompt?: string + resolution?: string + is_image_safe?: boolean + seed?: number + url?: string + style_type?: string + }[] + } + IdeogramV3ReframeRequest: { + /** Format: binary */ + image?: string + resolution: string + num_images?: number + seed?: number + /** @enum {string} */ + rendering_speed?: 'TURBO' | 'DEFAULT' | 'QUALITY' + color_palette?: Record + style_codes?: string[] + style_reference_images?: string[] + } + IdeogramV3ReplaceBackgroundRequest: { + /** Format: binary */ + image?: string + prompt: string + /** @enum {string} */ + magic_prompt?: 'AUTO' | 'ON' | 'OFF' + num_images?: number + seed?: number + /** @enum {string} */ + rendering_speed?: 'TURBO' | 'DEFAULT' | 'QUALITY' + color_palette?: Record + style_codes?: string[] + style_reference_images?: string[] + } + /** + * @description Task Status + * @enum {string} + */ + KlingTaskStatus: 'submitted' | 'processing' | 'succeed' | 'failed' + /** + * @description Model Name + * @default kling-v1 + * @enum {string} + */ + KlingTextToVideoModelName: 'kling-v1' | 'kling-v1-6' + /** + * @description Model Name + * @default kling-v2-master + * @enum {string} + */ + KlingVideoGenModelName: + | 'kling-v1' + | 'kling-v1-5' + | 'kling-v1-6' + | 'kling-v2-master' + /** + * @description Video generation mode. std: Standard Mode, which is cost-effective. pro: Professional Mode, generates videos with longer duration but higher quality output. + * @default std + * @enum {string} + */ + KlingVideoGenMode: 'std' | 'pro' + /** + * @description Video aspect ratio + * @default 16:9 + * @enum {string} + */ + KlingVideoGenAspectRatio: '16:9' | '9:16' | '1:1' + /** + * @description Video length in seconds + * @default 5 + * @enum {string} + */ + KlingVideoGenDuration: '5' | '10' + /** + * Format: float + * @description Flexibility in video generation. The higher the value, the lower the model's degree of flexibility, and the stronger the relevance to the user's prompt. + * @default 0.5 + */ + KlingVideoGenCfgScale: number + KlingCameraControl: { + type?: components['schemas']['KlingCameraControlType'] + config?: components['schemas']['KlingCameraConfig'] + } + /** + * @description Predefined camera movements type. simple: Customizable camera movement. down_back: Camera descends and moves backward. forward_up: Camera moves forward and tilts up. right_turn_forward: Rotate right and move forward. left_turn_forward: Rotate left and move forward. + * @enum {string} + */ + KlingCameraControlType: + | 'simple' + | 'down_back' + | 'forward_up' + | 'right_turn_forward' + | 'left_turn_forward' + KlingCameraConfig: { + /** @description Controls camera's movement along horizontal axis (x-axis). Negative indicates left, positive indicates right. */ + horizontal?: number + /** @description Controls camera's movement along vertical axis (y-axis). Negative indicates downward, positive indicates upward. */ + vertical?: number + /** @description Controls camera's rotation in vertical plane (x-axis). Negative indicates downward rotation, positive indicates upward rotation. */ + pan?: number + /** @description Controls camera's rotation in horizontal plane (y-axis). Negative indicates left rotation, positive indicates right rotation. */ + tilt?: number + /** @description Controls camera's rolling amount (z-axis). Negative indicates counterclockwise, positive indicates clockwise. */ + roll?: number + /** @description Controls change in camera's focal length. Negative indicates narrower field of view, positive indicates wider field of view. */ + zoom?: number + } + KlingVideoResult: { + /** @description Generated video ID */ + id?: string + /** + * Format: uri + * @description URL for generated video + */ + url?: string + /** @description Total video duration */ + duration?: string + } + /** + * @description Method of Transmitting Audio Files for Lip-Sync. Required when mode is audio2video. + * @enum {string} + */ + KlingAudioUploadType: 'file' | 'url' + /** + * @description Video Generation Mode. text2video: Text-to-video generation mode; audio2video: Audio-to-video generation mode + * @enum {string} + */ + KlingLipSyncMode: 'text2video' | 'audio2video' + /** + * @description The voice language corresponds to the Voice ID. + * @default en + * @enum {string} + */ + KlingLipSyncVoiceLanguage: 'zh' | 'en' + /** + * @description Scene Name. Dual-character Effects (hug, kiss, heart_gesture). + * @enum {string} + */ + KlingDualCharacterEffectsScene: 'hug' | 'kiss' | 'heart_gesture' + /** + * @description Scene Name. Single Image Effects (bloombloom, dizzydizzy, fuzzyfuzzy, squish, expansion). + * @enum {string} + */ + KlingSingleImageEffectsScene: + | 'bloombloom' + | 'dizzydizzy' + | 'fuzzyfuzzy' + | 'squish' + | 'expansion' + /** + * @description Model Name. Can be kling-v1, kling-v1-5, or kling-v1-6. + * @default kling-v1 + * @enum {string} + */ + KlingCharacterEffectModelName: 'kling-v1' | 'kling-v1-5' | 'kling-v1-6' + /** + * @description Model Name. Only kling-v1-6 is supported for single image effects. + * @enum {string} + */ + KlingSingleImageEffectModelName: 'kling-v1-6' + /** + * @description Video Length in seconds. Only 5-second videos are supported. + * @enum {string} + */ + KlingSingleImageEffectDuration: '5' + KlingDualCharacterImages: string[] + /** + * @description Aspect ratio of the generated images + * @default 16:9 + * @enum {string} + */ + KlingImageGenAspectRatio: + | '16:9' + | '9:16' + | '1:1' + | '4:3' + | '3:4' + | '3:2' + | '2:3' + | '21:9' + /** + * @description Image reference type + * @enum {string} + */ + KlingImageGenImageReferenceType: 'subject' | 'face' + /** + * @description Model Name + * @default kling-v1 + * @enum {string} + */ + KlingImageGenModelName: 'kling-v1' | 'kling-v1-5' | 'kling-v2' + KlingImageResult: { + /** @description Image Number (0-9) */ + index?: number + /** + * Format: uri + * @description URL for generated image + */ + url?: string + } + /** + * @description Model Name + * @default kolors-virtual-try-on-v1 + * @enum {string} + */ + KlingVirtualTryOnModelName: + | 'kolors-virtual-try-on-v1' + | 'kolors-virtual-try-on-v1-5' + KlingText2VideoRequest: { + model_name?: components['schemas']['KlingTextToVideoModelName'] + /** @description Positive text prompt */ + prompt?: string + /** @description Negative text prompt */ + negative_prompt?: string + cfg_scale?: components['schemas']['KlingVideoGenCfgScale'] + mode?: components['schemas']['KlingVideoGenMode'] + camera_control?: components['schemas']['KlingCameraControl'] + aspect_ratio?: components['schemas']['KlingVideoGenAspectRatio'] + duration?: components['schemas']['KlingVideoGenDuration'] + /** + * Format: uri + * @description The callback notification address + */ + callback_url?: string + /** @description Customized Task ID */ + external_task_id?: string + } + KlingText2VideoResponse: { + /** @description Error code */ + code?: number + /** @description Error message */ + message?: string + /** @description Request ID */ + request_id?: string + data?: { + /** @description Task ID */ + task_id?: string + task_status?: components['schemas']['KlingTaskStatus'] + task_info?: { + external_task_id?: string + } + /** @description Task creation time */ + created_at?: number + /** @description Task update time */ + updated_at?: number + task_result?: { + videos?: components['schemas']['KlingVideoResult'][] + } + } + } + KlingImage2VideoRequest: { + model_name?: components['schemas']['KlingVideoGenModelName'] + /** @description Reference Image - URL or Base64 encoded string, cannot exceed 10MB, resolution not less than 300*300px, aspect ratio between 1:2.5 ~ 2.5:1. Base64 should not include data:image prefix. */ + image?: string + /** @description Reference Image - End frame control. URL or Base64 encoded string, cannot exceed 10MB, resolution not less than 300*300px. Base64 should not include data:image prefix. */ + image_tail?: string + /** @description Positive text prompt */ + prompt?: string + /** @description Negative text prompt */ + negative_prompt?: string + cfg_scale?: components['schemas']['KlingVideoGenCfgScale'] + mode?: components['schemas']['KlingVideoGenMode'] + /** @description Static Brush Application Area (Mask image created by users using the motion brush). The aspect ratio must match the input image. */ + static_mask?: string + /** @description Dynamic Brush Configuration List (up to 6 groups). For 5-second videos, trajectory length must not exceed 77 coordinates. */ + dynamic_masks?: { + /** + * Format: uri + * @description Dynamic Brush Application Area (Mask image created by users using the motion brush). The aspect ratio must match the input image. + */ + mask?: string + trajectories?: { + /** @description The horizontal coordinate of trajectory point. Based on bottom-left corner of image as origin (0,0). */ + x?: number + /** @description The vertical coordinate of trajectory point. Based on bottom-left corner of image as origin (0,0). */ + y?: number + }[] + }[] + camera_control?: components['schemas']['KlingCameraControl'] + aspect_ratio?: components['schemas']['KlingVideoGenAspectRatio'] + duration?: components['schemas']['KlingVideoGenDuration'] + /** + * Format: uri + * @description The callback notification address. Server will notify when the task status changes. + */ + callback_url?: string + /** @description Customized Task ID. Must be unique within a single user account. */ + external_task_id?: string + } + KlingImage2VideoResponse: { + /** @description Error code */ + code?: number + /** @description Error message */ + message?: string + /** @description Request ID */ + request_id?: string + data?: { + /** @description Task ID */ + task_id?: string + task_status?: components['schemas']['KlingTaskStatus'] + task_info?: { + external_task_id?: string + } + /** @description Task creation time */ + created_at?: number + /** @description Task update time */ + updated_at?: number + task_result?: { + videos?: components['schemas']['KlingVideoResult'][] + } + } + } + KlingVideoExtendRequest: { + /** @description The ID of the video to be extended. Supports videos generated by text-to-video, image-to-video, and previous video extension operations. Cannot exceed 3 minutes total duration after extension. */ + video_id?: string + /** @description Positive text prompt for guiding the video extension */ + prompt?: string + /** @description Negative text prompt for elements to avoid in the extended video */ + negative_prompt?: string + cfg_scale?: components['schemas']['KlingVideoGenCfgScale'] + /** + * Format: uri + * @description The callback notification address. Server will notify when the task status changes. + */ + callback_url?: string + } + KlingVideoExtendResponse: { + /** @description Error code */ + code?: number + /** @description Error message */ + message?: string + /** @description Request ID */ + request_id?: string + data?: { + /** @description Task ID */ + task_id?: string + task_status?: components['schemas']['KlingTaskStatus'] + task_info?: { + external_task_id?: string + } + /** @description Task creation time */ + created_at?: number + /** @description Task update time */ + updated_at?: number + task_result?: { + videos?: components['schemas']['KlingVideoResult'][] + } + } + } + KlingLipSyncInputObject: { + /** @description The ID of the video generated by Kling AI. Only supports 5-second and 10-second videos generated within the last 30 days. */ + video_id?: string + /** @description Get link for uploaded video. Video files support .mp4/.mov, file size does not exceed 100MB, video length between 2-10s. */ + video_url?: string + mode: components['schemas']['KlingLipSyncMode'] + /** @description Text Content for Lip-Sync Video Generation. Required when mode is text2video. Maximum length is 120 characters. */ + text?: string + /** @description Voice ID. Required when mode is text2video. The system offers a variety of voice options to choose from. */ + voice_id?: string + voice_language?: components['schemas']['KlingLipSyncVoiceLanguage'] + /** + * @description Speech Rate. Valid range: 0.8~2.0, accurate to one decimal place. + * @default 1 + */ + voice_speed: number + audio_type?: components['schemas']['KlingAudioUploadType'] + /** @description Local Path of Audio File. Supported formats: .mp3/.wav/.m4a/.aac, maximum file size of 5MB. Base64 code. */ + audio_file?: string + /** @description Audio File Download URL. Supported formats: .mp3/.wav/.m4a/.aac, maximum file size of 5MB. */ + audio_url?: string + } + KlingLipSyncRequest: { + input: components['schemas']['KlingLipSyncInputObject'] + /** + * Format: uri + * @description The callback notification address. Server will notify when the task status changes. + */ + callback_url?: string + } + KlingLipSyncResponse: { + /** @description Error code */ + code?: number + /** @description Error message */ + message?: string + /** @description Request ID */ + request_id?: string + data?: { + /** @description Task ID */ + task_id?: string + task_status?: components['schemas']['KlingTaskStatus'] + task_info?: { + external_task_id?: string + } + /** @description Task creation time */ + created_at?: number + /** @description Task update time */ + updated_at?: number + task_result?: { + videos?: components['schemas']['KlingVideoResult'][] + } + } + } + KlingVideoEffectsRequest: { + effect_scene: + | components['schemas']['KlingDualCharacterEffectsScene'] + | components['schemas']['KlingSingleImageEffectsScene'] + input: components['schemas']['KlingVideoEffectsInput'] + /** + * Format: uri + * @description The callback notification address for the result of this task. + */ + callback_url?: string + /** @description Customized Task ID. Must be unique within a single user account. */ + external_task_id?: string + } + KlingVideoEffectsInput: + | components['schemas']['KlingSingleImageEffectInput'] + | components['schemas']['KlingDualCharacterEffectInput'] + KlingSingleImageEffectInput: { + model_name: components['schemas']['KlingSingleImageEffectModelName'] + /** @description Reference Image. URL or Base64 encoded string (without data:image prefix). File size cannot exceed 10MB, resolution not less than 300*300px, aspect ratio between 1:2.5 ~ 2.5:1. */ + image: string + duration: components['schemas']['KlingSingleImageEffectDuration'] + } + KlingDualCharacterEffectInput: { + model_name?: components['schemas']['KlingCharacterEffectModelName'] + mode?: components['schemas']['KlingVideoGenMode'] + images: components['schemas']['KlingDualCharacterImages'] + duration: components['schemas']['KlingVideoGenDuration'] + } + KlingVideoEffectsResponse: { + /** @description Error code */ + code?: number + /** @description Error message */ + message?: string + /** @description Request ID */ + request_id?: string + data?: { + /** @description Task ID */ + task_id?: string + task_status?: components['schemas']['KlingTaskStatus'] + task_info?: { + external_task_id?: string + } + /** @description Task creation time */ + created_at?: number + /** @description Task update time */ + updated_at?: number + task_result?: { + videos?: components['schemas']['KlingVideoResult'][] + } + } + } + KlingImageGenerationsRequest: { + model_name?: components['schemas']['KlingImageGenModelName'] + /** @description Positive text prompt */ + prompt: string + /** @description Negative text prompt */ + negative_prompt?: string + /** @description Reference Image - Base64 encoded string or image URL */ + image?: string + image_reference?: components['schemas']['KlingImageGenImageReferenceType'] + /** + * @description Reference intensity for user-uploaded images + * @default 0.5 + */ + image_fidelity: number + /** + * @description Subject reference similarity + * @default 0.45 + */ + human_fidelity: number + /** + * @description Number of generated images + * @default 1 + */ + n: number + aspect_ratio?: components['schemas']['KlingImageGenAspectRatio'] + /** + * Format: uri + * @description The callback notification address + */ + callback_url?: string + } + KlingImageGenerationsResponse: { + /** @description Error code */ + code?: number + /** @description Error message */ + message?: string + /** @description Request ID */ + request_id?: string + data?: { + /** @description Task ID */ + task_id?: string + task_status?: components['schemas']['KlingTaskStatus'] + /** @description Task status information */ + task_status_msg?: string + /** @description Task creation time */ + created_at?: number + /** @description Task update time */ + updated_at?: number + task_result?: { + images?: components['schemas']['KlingImageResult'][] + } + } + } + KlingVirtualTryOnRequest: { + model_name?: components['schemas']['KlingVirtualTryOnModelName'] + /** @description Reference human image - Base64 encoded string or image URL */ + human_image: string + /** @description Reference clothing image - Base64 encoded string or image URL */ + cloth_image?: string + /** + * Format: uri + * @description The callback notification address + */ + callback_url?: string + } + KlingVirtualTryOnResponse: { + /** @description Error code */ + code?: number + /** @description Error message */ + message?: string + /** @description Request ID */ + request_id?: string + data?: { + /** @description Task ID */ + task_id?: string + task_status?: components['schemas']['KlingTaskStatus'] + /** @description Task status information */ + task_status_msg?: string + /** @description Task creation time */ + created_at?: number + /** @description Task update time */ + updated_at?: number + task_result?: { + images?: components['schemas']['KlingImageResult'][] + } + } + } + KlingResourcePackageResponse: { + /** @description Error code; 0 indicates success */ + code?: number + /** @description Error information */ + message?: string + /** @description Request ID, generated by the system, used to track requests and troubleshoot problems */ + request_id?: string + data?: { + /** @description Error code; 0 indicates success */ + code?: number + /** @description Error information */ + msg?: string + /** @description Resource package list */ + resource_pack_subscribe_infos?: { + /** @description Resource package name */ + resource_pack_name?: string + /** @description Resource package ID */ + resource_pack_id?: string + /** + * @description Resource package type (decreasing_total=decreasing total, constant_period=constant periodicity) + * @enum {string} + */ + resource_pack_type?: 'decreasing_total' | 'constant_period' + /** + * Format: float + * @description Total quantity + */ + total_quantity?: number + /** + * Format: float + * @description Remaining quantity (updated with a 12-hour delay) + */ + remaining_quantity?: number + /** + * Format: int64 + * @description Purchase time, Unix timestamp in ms + */ + purchase_time?: number + /** + * Format: int64 + * @description Effective time, Unix timestamp in ms + */ + effective_time?: number + /** + * Format: int64 + * @description Expiration time, Unix timestamp in ms + */ + invalid_time?: number + /** + * @description Resource Package Status + * @enum {string} + */ + status?: 'toBeOnline' | 'online' | 'expired' | 'runOut' + }[] + } + } + StripeEvent: { + id: string + /** @enum {string} */ + object: 'event' + api_version?: string + created?: number + data: { + object?: components['schemas']['StripePaymentIntent'] + } + livemode?: boolean + pending_webhooks?: number + request?: components['schemas']['StripeRequestInfo'] + /** @enum {string} */ + type: 'payment_intent.succeeded' + } + StripeRequestInfo: { + id?: string | null + idempotency_key?: string | null + } + StripePaymentIntent: { + id?: string + /** @enum {string} */ + object?: 'payment_intent' + amount?: number + amount_capturable?: number + amount_details?: components['schemas']['StripeAmountDetails'] + amount_received?: number + application?: string | null + application_fee_amount?: number | null + automatic_payment_methods?: unknown + canceled_at?: number | null + cancellation_reason?: string | null + capture_method?: string + charges?: components['schemas']['StripeChargeList'] + client_secret?: string + confirmation_method?: string + created?: number + currency?: string + customer?: string | null + description?: string | null + invoice?: string | null + last_payment_error?: unknown + latest_charge?: string + livemode?: boolean + metadata?: Record + next_action?: unknown + on_behalf_of?: unknown + payment_method?: string + payment_method_configuration_details?: unknown + payment_method_options?: components['schemas']['StripePaymentMethodOptions'] + payment_method_types?: string[] + processing?: unknown + receipt_email?: string | null + review?: unknown + setup_future_usage?: unknown + shipping?: components['schemas']['StripeShipping'] + source?: unknown + statement_descriptor?: unknown + statement_descriptor_suffix?: unknown + status?: string + transfer_data?: unknown + transfer_group?: unknown + } + StripeAmountDetails: { + tip?: Record + } + StripeChargeList: { + object?: string + data?: components['schemas']['StripeCharge'][] + has_more?: boolean + total_count?: number + url?: string + } + StripeCharge: { + id?: string + /** @enum {string} */ + object?: 'charge' + amount?: number + amount_captured?: number + amount_refunded?: number + application?: string | null + application_fee?: string | null + application_fee_amount?: number | null + balance_transaction?: string | null + billing_details?: components['schemas']['StripeBillingDetails'] + calculated_statement_descriptor?: string + captured?: boolean + created?: number + currency?: string + customer?: string | null + description?: string | null + destination?: unknown + dispute?: unknown + disputed?: boolean + failure_balance_transaction?: unknown + failure_code?: unknown + failure_message?: unknown + fraud_details?: Record + invoice?: unknown + livemode?: boolean + metadata?: Record + on_behalf_of?: unknown + order?: unknown + outcome?: components['schemas']['StripeOutcome'] + paid?: boolean + payment_intent?: string + payment_method?: string + payment_method_details?: components['schemas']['StripePaymentMethodDetails'] + radar_options?: Record + receipt_email?: string | null + receipt_number?: string | null + receipt_url?: string + refunded?: boolean + refunds?: components['schemas']['StripeRefundList'] + review?: unknown + shipping?: components['schemas']['StripeShipping'] + source?: unknown + source_transfer?: unknown + statement_descriptor?: unknown + statement_descriptor_suffix?: unknown + status?: string + transfer_data?: unknown + transfer_group?: unknown + } + StripeBillingDetails: { + address?: components['schemas']['StripeAddress'] + email?: string | null + name?: string | null + phone?: string | null + tax_id?: unknown + } + StripeAddress: { + city?: string | null + country?: string | null + line1?: string | null + line2?: string | null + postal_code?: string | null + state?: string | null + } + StripeOutcome: { + advice_code?: unknown + network_advice_code?: unknown + network_decline_code?: unknown + network_status?: string + reason?: unknown + risk_level?: string + risk_score?: number + seller_message?: string + type?: string + } + StripePaymentMethodDetails: { + card?: components['schemas']['StripeCardDetails'] + type?: string + } + StripeCardDetails: { + amount_authorized?: number + authorization_code?: unknown + brand?: string + checks?: { + address_line1_check?: unknown + address_postal_code_check?: unknown + cvc_check?: string + } + country?: string + exp_month?: number + exp_year?: number + extended_authorization?: { + status?: string + } + fingerprint?: string + funding?: string + incremental_authorization?: { + status?: string + } + installments?: unknown + last4?: string + mandate?: unknown + multicapture?: { + status?: string + } + network?: string + network_token?: { + used?: boolean + } + network_transaction_id?: string + overcapture?: { + maximum_amount_capturable?: number + status?: string + } + regulated_status?: string + three_d_secure?: unknown + wallet?: unknown + } + StripeRefundList: { + object?: string + data?: Record[] + has_more?: boolean + total_count?: number + url?: string + } + StripePaymentMethodOptions: { + card?: { + installments?: unknown + mandate_options?: unknown + network?: unknown + request_three_d_secure?: string + } + } + StripeShipping: { + address?: components['schemas']['StripeAddress'] + carrier?: string | null + name?: string + phone?: string | null + tracking_number?: string | null + } + /** @description Parameters for the Minimax video generation proxy request. */ + MinimaxVideoGenerationRequest: { + /** + * @description Required. ID of model. Options: T2V-01-Director, I2V-01-Director, S2V-01, I2V-01, I2V-01-live, T2V-01 + * @enum {string} + */ + model: + | 'T2V-01-Director' + | 'I2V-01-Director' + | 'S2V-01' + | 'I2V-01' + | 'I2V-01-live' + | 'T2V-01' + /** @description Description of the video. Should be less than 2000 characters. Supports camera movement instructions in [brackets]. */ + prompt?: string + /** + * @description If true (default), the model will automatically optimize the prompt. Set to false for more precise control. + * @default true + */ + prompt_optimizer: boolean + /** @description URL or base64 encoding of the first frame image. Required when model is I2V-01, I2V-01-Director, or I2V-01-live. */ + first_frame_image?: string + /** @description Only available when model is S2V-01. The model will generate a video based on the subject uploaded through this parameter. */ + subject_reference?: { + /** @description URL or base64 encoding of the subject reference image. */ + image?: string + /** @description URL or base64 encoding of the mask for the subject reference image. */ + mask?: string + }[] + /** @description Optional. URL to receive real-time status updates about the video generation task. */ + callback_url?: string + } + /** @description Common response structure used by Minimax APIs */ + MinimaxBaseResponse: { + /** @description Status code. 0 indicates success, other values indicate errors. */ + status_code: number + /** @description Specific error details or success message. */ + status_msg: string + } + /** @description Response from the Minimax video generation API. */ + MinimaxVideoGenerationResponse: { + /** @description The task ID for the asynchronous video generation task. */ + task_id: string + base_resp: components['schemas']['MinimaxBaseResponse'] + } + /** @description Response from retrieving a Minimax file download URL. */ + MinimaxFileRetrieveResponse: { + file: { + /** @description Unique identifier for the file */ + file_id?: number + /** @description File size in bytes */ + bytes?: number + /** @description Unix timestamp when the file was created, in seconds */ + created_at?: number + /** @description The name of the file */ + filename?: string + /** @description The purpose of using the file */ + purpose?: string + /** @description The URL to download the video */ + download_url?: string + } + base_resp: components['schemas']['MinimaxBaseResponse'] + } + /** @description Response from querying a Minimax video generation task status. */ + MinimaxTaskResultResponse: { + /** @description The task ID being queried. */ + task_id: string + /** + * @description Task status: 'Queueing' (in queue), 'Preparing' (task is preparing), 'Processing' (generating), 'Success' (task completed successfully), or 'Fail' (task failed). + * @enum {string} + */ + status: 'Queueing' | 'Preparing' | 'Processing' | 'Success' | 'Fail' + /** @description After the task status changes to Success, this field returns the file ID corresponding to the generated video. */ + file_id?: string + base_resp: components['schemas']['MinimaxBaseResponse'] + } + BFLFluxKontextProGenerateRequest: { + /** @description The text prompt describing what to edit on the image */ + prompt: string + /** @description Base64 encoded image to be edited */ + input_image: string + /** + * @description Number of inference steps + * @default 50 + */ + steps: number + /** + * @description The guidance scale for generation + * @default 3 + */ + guidance: number + } + BFLFluxKontextProGenerateResponse: { + /** @description Job ID for tracking */ + id: string + /** @description URL to poll for results */ + polling_url: string + } + BFLFluxKontextMaxGenerateRequest: { + /** @description The text prompt describing what to edit on the image */ + prompt: string + /** @description Base64 encoded image to be edited */ + input_image: string + /** + * @description Number of inference steps + * @default 50 + */ + steps: number + /** + * @description The guidance scale for generation + * @default 3 + */ + guidance: number + } + BFLFluxKontextMaxGenerateResponse: { + /** @description Job ID for tracking */ + id: string + /** @description URL to poll for results */ + polling_url: string + } + BFLFluxPro1_1GenerateRequest: { + /** @description The main text prompt for image generation */ + prompt: string + /** @description Optional image prompt */ + image_prompt?: string + /** @description Width of the generated image */ + width: number + /** @description Height of the generated image */ + height: number + /** @description Whether to use prompt upsampling */ + prompt_upsampling?: boolean + /** @description Random seed for reproducibility */ + seed?: number + /** @description Safety tolerance level */ + safety_tolerance?: number + /** + * @description Output image format + * @enum {string} + */ + output_format?: 'jpeg' | 'png' + /** @description Optional webhook URL for async processing */ + webhook_url?: string + /** @description Optional webhook secret for async processing */ + webhook_secret?: string + } + BFLFluxPro1_1GenerateResponse: { + /** @description Job ID for tracking */ + id: string + /** @description URL to poll for results */ + polling_url: string + } + /** @description Request body for the BFL Flux Pro 1.1 Ultra image generation API. */ + BFLFluxProGenerateRequest: { + /** @description The text prompt for image generation. */ + prompt: string + /** @description The negative prompt for image generation. */ + negative_prompt?: string + /** @description The width of the image to generate. */ + width: number + /** @description The height of the image to generate. */ + height: number + /** @description The number of inference steps. */ + num_inference_steps?: number + /** @description The guidance scale for generation. */ + guidance_scale?: number + /** @description The seed value for reproducibility. */ + seed?: number + /** @description The number of images to generate. */ + num_images?: number + } + /** @description Response from the BFL Flux Pro 1.1 Ultra image generation API. */ + BFLFluxProGenerateResponse: { + /** @description The unique identifier for the generation task. */ + id: string + /** @description URL to poll for the generation result. */ + polling_url: string + } + /** @description Response from the BFL Flux Pro 1.1 Ultra status check API. */ + BFLFluxProStatusResponse: { + /** @description The unique identifier for the generation task. */ + id: string + /** @description The status of the task. */ + status: components['schemas']['BFLStatus'] + /** @description The result of the task (null if not completed). */ + result?: Record | null + /** + * Format: float + * @description The progress of the task (0.0 to 1.0). + */ + progress: number + /** @description Additional details about the task (null if not available). */ + details?: Record | null + } + /** + * @description Possible statuses for a BFL Flux Pro generation task. + * @example Ready + * @enum {string} + */ + BFLStatus: + | 'Task not found' + | 'Pending' + | 'Request Moderated' + | 'Content Moderated' + | 'Ready' + | 'Error' + /** FluxProFillInputs */ + BFLFluxProFillInputs: { + /** + * Image + * @description A Base64-encoded string representing the image you wish to modify. Can contain alpha mask if desired. + */ + image: string + /** + * Mask + * @description A Base64-encoded string representing a mask for the areas you want to modify in the image. The mask should be the same dimensions as the image and in black and white. Black areas (0%) indicate no modification, while white areas (100%) specify areas for inpainting. Optional if you provide an alpha mask in the original image. Validation: The endpoint verifies that the dimensions of the mask match the original image. + */ + mask?: string + /** + * Prompt + * @description The description of the changes you want to make. This text guides the inpainting process, allowing you to specify features, styles, or modifications for the masked area. + * @default + * @example ein fantastisches bild + */ + prompt: string + /** + * Steps + * @description Number of steps for the image generation process + * @default 50 + * @example 50 + */ + steps: number + /** + * Prompt Upsampling + * @description Whether to perform upsampling on the prompt. If active, automatically modifies the prompt for more creative generation + * @default false + */ + prompt_upsampling: boolean + /** + * Seed + * @description Optional seed for reproducibility + */ + seed?: number + /** + * Guidance + * @description Guidance strength for the image generation process + * @default 60 + */ + guidance: number + /** + * @description Output format for the generated image. Can be 'jpeg' or 'png'. + * @default jpeg + */ + output_format: components['schemas']['BFLOutputFormat'] + /** + * Safety Tolerance + * @description Tolerance level for input and output moderation. Between 0 and 6, 0 being most strict, 6 being least strict. + * @default 2 + * @example 2 + */ + safety_tolerance: number + /** + * Webhook Url + * @description URL to receive webhook notifications + */ + webhook_url?: string + /** + * Webhook Secret + * @description Optional secret for webhook signature verification + */ + webhook_secret?: string + } + /** AsyncResponse */ + BFLAsyncResponse: { + /** Id */ + id: string + /** Polling Url */ + polling_url: string + } + /** AsyncWebhookResponse */ + BFLAsyncWebhookResponse: { + /** Id */ + id: string + /** Status */ + status: string + /** Webhook Url */ + webhook_url: string + } + /** HTTPValidationError */ + BFLHTTPValidationError: { + /** Detail */ + detail?: components['schemas']['BFLValidationError'][] + } + /** FluxProExpandInputs */ + BFLFluxProExpandInputs: { + /** + * Image + * @description A Base64-encoded string representing the image you wish to expand. + */ + image: string + /** + * Top + * @description Number of pixels to expand at the top of the image + * @default 0 + */ + top: number + /** + * Bottom + * @description Number of pixels to expand at the bottom of the image + * @default 0 + */ + bottom: number + /** + * Left + * @description Number of pixels to expand on the left side of the image + * @default 0 + */ + left: number + /** + * Right + * @description Number of pixels to expand on the right side of the image + * @default 0 + */ + right: number + /** + * Prompt + * @description The description of the changes you want to make. This text guides the expansion process, allowing you to specify features, styles, or modifications for the expanded areas. + * @default + * @example ein fantastisches bild + */ + prompt: string + /** + * Steps + * @description Number of steps for the image generation process + * @default 50 + * @example 50 + */ + steps: number + /** + * Prompt Upsampling + * @description Whether to perform upsampling on the prompt. If active, automatically modifies the prompt for more creative generation + * @default false + */ + prompt_upsampling: boolean + /** + * Seed + * @description Optional seed for reproducibility + */ + seed?: number + /** + * Guidance + * @description Guidance strength for the image generation process + * @default 60 + */ + guidance: number + /** + * @description Output format for the generated image. Can be 'jpeg' or 'png'. + * @default jpeg + */ + output_format: components['schemas']['BFLOutputFormat'] + /** + * Safety Tolerance + * @description Tolerance level for input and output moderation. Between 0 and 6, 0 being most strict, 6 being least strict. + * @default 2 + * @example 2 + */ + safety_tolerance: number + /** + * Webhook Url + * @description URL to receive webhook notifications + */ + webhook_url?: string + /** + * Webhook Secret + * @description Optional secret for webhook signature verification + */ + webhook_secret?: string + } + /** CannyInputs */ + BFLCannyInputs: { + /** + * Prompt + * @description Text prompt for image generation + * @example ein fantastisches bild + */ + prompt: string + /** + * Control Image + * @description Base64 encoded image to use as control input if no preprocessed image is provided + */ + control_image?: string + /** + * Preprocessed Image + * @description Optional pre-processed image that will bypass the control preprocessing step + */ + preprocessed_image?: string + /** + * Canny Low Threshold + * @description Low threshold for Canny edge detection + * @default 50 + */ + canny_low_threshold: number + /** + * Canny High Threshold + * @description High threshold for Canny edge detection + * @default 200 + */ + canny_high_threshold: number + /** + * Prompt Upsampling + * @description Whether to perform upsampling on the prompt + * @default false + */ + prompt_upsampling: boolean + /** + * Seed + * @description Optional seed for reproducibility + * @example 42 + */ + seed?: number + /** + * Steps + * @description Number of steps for the image generation process + * @default 50 + */ + steps: number + /** + * @description Output format for the generated image. Can be 'jpeg' or 'png'. + * @default jpeg + */ + output_format: components['schemas']['BFLOutputFormat'] + /** + * Guidance + * @description Guidance strength for the image generation process + * @default 30 + */ + guidance: number + /** + * Safety Tolerance + * @description Tolerance level for input and output moderation. Between 0 and 6, 0 being most strict, 6 being least strict. + * @default 2 + */ + safety_tolerance: number + /** + * Webhook Url + * @description URL to receive webhook notifications + */ + webhook_url?: string + /** + * Webhook Secret + * @description Optional secret for webhook signature verification + */ + webhook_secret?: string + } + /** DepthInputs */ + BFLDepthInputs: { + /** + * Prompt + * @description Text prompt for image generation + * @example ein fantastisches bild + */ + prompt: string + /** + * Control Image + * @description Base64 encoded image to use as control input + */ + control_image?: string + /** + * Preprocessed Image + * @description Optional pre-processed image that will bypass the control preprocessing step + */ + preprocessed_image?: string + /** + * Prompt Upsampling + * @description Whether to perform upsampling on the prompt + * @default false + */ + prompt_upsampling: boolean + /** + * Seed + * @description Optional seed for reproducibility + * @example 42 + */ + seed?: number + /** + * Steps + * @description Number of steps for the image generation process + * @default 50 + */ + steps: number + /** + * @description Output format for the generated image. Can be 'jpeg' or 'png'. + * @default jpeg + */ + output_format: components['schemas']['BFLOutputFormat'] + /** + * Guidance + * @description Guidance strength for the image generation process + * @default 15 + */ + guidance: number + /** + * Safety Tolerance + * @description Tolerance level for input and output moderation. Between 0 and 6, 0 being most strict, 6 being least strict. + * @default 2 + */ + safety_tolerance: number + /** + * Webhook Url + * @description URL to receive webhook notifications + */ + webhook_url?: string + /** + * Webhook Secret + * @description Optional secret for webhook signature verification + */ + webhook_secret?: string + } + /** + * OutputFormat + * @enum {string} + */ + BFLOutputFormat: 'jpeg' | 'png' + /** ValidationError */ + BFLValidationError: { + /** Location */ + loc: (string | number)[] + /** Message */ + msg: string + /** Error Type */ + type: string + } + /** @description Parameters for the Recraft image generation proxy request. */ + RecraftImageGenerationRequest: { + /** @description The text prompt describing the image to generate */ + prompt: string + /** @description The model to use for generation (e.g., "recraftv3") */ + model: string + /** @description The style to apply to the generated image (e.g., "digital_illustration") */ + style?: string + /** @description The style ID to apply to the generated image (e.g., "123e4567-e89b-12d3-a456-426614174000"). If style_id is provided, style should not be provided. */ + style_id?: string + /** @description The size of the generated image (e.g., "1024x1024") */ + size: string + /** @description The controls for the generated image */ + controls?: { + /** @description Defines artistic tone of your image. At a simple level, the person looks straight at the camera in a static and clean style. Dynamic and eccentric levels introduce movement and creativity. */ + artistic_level?: number | null + /** @description An array of preferable colors */ + colors?: components['schemas']['RGBColor'][] + /** @description Use given color as a desired background color */ + background_color?: components['schemas']['RGBColor'] + /** @description Do not embed text layouts */ + no_text?: boolean + } + /** @description The number of images to generate */ + n: number + } + /** @description Response from the Recraft image generation API. */ + RecraftImageGenerationResponse: { + /** @description Unix timestamp when the generation was created */ + created: number + /** @description Number of credits used for the generation */ + credits: number + /** @description Array of generated image information */ + data: { + /** @description Unique identifier for the generated image */ + image_id?: string + /** @description URL to access the generated image */ + url?: string + }[] + } + RecraftImageFeatures: { + nsfw_score?: number + } + RecraftTextLayoutItem: { + bbox: number[][] + text: string + } + RecraftImageColor: { + rgb?: number[] + std?: number[] + weight?: number + } + /** @enum {string} */ + RecraftImageStyle: + | 'digital_illustration' + | 'icon' + | 'realistic_image' + | 'vector_illustration' + /** @enum {string} */ + RecraftImageSubStyle: + | '2d_art_poster' + | '3d' + | '80s' + | 'glow' + | 'grain' + | 'hand_drawn' + | 'infantile_sketch' + | 'kawaii' + | 'pixel_art' + | 'psychedelic' + | 'seamless' + | 'voxel' + | 'watercolor' + | 'broken_line' + | 'colored_outline' + | 'colored_shapes' + | 'colored_shapes_gradient' + | 'doodle_fill' + | 'doodle_offset_fill' + | 'offset_fill' + | 'outline-solid' + | 'outline_gradient' + | 'uneven_fill' + | '70s' + | 'cartoon' + | 'doodle_line_art' + | 'engraving' + | 'flat_2' + | 'kawaii' + | 'line_art' + | 'linocut' + | 'seamless' + | 'b_and_w' + | 'enterprise' + | 'hard_flash' + | 'hdr' + | 'motion_blur' + | 'natural_light' + | 'studio_portrait' + | 'line_circuit' + | '2d_art_poster_2' + | 'engraving_color' + | 'flat_air_art' + | 'hand_drawn_outline' + | 'handmade_3d' + | 'stickers_drawings' + | 'plastic' + | 'pictogram' + /** @enum {string} */ + RecraftTransformModel: + | 'refm1' + | 'recraft20b' + | 'recraftv2' + | 'recraftv3' + | 'flux1_1pro' + | 'flux1dev' + | 'imagen3' + | 'hidream_i1_dev' + /** @enum {string} */ + RecraftImageFormat: 'webp' | 'png' + /** @enum {string} */ + RecraftResponseFormat: 'url' | 'b64_json' + RecraftImage: { + b64_json?: string + features?: components['schemas']['RecraftImageFeatures'] + /** Format: uuid */ + image_id: string + revised_prompt?: string + url?: string + } + RecraftUserControls: { + artistic_level?: number + background_color?: components['schemas']['RecraftImageColor'] + colors?: components['schemas']['RecraftImageColor'][] + no_text?: boolean + } + RecraftTextLayout: components['schemas']['RecraftTextLayoutItem'][] + RecraftProcessImageRequest: { + /** Format: binary */ + image: string + image_format?: components['schemas']['RecraftImageFormat'] + response_format?: components['schemas']['RecraftResponseFormat'] + } + RecraftProcessImageResponse: { + created: number + credits: number + image: components['schemas']['RecraftImage'] + } + RecraftImageToImageRequest: { + block_nsfw?: boolean + calculate_features?: boolean + controls?: components['schemas']['RecraftUserControls'] + /** Format: binary */ + image: string + image_format?: components['schemas']['RecraftImageFormat'] + model?: components['schemas']['RecraftTransformModel'] + n?: number + negative_prompt?: string + prompt: string + response_format?: components['schemas']['RecraftResponseFormat'] + strength: number + style?: components['schemas']['RecraftImageStyle'] + /** Format: uuid */ + style_id?: string + substyle?: components['schemas']['RecraftImageSubStyle'] + text_layout?: components['schemas']['RecraftTextLayout'] + } + RecraftGenerateImageResponse: { + created: number + credits: number + data: components['schemas']['RecraftImage'][] + } + RecraftTransformImageWithMaskRequest: { + block_nsfw?: boolean + calculate_features?: boolean + /** Format: binary */ + image: string + image_format?: components['schemas']['RecraftImageFormat'] + /** Format: binary */ + mask: string + model?: components['schemas']['RecraftTransformModel'] + n?: number + negative_prompt?: string + prompt: string + response_format?: components['schemas']['RecraftResponseFormat'] + style?: components['schemas']['RecraftImageStyle'] + /** Format: uuid */ + style_id?: string + substyle?: components['schemas']['RecraftImageSubStyle'] + text_layout?: components['schemas']['RecraftTextLayout'] + } + KlingErrorResponse: { + /** @description - 1000: Authentication failed + * - 1001: Authorization is empty + * - 1002: Authorization is invalid + * - 1003: Authorization is not yet valid + * - 1004: Authorization has expired + * - 1100: Account exception + * - 1101: Account in arrears (postpaid scenario) + * - 1102: Resource pack depleted or expired (prepaid scenario) + * - 1103: Unauthorized access to requested resource + * - 1200: Invalid request parameters + * - 1201: Invalid parameters + * - 1202: Invalid request method + * - 1203: Requested resource does not exist + * - 1300: Trigger platform strategy + * - 1301: Trigger content security policy + * - 1302: API request too frequent + * - 1303: Concurrency/QPS exceeds limit + * - 1304: Trigger IP whitelist policy + * - 5000: Internal server error + * - 5001: Service temporarily unavailable + * - 5002: Server internal timeout + * */ + code: number + /** @description Human-readable error message */ + message: string + /** @description Request ID for tracking and troubleshooting */ + request_id: string + } + TripoTask: { + task_id: string + type: string + /** @enum {string} */ + status: + | 'queued' + | 'running' + | 'success' + | 'failed' + | 'cancelled' + | 'unknown' + | 'banned' + | 'expired' + input: Record + output: { + model?: string + base_model?: string + pbr_model?: string + rendered_image?: string + riggable?: boolean + /** @enum {string} */ + topology?: 'bip' | 'quad' + } + progress: number + create_time: number + } + TripoSuccessTask: { + /** @enum {integer} */ + code: 0 + data: { + /** @description used for getTask */ + task_id: string + } + } + TripoBalance: { + balance: number + frozen: number + } + TripoErrorResponse: { + /** @enum {integer} */ + code: 1001 | 2000 | 2001 | 2002 | 2003 | 2004 | 2006 | 2007 | 2008 | 2010 + message: string + suggestion: string + } + /** + * @description Standard success code for Tripo API responses. Typically 0 for success. + * @example 0 + */ + TripoResponseSuccessCode: number + /** + * @description The type of the Tripo task, specifically for text-to-model operations. + * @example text_to_model + * @enum {string} + */ + TripoTextToModel: 'text_to_model' + /** + * @description Version of the Tripo model. + * @example v2.5-20250123 + * @enum {string} + */ + TripoModelVersion: 'v2.5-20250123' | 'v2.0-20240919' | 'v1.4-20240625' + /** + * @description Style for the Tripo model generation. + * @example object:clay + * @enum {string} + */ + TripoModelStyle: + | 'person:person2cartoon' + | 'animal:venom' + | 'object:clay' + | 'object:steampunk' + | 'object:christmas' + | 'object:barbie' + | 'gold' + | 'ancient_bronze' + /** + * @description Task type for Tripo image-to-model generation. + * @example image_to_model + * @enum {string} + */ + TripoImageToModel: 'image_to_model' + /** + * @description Task type for Tripo multiview-to-model generation. + * @example multiview_to_model + * @enum {string} + */ + TripoMultiviewToModel: 'multiview_to_model' + /** + * @description Mode for multiview generation, specifying view orientation. + * @example LEFT + * @enum {string} + */ + TripoMultiviewMode: 'LEFT' | 'RIGHT' + /** @enum {string} */ + TripoTextureQuality: 'standard' | 'detailed' + /** @enum {string} */ + TripoTextureAlignment: 'original_image' | 'geometry' + /** + * @default default + * @enum {string} + */ + TripoOrientation: 'align_image' | 'default' + /** @enum {string} */ + TripoTypeTextureModel: 'texture_model' + /** @enum {string} */ + TripoTypeRefineModel: 'refine_model' + /** @enum {string} */ + TripoTypeAnimatePrerigcheck: 'animate_prerigcheck' + /** @enum {string} */ + TripoTypeAnimateRig: 'animate_rig' + /** @enum {string} */ + TripoStandardFormat: 'glb' | 'fbx' + /** @enum {string} */ + TripoTopology: 'bip' | 'quad' + /** @enum {string} */ + TripoSpec: 'mixamo' | 'tripo' + /** @enum {string} */ + TripoTypeAnimateRetarget: 'animate_retarget' + /** @enum {string} */ + TripoAnimation: + | 'preset:idle' + | 'preset:walk' + | 'preset:climb' + | 'preset:jump' + | 'preset:run' + | 'preset:slash' + | 'preset:shoot' + | 'preset:hurt' + | 'preset:fall' + | 'preset:turn' + /** @enum {string} */ + TripoTypeStylizeModel: 'stylize_model' + /** @enum {string} */ + TripoStylizeOptions: 'lego' | 'voxel' | 'voronoi' | 'minecraft' + /** @enum {string} */ + TripoTypeConvertModel: 'convert_model' + /** @enum {string} */ + TripoConvertFormat: 'GLTF' | 'USDZ' | 'FBX' | 'OBJ' | 'STL' | '3MF' + /** @enum {string} */ + TripoTextureFormat: + | 'BMP' + | 'DPX' + | 'HDR' + | 'JPEG' + | 'OPEN_EXR' + | 'PNG' + | 'TARGA' + | 'TIFF' + | 'WEBP' + /** + * @description The aspect ratio of the generation + * @default 16:9 + * @example 16:9 + * @enum {string} + */ + LumaAspectRatio: '1:1' | '16:9' | '9:16' | '4:3' | '3:4' | '21:9' | '9:21' + /** + * @description The keyframes of the generation + * @example { + * "frame0": { + * "type": "image", + * "url": "https://example.com/image.jpg" + * }, + * "frame1": { + * "type": "generation", + * "id": "123e4567-e89b-12d3-a456-426614174000" + * } + * } + */ + LumaKeyframes: { + frame0?: components['schemas']['LumaKeyframe'] + frame1?: components['schemas']['LumaKeyframe'] + } + /** + * @description The video model used for the generation + * @default ray-2 + * @example ray-2 + * @enum {string} + */ + LumaVideoModel: 'ray-2' | 'ray-flash-2' | 'ray-1-6' + LumaVideoModelOutputResolution: ('540p' | '720p' | '1080p' | '4k') | string + LumaVideoModelOutputDuration: ('5s' | '9s') | string + /** + * @description The image model used for the generation + * @default photon-1 + * @enum {string} + */ + LumaImageModel: 'photon-1' | 'photon-flash-1' + /** @description The image reference object */ + LumaImageRef: { + /** + * Format: uri + * @description The URL of the image reference + */ + url?: string + /** @description The weight of the image reference */ + weight?: number + } + /** @description The image identity object */ + LumaImageIdentity: { + /** @description The URLs of the image identity */ + images?: string[] + } + /** @description The modify image reference object */ + LumaModifyImageRef: { + /** + * Format: uri + * @description The URL of the image reference + */ + url?: string + /** @description The weight of the modify image reference */ + weight?: number + } + /** + * @description The generation reference object + * @example { + * "type": "generation", + * "id": "123e4567-e89b-12d3-a456-426614174003" + * } + */ + LumaGenerationReference: { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + type: 'generation' + /** + * Format: uuid + * @description The ID of the generation + */ + id: string + } + /** + * @description The image object + * @example { + * "type": "image", + * "url": "https://example.com/image.jpg" + * } + */ + LumaImageReference: { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + type: 'image' + /** + * Format: uri + * @description The URL of the image + */ + url: string + } + /** @description A keyframe can be either a Generation reference, an Image, or a Video */ + LumaKeyframe: + | components['schemas']['LumaGenerationReference'] + | components['schemas']['LumaImageReference'] + /** @enum {string} */ + LumaGenerationType: 'video' | 'image' + /** + * @description The state of the generation + * @example completed + * @enum {string} + */ + LumaState: 'queued' | 'dreaming' | 'completed' | 'failed' + /** @description The assets of the generation */ + LumaAssets: { + /** + * Format: uri + * @description The URL of the video + */ + video?: string + /** + * Format: uri + * @description The URL of the image + */ + image?: string + /** + * Format: uri + * @description The URL of the progress video + */ + progress_video?: string + } + /** @description The generation request object */ + LumaGenerationRequest: { + /** + * @default video + * @enum {string} + */ + generation_type: 'video' + /** @description The prompt of the generation */ + prompt: string + aspect_ratio: components['schemas']['LumaAspectRatio'] + /** @description Whether to loop the video */ + loop?: boolean + keyframes?: components['schemas']['LumaKeyframes'] + /** + * Format: uri + * @description The callback URL of the generation, a POST request with Generation object will be sent to the callback URL when the generation is dreaming, completed, or failed + */ + callback_url?: string + model: components['schemas']['LumaVideoModel'] + resolution: components['schemas']['LumaVideoModelOutputResolution'] + duration: components['schemas']['LumaVideoModelOutputDuration'] + } + /** @description The image generation request object */ + LumaImageGenerationRequest: { + /** + * @default image + * @enum {string} + */ + generation_type: 'image' + model?: components['schemas']['LumaImageModel'] + /** @description The prompt of the generation */ + prompt?: string + aspect_ratio?: components['schemas']['LumaAspectRatio'] + /** + * Format: uri + * @description The callback URL for the generation + */ + callback_url?: string + image_ref?: components['schemas']['LumaImageRef'][] + style_ref?: components['schemas']['LumaImageRef'][] + character_ref?: { + identity0?: components['schemas']['LumaImageIdentity'] + } + modify_image_ref?: components['schemas']['LumaModifyImageRef'] + } + /** @description The upscale generation request object */ + LumaUpscaleVideoGenerationRequest: { + /** + * @default upscale_video + * @enum {string} + */ + generation_type: 'upscale_video' + resolution?: components['schemas']['LumaVideoModelOutputResolution'] + /** + * Format: uri + * @description The callback URL for the upscale + */ + callback_url?: string + } + /** @description The audio generation request object */ + LumaAudioGenerationRequest: { + /** + * @default add_audio + * @enum {string} + */ + generation_type: 'add_audio' + /** @description The prompt of the audio */ + prompt?: string + /** @description The negative prompt of the audio */ + negative_prompt?: string + /** + * Format: uri + * @description The callback URL for the audio + */ + callback_url?: string + } + /** + * @description The error object + * @example { + * "detail": "Invalid API key is provided" + * } + */ + LumaError: { + /** @description The error message */ + detail?: string + } + /** + * @description The generation response object + * @example { + * "id": "123e4567-e89b-12d3-a456-426614174000", + * "state": "completed", + * "failure_reason": null, + * "created_at": "2023-06-01T12:00:00Z", + * "assets": { + * "video": "https://example.com/video.mp4" + * }, + * "model": "ray-2", + * "request": { + * "prompt": "A serene lake surrounded by mountains at sunset", + * "aspect_ratio": "16:9", + * "loop": true, + * "keyframes": { + * "frame0": { + * "type": "image", + * "url": "https://example.com/image.jpg" + * }, + * "frame1": { + * "type": "generation", + * "id": "123e4567-e89b-12d3-a456-426614174000" + * } + * } + * } + * } + */ + LumaGeneration: { + /** + * Format: uuid + * @description The ID of the generation + */ + id?: string + generation_type?: components['schemas']['LumaGenerationType'] + state?: components['schemas']['LumaState'] + /** @description The reason for the state of the generation */ + failure_reason?: string + /** + * Format: date-time + * @description The date and time when the generation was created + */ + created_at?: string + assets?: components['schemas']['LumaAssets'] + /** @description The model used for the generation */ + model?: string + /** @description The request of the generation */ + request?: + | components['schemas']['LumaGenerationRequest'] + | components['schemas']['LumaImageGenerationRequest'] + | components['schemas']['LumaUpscaleVideoGenerationRequest'] + | components['schemas']['LumaAudioGenerationRequest'] + } + PixverseTextVideoRequest: { + /** @enum {string} */ + aspect_ratio: '16:9' | '4:3' | '1:1' | '3:4' | '9:16' + /** @enum {integer} */ + duration: 5 | 8 + /** @enum {string} */ + model: 'v3.5' + /** @enum {string} */ + motion_mode?: 'normal' | 'fast' + negative_prompt?: string + prompt: string + /** @enum {string} */ + quality: '360p' | '540p' | '720p' | '1080p' + seed?: number + /** @enum {string} */ + style?: 'anime' | '3d_animation' | 'clay' | 'comic' | 'cyberpunk' + template_id?: number + water_mark?: boolean + } + PixverseVideoResponse: { + ErrCode?: number + ErrMsg?: string + Resp?: { + video_id?: number + } + } + PixverseImageUploadResponse: { + ErrCode?: number + ErrMsg?: string + Resp?: { + img_id?: number + } + } + PixverseImageVideoRequest: { + img_id: number + /** @enum {string} */ + model: 'v3.5' + prompt: string + /** @enum {integer} */ + duration: 5 | 8 + /** @enum {string} */ + quality: '360p' | '540p' | '720p' | '1080p' + /** @enum {string} */ + motion_mode?: 'normal' | 'fast' + seed?: number + /** @enum {string} */ + style?: 'anime' | '3d_animation' | 'clay' | 'comic' | 'cyberpunk' + template_id?: number + water_mark?: boolean + } + PixverseTransitionVideoRequest: { + first_frame_img: number + last_frame_img: number + /** @enum {string} */ + model: 'v3.5' + /** @enum {integer} */ + duration: 5 | 8 + /** @enum {string} */ + quality: '360p' | '540p' | '720p' | '1080p' + /** @enum {string} */ + motion_mode: 'normal' | 'fast' + seed: number + prompt: string + /** @enum {string} */ + style?: 'anime' | '3d_animation' | 'clay' | 'comic' | 'cyberpunk' + template_id?: number + water_mark?: boolean + } + PixverseVideoResultResponse: { + ErrCode?: number + ErrMsg?: string + Resp?: { + create_time?: string + id?: number + modify_time?: string + negative_prompt?: string + outputHeight?: number + outputWidth?: number + prompt?: string + resolution_ratio?: number + seed?: number + size?: number + /** + * @description Video generation status codes: + * * 1 - Generation successful + * * 5 - Generating + * * 6 - Deleted + * * 7 - Contents moderation failed + * * 8 - Generation failed + * + * @enum {integer} + */ + status?: 1 | 5 | 6 | 7 | 8 + style?: string + url?: string + } + } + Veo2GenVidRequest: { + instances?: { + /** @description Text description of the video */ + prompt: string + /** @description Optional image to guide video generation */ + image?: { + /** Format: byte */ + bytesBase64Encoded?: string + gcsUri?: string + mimeType?: string + } & (unknown | unknown) + }[] + parameters?: { + /** @example 16:9 */ + aspectRatio?: string + negativePrompt?: string + /** @enum {string} */ + personGeneration?: 'ALLOW' | 'BLOCK' + sampleCount?: number + /** Format: uint32 */ + seed?: number + /** @description Optional Cloud Storage URI to upload the video */ + storageUri?: string + durationSeconds?: number + enhancePrompt?: boolean + } + } + Veo2GenVidResponse: { + /** + * @description Operation resource name + * @example projects/PROJECT_ID/locations/us-central1/publishers/google/models/MODEL_ID/operations/a1b07c8e-7b5a-4aba-bb34-3e1ccb8afcc8 + */ + name: string + } + Veo2GenVidPollRequest: { + /** + * @description Full operation name (from predict response) + * @example projects/PROJECT_ID/locations/us-central1/publishers/google/models/MODEL_ID/operations/OPERATION_ID + */ + operationName: string + } + Veo2GenVidPollResponse: { + name?: string + done?: boolean + /** @description The actual prediction response if done is true */ + response?: { + /** @example type.googleapis.com/cloud.ai.large_models.vision.GenerateVideoResponse */ + '@type'?: string + /** @description Count of media filtered by responsible AI policies */ + raiMediaFilteredCount?: number + /** @description Reasons why media was filtered by responsible AI policies */ + raiMediaFilteredReasons?: string[] + videos?: { + /** @description Cloud Storage URI of the video */ + gcsUri?: string + /** @description Base64-encoded video content */ + bytesBase64Encoded?: string + /** @description Video MIME type */ + mimeType?: string + }[] + } + /** @description Error details if operation failed */ + error?: { + /** @description Error code */ + code?: number + /** @description Error message */ + message?: string + } + } + VeoGenVidRequest: { + instances?: { + /** @description Text description of the video */ + prompt: string + /** @description Optional image to guide video generation */ + image?: { + /** Format: byte */ + bytesBase64Encoded?: string + gcsUri?: string + mimeType?: string + } & (unknown | unknown) + }[] + parameters?: { + /** @example 16:9 */ + aspectRatio?: string + negativePrompt?: string + /** @enum {string} */ + personGeneration?: 'ALLOW' | 'BLOCK' + sampleCount?: number + /** Format: uint32 */ + seed?: number + /** @description Optional Cloud Storage URI to upload the video */ + storageUri?: string + durationSeconds?: number + enhancePrompt?: boolean + } + } + VeoGenVidResponse: { + /** + * @description Operation resource name + * @example projects/PROJECT_ID/locations/us-central1/publishers/google/models/MODEL_ID/operations/a1b07c8e-7b5a-4aba-bb34-3e1ccb8afcc8 + */ + name: string + } + VeoGenVidPollRequest: { + /** + * @description Full operation name (from predict response) + * @example projects/PROJECT_ID/locations/us-central1/publishers/google/models/MODEL_ID/operations/OPERATION_ID + */ + operationName: string + } + VeoGenVidPollResponse: { + name?: string + done?: boolean + /** @description The actual prediction response if done is true */ + response?: { + /** @example type.googleapis.com/cloud.ai.large_models.vision.GenerateVideoResponse */ + '@type'?: string + /** @description Count of media filtered by responsible AI policies */ + raiMediaFilteredCount?: number + /** @description Reasons why media was filtered by responsible AI policies */ + raiMediaFilteredReasons?: string[] + videos?: { + /** @description Cloud Storage URI of the video */ + gcsUri?: string + /** @description Base64-encoded video content */ + bytesBase64Encoded?: string + /** @description Video MIME type */ + mimeType?: string + }[] + } + /** @description Error details if operation failed */ + error?: { + /** @description Error code */ + code?: number + /** @description Error message */ + message?: string + } + } + RunwayImageToVideoRequest: { + promptImage: components['schemas']['RunwayPromptImageObject'] + /** + * Format: int64 + * @description Random seed for generation + */ + seed: number + /** @description Model to use for generation */ + model: components['schemas']['RunwayModelEnum'] + /** @description Text prompt for the generation */ + promptText?: string + /** @description The number of seconds of duration for the output video. */ + duration: components['schemas']['RunwayDurationEnum'] + /** @description The resolution (aspect ratio) of the output video. Allowable values depend on the selected model. 1280:768 and 768:1280 are only supported for gen3a_turbo. */ + ratio: components['schemas']['RunwayAspectRatioEnum'] + } + RunwayImageToVideoResponse: { + /** @description Task ID */ + id?: string + } + RunwayTextToImageResponse: { + /** @description Task ID */ + id?: string + } + RunwayTaskStatusResponse: { + /** @description Task ID */ + id: string + /** @description Task status */ + status: components['schemas']['RunwayTaskStatusEnum'] + /** + * Format: date-time + * @description Task creation timestamp + */ + createdAt: string + /** @description Array of output video URLs */ + output?: string[] + /** + * Format: float + * @description Float value between 0 and 1 representing the progress of the task. Only available if status is RUNNING. + */ + progress?: number + } + /** + * @description Possible statuses for a Runway task. + * @enum {string} + */ + RunwayTaskStatusEnum: + | 'SUCCEEDED' + | 'RUNNING' + | 'FAILED' + | 'PENDING' + | 'CANCELLED' + | 'THROTTLED' + /** + * @description Available Runway models for generation. + * @enum {string} + */ + RunwayModelEnum: 'gen4_turbo' | 'gen3a_turbo' + /** @description Represents an image with its position in the video sequence. */ + RunwayPromptImageDetailedObject: { + /** @description A HTTPS URL or data URI containing an encoded image. */ + uri: string + /** + * @description The position of the image in the output video. 'last' is currently supported for gen3a_turbo only. + * @enum {string} + */ + position: 'first' | 'last' + } + /** @enum {integer} */ + RunwayDurationEnum: 5 | 10 + /** @enum {string} */ + RunwayAspectRatioEnum: + | '1280:720' + | '720:1280' + | '1104:832' + | '832:1104' + | '960:960' + | '1584:672' + | '1280:768' + | '768:1280' + /** @enum {string} */ + RunwayTextToImageAspectRatioEnum: + | '1920:1080' + | '1080:1920' + | '1024:1024' + | '1360:768' + | '1080:1080' + | '1168:880' + | '1440:1080' + | '1080:1440' + | '1808:768' + | '2112:912' + /** @description Image(s) to use for the video generation. Can be a single URI or an array of image objects with positions. */ + RunwayPromptImageObject: + | string + | components['schemas']['RunwayPromptImageDetailedObject'][] + OpenAIImageGenerationResponse: { + data?: { + /** @description Base64 encoded image data */ + b64_json?: string + /** @description URL of the image */ + url?: string + /** @description Revised prompt */ + revised_prompt?: string + }[] + usage?: { + input_tokens?: number + input_tokens_details?: { + text_tokens?: number + image_tokens?: number + } + output_tokens?: number + total_tokens?: number + } + } + OpenAIImageGenerationRequest: { + /** + * @description The model to use for image generation + * @example dall-e-3 + */ + model?: string + /** + * @description A text description of the desired image + * @example Draw a rocket in front of a blackhole in deep space + */ + prompt: string + /** + * @description The number of images to generate (1-10). Only 1 supported for dall-e-3. + * @example 1 + */ + n?: number + /** + * @description The quality of the generated image + * @example high + * @enum {string} + */ + quality?: 'low' | 'medium' | 'high' | 'standard' | 'hd' + /** + * @description Size of the image (e.g., 1024x1024, 1536x1024, auto) + * @example 1024x1536 + */ + size?: string + /** + * @description Format of the output image + * @example png + * @enum {string} + */ + output_format?: 'png' | 'webp' | 'jpeg' + /** + * @description Compression level for JPEG or WebP (0-100) + * @example 100 + */ + output_compression?: number + /** + * @description Content moderation setting + * @example auto + * @enum {string} + */ + moderation?: 'low' | 'auto' + /** + * @description Background transparency + * @example opaque + * @enum {string} + */ + background?: 'transparent' | 'opaque' + /** + * @description Response format of image data + * @example b64_json + * @enum {string} + */ + response_format?: 'url' | 'b64_json' + /** + * @description Style of the image (only for dall-e-3) + * @example vivid + * @enum {string} + */ + style?: 'vivid' | 'natural' + /** + * @description A unique identifier for end-user monitoring + * @example user-1234 + */ + user?: string + } + OpenAIImageEditRequest: { + /** + * @description The model to use for image editing + * @example gpt-image-1 + */ + model: string + /** + * @description A text description of the desired edit + * @example Give the rocketship rainbow coloring + */ + prompt: string + /** + * @description The number of images to generate + * @example 1 + */ + n?: number + /** + * @description The quality of the edited image + * @example low + */ + quality?: string + /** + * @description Size of the output image + * @example 1024x1024 + */ + size?: string + /** + * @description Format of the output image + * @example png + * @enum {string} + */ + output_format?: 'png' | 'webp' | 'jpeg' + /** + * @description Compression level for JPEG or WebP (0-100) + * @example 100 + */ + output_compression?: number + /** + * @description Content moderation setting + * @example auto + * @enum {string} + */ + moderation?: 'low' | 'auto' + /** + * @description Background transparency + * @example opaque + */ + background?: string + /** + * @description A unique identifier for end-user monitoring + * @example user-1234 + */ + user?: string + } + CustomerStorageResourceResponse: { + /** @description The signed URL to use for downloading the file from the specified path */ + download_url?: string + /** @description The signed URL to use for uploading the file to the specified path */ + upload_url?: string + /** + * Format: date-time + * @description When the signed URL will expire + */ + expires_at?: string + /** @description Whether an existing file with the same hash was found */ + existing_file?: boolean + } + /** @enum {string} */ + Pikaffect: + | 'Cake-ify' + | 'Crumble' + | 'Crush' + | 'Decapitate' + | 'Deflate' + | 'Dissolve' + | 'Explode' + | 'Eye-pop' + | 'Inflate' + | 'Levitate' + | 'Melt' + | 'Peel' + | 'Poke' + | 'Squish' + | 'Ta-da' + | 'Tear' + /** Body_generate_pikaffects_generate_pikaffects_post */ + PikaBody_generate_pikaffects_generate_pikaffects_post: { + /** + * Image + * Format: binary + */ + image?: string + /** Pikaffect */ + pikaffect?: components['schemas']['Pikaffect'] + /** Prompttext */ + promptText?: string + /** Negativeprompt */ + negativePrompt?: string + /** Seed */ + seed?: number + } + /** GenerateResponse */ + PikaGenerateResponse: { + /** Video Id */ + video_id: string + } + /** HTTPValidationError */ + PikaHTTPValidationError: { + /** Detail */ + detail?: components['schemas']['PikaValidationError'][] + } + /** Body_generate_pikadditions_generate_pikadditions_post */ + PikaBody_generate_pikadditions_generate_pikadditions_post: { + /** + * Video + * Format: binary + */ + video?: string + /** + * Image + * Format: binary + */ + image?: string + /** Prompttext */ + promptText?: string + /** Negativeprompt */ + negativePrompt?: string + /** Seed */ + seed?: number + } + /** Body_generate_pikaswaps_generate_pikaswaps_post */ + PikaBody_generate_pikaswaps_generate_pikaswaps_post: { + /** + * Video + * Format: binary + */ + video?: string + /** Image */ + image?: string + /** Prompttext */ + promptText?: string + /** + * Modifyregionmask + * @description A mask image that specifies the region to modify, where the mask is white and the background is black + */ + modifyRegionMask?: string + /** + * Modifyregionroi + * @description Plaintext description of the object / region to modify + */ + modifyRegionRoi?: string + /** Negativeprompt */ + negativePrompt?: string + /** Seed */ + seed?: number + } + /** Body_generate_2_2_t2v_generate_2_2_t2v_post */ + PikaBody_generate_2_2_t2v_generate_2_2_t2v_post: { + /** Prompttext */ + promptText: string + /** Negativeprompt */ + negativePrompt?: string | null + /** Seed */ + seed?: number | null + /** Resolution */ + resolution?: components['schemas']['PikaResolutionEnum'] + /** Duration */ + duration?: components['schemas']['PikaDurationEnum'] + /** + * Aspectratio + * Format: float + * @description Aspect ratio (width / height) + * @default 1.7777777777777777 + */ + aspectRatio: number + } + /** Body_generate_2_2_i2v_generate_2_2_i2v_post */ + PikaBody_generate_2_2_i2v_generate_2_2_i2v_post: { + /** + * Image + * Format: binary + */ + image?: string | null + /** Prompttext */ + promptText?: string | null + /** Negativeprompt */ + negativePrompt?: string | null + /** Seed */ + seed?: number | null + /** Resolution */ + resolution?: components['schemas']['PikaResolutionEnum'] + /** Duration */ + duration?: components['schemas']['PikaDurationEnum'] + } + /** Body_generate_2_2_c2v_generate_2_2_pikascenes_post */ + PikaBody_generate_2_2_c2v_generate_2_2_pikascenes_post: { + /** Images */ + images?: string[] + /** + * Ingredientsmode + * @enum {string} + */ + ingredientsMode: 'creative' | 'precise' + /** Prompttext */ + promptText?: string + /** Negativeprompt */ + negativePrompt?: string + /** Seed */ + seed?: number + /** + * Resolution + * @default 1080p + */ + resolution: string + /** + * Duration + * @default 5 + */ + duration: number + /** + * Aspectratio + * @description Aspect ratio (width / height) + */ + aspectRatio?: number + } + /** Body_generate_2_2_keyframe_generate_2_2_pikaframes_post */ + PikaBody_generate_2_2_keyframe_generate_2_2_pikaframes_post: { + /** + * Keyframes + * @description Array of keyframe images + */ + keyFrames?: string[] + /** Prompttext */ + promptText: string + /** Negativeprompt */ + negativePrompt?: string + /** Seed */ + seed?: number + /** Resolution */ + resolution?: components['schemas']['PikaResolutionEnum'] + /** Duration */ + duration?: number + } + /** VideoResponse */ + PikaVideoResponse: { + /** Id */ + id: string + /** + * Status + * @description The status of the video + */ + status: components['schemas']['PikaStatusEnum'] + /** + * Url + * @default null + */ + url: string | null + /** + * Progress + * @default null + */ + progress: number | null + } + /** @enum {string} */ + PikaStatusEnum: 'queued' | 'started' | 'finished' + /** ValidationError */ + PikaValidationError: { + /** Location */ + loc: (string | number)[] + /** Message */ + msg: string + /** Error Type */ + type: string + } + /** + * @default 1080p + * @enum {string} + */ + PikaResolutionEnum: '1080p' | '720p' + /** + * @default 5 + * @enum {integer} + */ + PikaDurationEnum: 5 | 10 + /** + * @description RGB color values + * @example { + * "rgb": [ + * 255, + * 0, + * 0 + * ] + * } + */ + RGBColor: { + rgb: number[] + } + /** @example { + * "id": "2a1b2d4eafe2bc6ab4cd4d5c6133f513", + * "name": "internal_error", + * "errors": [ + * "An unexpected server error has occurred, please try again later." + * ] + * } */ + StabilityError: { + /** + * @description A unique identifier associated with this error. Please include this in any [support tickets](https://kb.stability.ai/knowledge-base/kb-tickets/new) you file, as it will greatly assist us in diagnosing the root cause of the problem. + * + * @example a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4 + */ + id: string + /** + * @description Short-hand name for an error, useful for discriminating between errors with the same status code. + * @example bad_request + */ + name: string + /** + * @description One or more error messages indicating what went wrong. + * @example [ + * { + * "some-field": "is required" + * } + * ] + */ + errors: string[] + } + /** + * @description The name of your application, used to help us communicate app-specific debugging or moderation issues to you. + * @example my-awesome-app + */ + StabilityStabilityClientID: string + /** + * @description A unique identifier for your end user. Used to help us communicate user-specific debugging or moderation issues to you. Feel free to obfuscate this value to protect user privacy. + * @example DiscordUser#9999 + */ + StabilityStabilityClientUserID: string + /** + * @description The version of your application, used to help us communicate version-specific debugging or moderation issues to you. + * @example 1.2.1 + */ + StabilityStabilityClientVersion: string + /** + * @description Your request was flagged by our content moderation system. + * @example { + * "id": "ed14db44362126aab3cbd25cca51ffe3", + * "name": "content_moderation", + * "errors": [ + * "Your request was flagged by our content moderation system, as a result your request was denied and you were not charged." + * ] + * } + */ + StabilityContentModerationResponse: { + /** + * @description A unique identifier associated with this error. Please include this in any [support tickets](https://kb.stability.ai/knowledge-base/kb-tickets/new) you file, as it will greatly assist us in diagnosing the root cause of the problem. + * @example a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4 + */ + id: string + /** + * @description Our content moderation system has flagged some part of your request and subsequently denied it. You were not charged for this request. While this may at times be frustrating, it is necessary to maintain the integrity of our platform and ensure a safe experience for all users. If you would like to provide feedback, please use the [Support Form](https://kb.stability.ai/knowledge-base/kb-tickets/new). + * @enum {string} + */ + name: 'content_moderation' + /** + * @description One or more error messages indicating what went wrong. + * @example [ + * "some-field: is required" + * ] + */ + errors: string[] + } + ImagenGenerateImageRequest: { + instances: components['schemas']['ImagenImageGenerationInstance'][] + parameters: components['schemas']['ImagenImageGenerationParameters'] + } + ImagenGenerateImageResponse: { + predictions?: components['schemas']['ImagenImagePrediction'][] + } + ImagenImageGenerationInstance: { + /** @description Text prompt for image generation */ + prompt: string + } + ImagenImageGenerationParameters: { + sampleCount?: number + /** Format: uint32 */ + seed?: number + addWatermark?: boolean + /** @enum {string} */ + aspectRatio?: '1:1' | '9:16' | '16:9' | '3:4' | '4:3' + enhancePrompt?: boolean + includeRaiReason?: boolean + includeSafetyAttributes?: boolean + outputOptions?: components['schemas']['ImagenOutputOptions'] + /** @enum {string} */ + personGeneration?: 'dont_allow' | 'allow_adult' | 'allow_all' + /** @enum {string} */ + safetySetting?: 'block_most' | 'block_some' | 'block_few' | 'block_fewest' + /** Format: uri */ + storageUri?: string + } + ImagenImagePrediction: { + /** @description MIME type of the generated image */ + mimeType?: string + /** @description Enhanced or rewritten prompt used to generate this image */ + prompt?: string + /** + * Format: byte + * @description Base64-encoded image content + */ + bytesBase64Encoded?: string + } + ImagenOutputOptions: { + /** @enum {string} */ + mimeType?: 'image/png' | 'image/jpeg' + compressionQuality?: number + } + /** + * @description The rendering speed setting that controls the trade-off between generation speed and quality + * @default BALANCED + * @enum {string} + */ + RenderingSpeed: 'BALANCED' | 'TURBO' | 'QUALITY' + /** + * @description Controls the likelihood of creating additional details not heavily conditioned by the init image. + * @default 0.35 + */ + StabilityCreativity: number + /** + * @description The `id` of a generation, typically used for async generations, that can be used to check the status of the generation or retrieve the result. + * @example a6dc6c6e20acda010fe14d71f180658f2896ed9b4ec25aa99a6ff06c796987c4 + */ + StabilityGenerationID: string + StabilityImageGenerationSD3_Request: { + /** @description What you wish to see in the output image. A strong, descriptive prompt that clearly defines + * elements, colors, and subjects will lead to better results. */ + prompt: string + /** + * GenerationMode + * @description Controls whether this is a text-to-image or image-to-image generation, which affects which parameters are required: + * - **text-to-image** requires only the `prompt` parameter + * - **image-to-image** requires the `prompt`, `image`, and `strength` parameters + * @default text-to-image + * @enum {string} + */ + mode: 'text-to-image' | 'image-to-image' + /** + * Format: binary + * @description The image to use as the starting point for the generation. + * + * Supported formats: + * + * + * + * - jpeg + * - png + * - webp + * + * Supported dimensions: + * + * + * + * - Every side must be at least 64 pixels + * + * > **Important:** This parameter is only valid for **image-to-image** requests. + */ + image?: string + /** @description Sometimes referred to as _denoising_, this parameter controls how much influence the + * `image` parameter has on the generated image. A value of 0 would yield an image that + * is identical to the input. A value of 1 would be as if you passed in no image at all. + * + * > **Important:** This parameter is only valid for **image-to-image** requests. */ + strength?: number + /** + * @description Controls the aspect ratio of the generated image. Defaults to 1:1. + * + * > **Important:** This parameter is only valid for **text-to-image** requests. + * @default 1:1 + * @enum {string} + */ + aspect_ratio: + | '21:9' + | '16:9' + | '3:2' + | '5:4' + | '1:1' + | '4:5' + | '2:3' + | '9:16' + | '9:21' + /** + * @description The model to use for generation. + * + * - `sd3.5-large` requires 6.5 credits per generation + * - `sd3.5-large-turbo` requires 4 credits per generation + * - `sd3.5-medium` requires 3.5 credits per generation + * - As of the April 17, 2025, `sd3-large`, `sd3-large-turbo` and `sd3-medium` + * + * + * + * are re-routed to their `sd3.5-[model version]` equivalent, at the same price. + * @default sd3.5-large + * @enum {string} + */ + model: 'sd3.5-large' | 'sd3.5-large-turbo' | 'sd3.5-medium' + /** + * @description A specific value that is used to guide the 'randomness' of the generation. (Omit this parameter or pass `0` to use a random seed.) + * @default 0 + */ + seed: number + /** + * @description Dictates the `content-type` of the generated image. + * @default png + * @enum {string} + */ + output_format: 'png' | 'jpeg' + /** + * @description Guides the image model towards a particular style. + * @enum {string} + */ + style_preset?: + | 'enhance' + | 'anime' + | 'photographic' + | 'digital-art' + | 'comic-book' + | 'fantasy-art' + | 'line-art' + | 'analog-film' + | 'neon-punk' + | 'isometric' + | 'low-poly' + | 'origami' + | 'modeling-compound' + | 'cinematic' + | '3d-model' + | 'pixel-art' + | 'tile-texture' + /** @description Keywords of what you **do not** wish to see in the output image. + * This is an advanced feature. */ + negative_prompt?: string + /** @description How strictly the diffusion process adheres to the prompt text (higher values keep your image closer to your prompt). The _Large_ and _Medium_ models use a default of `4`. The _Turbo_ model uses a default of `1`. */ + cfg_scale?: number + } + StabilityImageGenrationSD3_Response_200: { + /** + * @description The generated image, encoded to base64. + * @example AAAAIGZ0eXBpc29tAAACAGlzb21pc28yYXZjMW1... + */ + image: string + /** + * @description The seed used as random noise for this generation. + * @default 0 + * @example 343940597 + */ + seed: number + /** + * @description The reason the generation finished. + * + * - `SUCCESS` = successful generation. + * - `CONTENT_FILTERED` = successful generation, however the output violated our content moderation + * policy and has been blurred as a result. + * @example SUCCESS + * @enum {string} + */ + finish_reason: 'SUCCESS' | 'CONTENT_FILTERED' + } + StabilityImageGenrationSD3_Response_400: { + /** + * @description A unique identifier associated with this error. Please include this in any [support tickets](https://kb.stability.ai/knowledge-base/kb-tickets/new) + * you file, as it will greatly assist us in diagnosing the root cause of the problem. + * @example a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4 + */ + id: string + /** + * @description Short-hand name for an error, useful for discriminating between errors with the same status code. + * @example bad_request + */ + name: string + /** + * @description One or more error messages indicating what went wrong. + * @example [ + * "some-field: is required" + * ] + */ + errors: string[] + } + /** @example { + * "id": "4212a4b66fbe1cedca4bf2133d35dca5", + * "name": "payload_too_large", + * "errors": [ + * "body: payloads cannot be larger than 10MiB in size" + * ] + * } */ + StabilityImageGenrationSD3_Response_413: { + /** + * @description A unique identifier associated with this error. Please include this in any [support tickets](https://kb.stability.ai/knowledge-base/kb-tickets/new) + * you file, as it will greatly assist us in diagnosing the root cause of the problem. + * @example a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4 + */ + id: string + /** + * @description Short-hand name for an error, useful for discriminating between errors with the same status code. + * @example bad_request + */ + name: string + /** + * @description One or more error messages indicating what went wrong. + * @example [ + * "some-field: is required" + * ] + */ + errors: string[] + } + StabilityImageGenrationSD3_Response_422: { + /** + * @description A unique identifier associated with this error. Please include this in any [support tickets](https://kb.stability.ai/knowledge-base/kb-tickets/new) + * you file, as it will greatly assist us in diagnosing the root cause of the problem. + * @example a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4 + */ + id: string + /** + * @description Short-hand name for an error, useful for discriminating between errors with the same status code. + * @example bad_request + */ + name: string + /** + * @description One or more error messages indicating what went wrong. + * @example [ + * "some-field: is required" + * ] + */ + errors: string[] + } + /** @example { + * "id": "rate_limit_exceeded", + * "name": "rate_limit_exceeded", + * "errors": [ + * "You have exceeded the rate limit of 150 requests within a 10 second period, and have been timed out for 60 seconds." + * ] + * } */ + StabilityImageGenrationSD3_Response_429: { + /** + * @description A unique identifier associated with this error. Please include this in any [support tickets](https://kb.stability.ai/knowledge-base/kb-tickets/new) + * you file, as it will greatly assist us in diagnosing the root cause of the problem. + * @example a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4 + */ + id: string + /** + * @description Short-hand name for an error, useful for discriminating between errors with the same status code. + * @example bad_request + */ + name: string + /** + * @description One or more error messages indicating what went wrong. + * @example [ + * "some-field: is required" + * ] + */ + errors: string[] + } + /** @example { + * "id": "2a1b2d4eafe2bc6ab4cd4d5c6133f513", + * "name": "internal_error", + * "errors": [ + * "An unexpected server error has occurred, please try again later." + * ] + * } */ + StabilityImageGenrationSD3_Response_500: { + /** + * @description A unique identifier associated with this error. Please include this in any [support tickets](https://kb.stability.ai/knowledge-base/kb-tickets/new) + * you file, as it will greatly assist us in diagnosing the root cause of the problem. + * @example a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4 + */ + id: string + /** + * @description Short-hand name for an error, useful for discriminating between errors with the same status code. + * @example bad_request + */ + name: string + /** + * @description One or more error messages indicating what went wrong. + * @example [ + * "some-field: is required" + * ] + */ + errors: string[] + } + StabilityImageGenrationUpscaleConservative_Request: { + /** + * Format: binary + * @description The image you wish to upscale. + * + * Supported Formats: + * - jpeg + * - png + * - webp + * + * Validation Rules: + * - Every side must be at least 64 pixels + * - Total pixel count must be between 4,096 and 9,437,184 pixels + * - The aspect ratio must be between 1:2.5 and 2.5:1 + * @example ./some/image.png + */ + image: string + /** @description What you wish to see in the output image. A strong, descriptive prompt that clearly defines + * elements, colors, and subjects will lead to better results. + * + * To control the weight of a given word use the format `(word:weight)`, + * where `word` is the word you'd like to control the weight of and `weight` + * is a value between 0 and 1. For example: `The sky was a crisp (blue:0.3) and (green:0.8)` + * would convey a sky that was blue and green, but more green than blue. */ + prompt: string + /** @description A blurb of text describing what you **do not** wish to see in the output image. + * This is an advanced feature. */ + negative_prompt?: string + /** + * @description A specific value that is used to guide the 'randomness' of the generation. (Omit this parameter or pass `0` to use a random seed.) + * @default 0 + */ + seed: number + /** + * @description Dictates the `content-type` of the generated image. + * @default png + * @enum {string} + */ + output_format: 'jpeg' | 'png' | 'webp' + creativity?: components['schemas']['StabilityCreativity'] + } + StabilityImageGenrationUpscaleConservative_Response_200: { + /** + * @description The generated image, encoded to base64. + * @example AAAAIGZ0eXBpc29tAAACAGlzb21pc28yYXZjMW1... + */ + image: string + /** + * @description The seed used as random noise for this generation. + * @default 0 + * @example 343940597 + */ + seed: number + /** + * @description The reason the generation finished. + * + * - `SUCCESS` = successful generation. + * - `CONTENT_FILTERED` = successful generation, however the output violated our content moderation + * policy and has been blurred as a result. + * @example SUCCESS + * @enum {string} + */ + finish_reason: 'SUCCESS' | 'CONTENT_FILTERED' + } + StabilityImageGenrationUpscaleConservative_Response_400: { + /** + * @description A unique identifier associated with this error. Please include this in any [support tickets](https://kb.stability.ai/knowledge-base/kb-tickets/new) + * you file, as it will greatly assist us in diagnosing the root cause of the problem. + * @example a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4 + */ + id: string + /** + * @description Short-hand name for an error, useful for discriminating between errors with the same status code. + * @example bad_request + */ + name: string + /** + * @description One or more error messages indicating what went wrong. + * @example [ + * "some-field: is required" + * ] + */ + errors: string[] + } + /** @example { + * "id": "4212a4b66fbe1cedca4bf2133d35dca5", + * "name": "payload_too_large", + * "errors": [ + * "body: payloads cannot be larger than 10MiB in size" + * ] + * } */ + StabilityImageGenrationUpscaleConservative_Response_413: { + /** + * @description A unique identifier associated with this error. Please include this in any [support tickets](https://kb.stability.ai/knowledge-base/kb-tickets/new) + * you file, as it will greatly assist us in diagnosing the root cause of the problem. + * @example a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4 + */ + id: string + /** + * @description Short-hand name for an error, useful for discriminating between errors with the same status code. + * @example bad_request + */ + name: string + /** + * @description One or more error messages indicating what went wrong. + * @example [ + * "some-field: is required" + * ] + */ + errors: string[] + } + StabilityImageGenrationUpscaleConservative_Response_422: { + /** + * @description A unique identifier associated with this error. Please include this in any [support tickets](https://kb.stability.ai/knowledge-base/kb-tickets/new) + * you file, as it will greatly assist us in diagnosing the root cause of the problem. + * @example a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4 + */ + id: string + /** + * @description Short-hand name for an error, useful for discriminating between errors with the same status code. + * @example bad_request + */ + name: string + /** + * @description One or more error messages indicating what went wrong. + * @example [ + * "some-field: is required" + * ] + */ + errors: string[] + } + /** @example { + * "id": "rate_limit_exceeded", + * "name": "rate_limit_exceeded", + * "errors": [ + * "You have exceeded the rate limit of 150 requests within a 10 second period, and have been timed out for 60 seconds." + * ] + * } */ + StabilityImageGenrationUpscaleConservative_Response_429: { + /** + * @description A unique identifier associated with this error. Please include this in any [support tickets](https://kb.stability.ai/knowledge-base/kb-tickets/new) + * you file, as it will greatly assist us in diagnosing the root cause of the problem. + * @example a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4 + */ + id: string + /** + * @description Short-hand name for an error, useful for discriminating between errors with the same status code. + * @example bad_request + */ + name: string + /** + * @description One or more error messages indicating what went wrong. + * @example [ + * "some-field: is required" + * ] + */ + errors: string[] + } + /** @example { + * "id": "2a1b2d4eafe2bc6ab4cd4d5c6133f513", + * "name": "internal_error", + * "errors": [ + * "An unexpected server error has occurred, please try again later." + * ] + * } */ + StabilityImageGenrationUpscaleConservative_Response_500: { + /** + * @description A unique identifier associated with this error. Please include this in any [support tickets](https://kb.stability.ai/knowledge-base/kb-tickets/new) + * you file, as it will greatly assist us in diagnosing the root cause of the problem. + * @example a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4 + */ + id: string + /** + * @description Short-hand name for an error, useful for discriminating between errors with the same status code. + * @example bad_request + */ + name: string + /** + * @description One or more error messages indicating what went wrong. + * @example [ + * "some-field: is required" + * ] + */ + errors: string[] + } + StabilityImageGenrationUpscaleCreative_Request: { + /** + * Format: binary + * @description The image you wish to upscale. + * + * Supported Formats: + * - jpeg + * - png + * - webp + * + * Validation Rules: + * - Every side must be at least 64 pixels + * - Total pixel count must be between 4,096 and 1,048,576 pixels + * @example ./some/image.png + */ + image: string + /** @description What you wish to see in the output image. A strong, descriptive prompt that clearly defines + * elements, colors, and subjects will lead to better results. + * + * To control the weight of a given word use the format `(word:weight)`, + * where `word` is the word you'd like to control the weight of and `weight` + * is a value between 0 and 1. For example: `The sky was a crisp (blue:0.3) and (green:0.8)` + * would convey a sky that was blue and green, but more green than blue. */ + prompt: string + /** @description A blurb of text describing what you **do not** wish to see in the output image. + * This is an advanced feature. */ + negative_prompt?: string + /** + * @description Dictates the `content-type` of the generated image. + * @default png + * @enum {string} + */ + output_format: 'jpeg' | 'png' | 'webp' + /** + * @description A specific value that is used to guide the 'randomness' of the generation. (Omit this parameter or pass `0` to use a random seed.) + * @default 0 + */ + seed: number + /** + * @description Indicates how creative the model should be when upscaling an image. + * Higher values will result in more details being added to the image during upscaling. + * @default 0.3 + */ + creativity: number + /** + * @description Guides the image model towards a particular style. + * @enum {string} + */ + style_preset?: + | 'enhance' + | 'anime' + | 'photographic' + | 'digital-art' + | 'comic-book' + | 'fantasy-art' + | 'line-art' + | 'analog-film' + | 'neon-punk' + | 'isometric' + | 'low-poly' + | 'origami' + | 'modeling-compound' + | 'cinematic' + | '3d-model' + | 'pixel-art' + | 'tile-texture' + } + StabilityImageGenrationUpscaleCreative_Response_200: { + id: components['schemas']['StabilityGenerationID'] + } + StabilityImageGenrationUpscaleCreative_Response_400: { + /** + * @description A unique identifier associated with this error. Please include this in any [support tickets](https://kb.stability.ai/knowledge-base/kb-tickets/new) + * you file, as it will greatly assist us in diagnosing the root cause of the problem. + * @example a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4 + */ + id: string + /** + * @description Short-hand name for an error, useful for discriminating between errors with the same status code. + * @example bad_request + */ + name: string + /** + * @description One or more error messages indicating what went wrong. + * @example [ + * "some-field: is required" + * ] + */ + errors: string[] + } + /** @example { + * "id": "4212a4b66fbe1cedca4bf2133d35dca5", + * "name": "payload_too_large", + * "errors": [ + * "body: payloads cannot be larger than 10MiB in size" + * ] + * } */ + StabilityImageGenrationUpscaleCreative_Response_413: { + /** + * @description A unique identifier associated with this error. Please include this in any [support tickets](https://kb.stability.ai/knowledge-base/kb-tickets/new) + * you file, as it will greatly assist us in diagnosing the root cause of the problem. + * @example a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4 + */ + id: string + /** + * @description Short-hand name for an error, useful for discriminating between errors with the same status code. + * @example bad_request + */ + name: string + /** + * @description One or more error messages indicating what went wrong. + * @example [ + * "some-field: is required" + * ] + */ + errors: string[] + } + StabilityImageGenrationUpscaleCreative_Response_422: { + /** + * @description A unique identifier associated with this error. Please include this in any [support tickets](https://kb.stability.ai/knowledge-base/kb-tickets/new) + * you file, as it will greatly assist us in diagnosing the root cause of the problem. + * @example a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4 + */ + id: string + /** + * @description Short-hand name for an error, useful for discriminating between errors with the same status code. + * @example bad_request + */ + name: string + /** + * @description One or more error messages indicating what went wrong. + * @example [ + * "some-field: is required" + * ] + */ + errors: string[] + } + /** @example { + * "id": "rate_limit_exceeded", + * "name": "rate_limit_exceeded", + * "errors": [ + * "You have exceeded the rate limit of 150 requests within a 10 second period, and have been timed out for 60 seconds." + * ] + * } */ + StabilityImageGenrationUpscaleCreative_Response_429: { + /** + * @description A unique identifier associated with this error. Please include this in any [support tickets](https://kb.stability.ai/knowledge-base/kb-tickets/new) + * you file, as it will greatly assist us in diagnosing the root cause of the problem. + * @example a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4 + */ + id: string + /** + * @description Short-hand name for an error, useful for discriminating between errors with the same status code. + * @example bad_request + */ + name: string + /** + * @description One or more error messages indicating what went wrong. + * @example [ + * "some-field: is required" + * ] + */ + errors: string[] + } + /** @example { + * "id": "2a1b2d4eafe2bc6ab4cd4d5c6133f513", + * "name": "internal_error", + * "errors": [ + * "An unexpected server error has occurred, please try again later." + * ] + * } */ + StabilityImageGenrationUpscaleCreative_Response_500: { + /** + * @description A unique identifier associated with this error. Please include this in any [support tickets](https://kb.stability.ai/knowledge-base/kb-tickets/new) + * you file, as it will greatly assist us in diagnosing the root cause of the problem. + * @example a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4 + */ + id: string + /** + * @description Short-hand name for an error, useful for discriminating between errors with the same status code. + * @example bad_request + */ + name: string + /** + * @description One or more error messages indicating what went wrong. + * @example [ + * "some-field: is required" + * ] + */ + errors: string[] + } + StabilityImageGenrationUpscaleFast_Request: { + /** + * Format: binary + * @description The image you wish to upscale. + * + * Supported Formats: + * - jpeg + * - png + * - webp + * + * Validation Rules: + * - Width must be between 32 and 1,536 pixels + * - Height must be between 32 and 1,536 pixels + * - Total pixel count must be between 1,024 and 1,048,576 pixels + * @example ./some/image.png + */ + image: string + /** + * @description Dictates the `content-type` of the generated image. + * @default png + * @enum {string} + */ + output_format: 'jpeg' | 'png' | 'webp' + } + StabilityImageGenrationUpscaleFast_Response_200: { + /** + * @description The generated image, encoded to base64. + * @example AAAAIGZ0eXBpc29tAAACAGlzb21pc28yYXZjMW1... + */ + image: string + /** + * @description The seed used as random noise for this generation. + * @default 0 + * @example 343940597 + */ + seed: number + /** + * @description The reason the generation finished. + * + * - `SUCCESS` = successful generation. + * - `CONTENT_FILTERED` = successful generation, however the output violated our content moderation + * policy and has been blurred as a result. + * @example SUCCESS + * @enum {string} + */ + finish_reason: 'SUCCESS' | 'CONTENT_FILTERED' + } + StabilityImageGenrationUpscaleFast_Response_400: { + /** + * @description A unique identifier associated with this error. Please include this in any [support tickets](https://kb.stability.ai/knowledge-base/kb-tickets/new) + * you file, as it will greatly assist us in diagnosing the root cause of the problem. + * @example a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4 + */ + id: string + /** + * @description Short-hand name for an error, useful for discriminating between errors with the same status code. + * @example bad_request + */ + name: string + /** + * @description One or more error messages indicating what went wrong. + * @example [ + * "some-field: is required" + * ] + */ + errors: string[] + } + /** @example { + * "id": "4212a4b66fbe1cedca4bf2133d35dca5", + * "name": "payload_too_large", + * "errors": [ + * "body: payloads cannot be larger than 10MiB in size" + * ] + * } */ + StabilityImageGenrationUpscaleFast_Response_413: { + /** + * @description A unique identifier associated with this error. Please include this in any [support tickets](https://kb.stability.ai/knowledge-base/kb-tickets/new) + * you file, as it will greatly assist us in diagnosing the root cause of the problem. + * @example a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4 + */ + id: string + /** + * @description Short-hand name for an error, useful for discriminating between errors with the same status code. + * @example bad_request + */ + name: string + /** + * @description One or more error messages indicating what went wrong. + * @example [ + * "some-field: is required" + * ] + */ + errors: string[] + } + StabilityImageGenrationUpscaleFast_Response_422: { + /** + * @description A unique identifier associated with this error. Please include this in any [support tickets](https://kb.stability.ai/knowledge-base/kb-tickets/new) + * you file, as it will greatly assist us in diagnosing the root cause of the problem. + * @example a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4 + */ + id: string + /** + * @description Short-hand name for an error, useful for discriminating between errors with the same status code. + * @example bad_request + */ + name: string + /** + * @description One or more error messages indicating what went wrong. + * @example [ + * "some-field: is required" + * ] + */ + errors: string[] + } + /** @example { + * "id": "rate_limit_exceeded", + * "name": "rate_limit_exceeded", + * "errors": [ + * "You have exceeded the rate limit of 150 requests within a 10 second period, and have been timed out for 60 seconds." + * ] + * } */ + StabilityImageGenrationUpscaleFast_Response_429: { + /** + * @description A unique identifier associated with this error. Please include this in any [support tickets](https://kb.stability.ai/knowledge-base/kb-tickets/new) + * you file, as it will greatly assist us in diagnosing the root cause of the problem. + * @example a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4 + */ + id: string + /** + * @description Short-hand name for an error, useful for discriminating between errors with the same status code. + * @example bad_request + */ + name: string + /** + * @description One or more error messages indicating what went wrong. + * @example [ + * "some-field: is required" + * ] + */ + errors: string[] + } + StabilityGetResultResponse_202: { + /** @enum {string} */ + status?: 'in-progress' + /** + * @description The ID of the generation result. + * @example 1234567890 + */ + id?: string + } + APIKey: { + id?: string + name?: string + description?: string + key_prefix?: string + /** Format: date-time */ + created_at?: string + } + APIKeyWithPlaintext: components['schemas']['APIKey'] & { + /** @description The full API key (only returned at creation) */ + plaintext_key?: string + } + GeminiGenerateContentRequest: { + contents: components['schemas']['GeminiContent'][] + tools?: components['schemas']['GeminiTool'][] + safetySettings?: components['schemas']['GeminiSafetySetting'][] + generationConfig?: components['schemas']['GeminiGenerationConfig'] + systemInstruction?: components['schemas']['GeminiSystemInstructionContent'] + videoMetadata?: components['schemas']['GeminiVideoMetadata'] + } + GeminiGenerateContentResponse: { + candidates?: components['schemas']['GeminiCandidate'][] + promptFeedback?: components['schemas']['GeminiPromptFeedback'] + usageMetadata?: components['schemas']['GeminiUsageMetadata'] + } + GeminiUsageMetadata: { + /** @description Number of tokens in the request. When cachedContent is set, this is still the total effective prompt size meaning this includes the number of tokens in the cached content. */ + promptTokenCount?: number + /** @description Number of tokens in the response(s). */ + candidatesTokenCount?: number + /** @description Number of tokens present in tool-use prompt(s). */ + toolUsePromptTokenCount?: number + /** @description Number of tokens present in thoughts output. */ + thoughtsTokenCount?: number + /** @description Output only. Number of tokens in the cached part in the input (the cached content). */ + cachedContentTokenCount?: number + /** @description Breakdown of prompt tokens by modality. */ + promptTokensDetails?: components['schemas']['ModalityTokenCount'][] + /** @description Breakdown of candidate tokens by modality. */ + candidatesTokensDetails?: components['schemas']['ModalityTokenCount'][] + } + ModalityTokenCount: { + modality?: components['schemas']['Modality'] + /** @description Number of tokens for the given modality. */ + tokenCount?: number + } + /** + * @description Type of input or output content modality. + * @enum {string} + */ + Modality: + | 'MODALITY_UNSPECIFIED' + | 'TEXT' + | 'IMAGE' + | 'VIDEO' + | 'AUDIO' + | 'DOCUMENT' + /** @description Available for gemini-2.0-flash and gemini-2.0-flash-lite. Instructions for the model to steer it toward better performance. For example, "Answer as concisely as possible" or "Don't use technical terms in your response". The text strings count toward the token limit. The role field of systemInstruction is ignored and doesn't affect the performance of the model. Note: Only text should be used in parts and content in each part should be in a separate paragraph. + * */ + GeminiSystemInstructionContent: { + /** + * @description The identity of the entity that creates the message. The following values are supported: user: This indicates that the message is sent by a real person, typically a user-generated message. model: This indicates that the message is generated by the model. The model value is used to insert messages from the model into the conversation during multi-turn conversations. For non-multi-turn conversations, this field can be left blank or unset. + * + * @example user + * @enum {string} + */ + role: 'user' | 'model' + /** @description A list of ordered parts that make up a single message. Different parts may have different IANA MIME types. For limits on the inputs, such as the maximum number of tokens or the number of images, see the model specifications on the Google models page. + * */ + parts: components['schemas']['GeminiTextPart'][] + } + /** @description The content of the current conversation with the model. For single-turn queries, this is a single instance. For multi-turn queries, this is a repeated field that contains conversation history and the latest request. + * */ + GeminiContent: { + /** + * @example user + * @enum {string} + */ + role: 'user' | 'model' + parts: components['schemas']['GeminiPart'][] + } + /** @description A piece of code that enables the system to interact with external systems to perform an action, or set of actions, outside of knowledge and scope of the model. See Function calling. + * */ + GeminiTool: { + functionDeclarations?: components['schemas']['GeminiFunctionDeclaration'][] + } + /** @description Per request settings for blocking unsafe content. Enforced on GenerateContentResponse.candidates. + * */ + GeminiSafetySetting: { + category: components['schemas']['GeminiSafetyCategory'] + threshold: components['schemas']['GeminiSafetyThreshold'] + } + /** @enum {string} */ + GeminiSafetyCategory: + | 'HARM_CATEGORY_SEXUALLY_EXPLICIT' + | 'HARM_CATEGORY_HATE_SPEECH' + | 'HARM_CATEGORY_HARASSMENT' + | 'HARM_CATEGORY_DANGEROUS_CONTENT' + /** @enum {string} */ + GeminiSafetyThreshold: + | 'OFF' + | 'BLOCK_NONE' + | 'BLOCK_LOW_AND_ABOVE' + | 'BLOCK_MEDIUM_AND_ABOVE' + | 'BLOCK_ONLY_HIGH' + GeminiGenerationConfig: { + /** + * Format: float + * @description The temperature is used for sampling during response generation, which occurs when topP and topK are applied. Temperature controls the degree of randomness in token selection. Lower temperatures are good for prompts that require a less open-ended or creative response, while higher temperatures can lead to more diverse or creative results. A temperature of 0 means that the highest probability tokens are always selected. In this case, responses for a given prompt are mostly deterministic, but a small amount of variation is still possible. If the model returns a response that's too generic, too short, or the model gives a fallback response, try increasing the temperature + * + * @default 1 + */ + temperature: number + /** + * Format: float + * @description If specified, nucleus sampling is used. + * Top-P changes how the model selects tokens for output. Tokens are selected from the most (see top-K) to least probable until the sum of their probabilities equals the top-P value. For example, if tokens A, B, and C have a probability of 0.3, 0.2, and 0.1 and the top-P value is 0.5, then the model will select either A or B as the next token by using temperature and excludes C as a candidate. + * Specify a lower value for less random responses and a higher value for more random responses. + * + * @default 0.95 + */ + topP: number + /** + * @description Top-K changes how the model selects tokens for output. A top-K of 1 means the next selected token is the most probable among all tokens in the model's vocabulary. A top-K of 3 means that the next token is selected from among the 3 most probable tokens by using temperature. + * + * @default 40 + * @example 40 + */ + topK: number + /** + * @description Maximum number of tokens that can be generated in the response. A token is approximately 4 characters. 100 tokens correspond to roughly 60-80 words. + * + * @example 2048 + */ + maxOutputTokens?: number + /** + * @description When seed is fixed to a specific value, the model makes a best effort to provide the same response for repeated requests. Deterministic output isn't guaranteed. Also, changing the model or parameter settings, such as the temperature, can cause variations in the response even when you use the same seed value. By default, a random seed value is used. Available for the following models:, gemini-2.5-flash-preview-04-1, gemini-2.5-pro-preview-05-0, gemini-2.0-flash-lite-00, gemini-2.0-flash-001 + * + * @example 343940597 + */ + seed?: number + stopSequences?: string[] + } + /** @description For video input, the start and end offset of the video in Duration format. For example, to specify a 10 second clip starting at 1:00, set "startOffset": { "seconds": 60 } and "endOffset": { "seconds": 70 }. The metadata should only be specified while the video data is presented in inlineData or fileData. + * */ + GeminiVideoMetadata: { + startOffset?: components['schemas']['GeminiOffset'] + endOffset?: components['schemas']['GeminiOffset'] + } + /** @description Represents a duration offset for video timeline positions. + * */ + GeminiOffset: { + /** + * @description Signed seconds of the span of time. Must be from -315,576,000,000 to +315,576,000,000 inclusive. + * + * @example 60 + */ + seconds?: number + /** + * @description Signed fractions of a second at nanosecond resolution. Negative second values with fractions must still have non-negative nanos values. + * + * @example 0 + */ + nanos?: number + } + GeminiCandidate: { + content?: components['schemas']['GeminiContent'] + finishReason?: string + safetyRatings?: components['schemas']['GeminiSafetyRating'][] + citationMetadata?: components['schemas']['GeminiCitationMetadata'] + } + /** + * @description The media type of the file specified in the data or fileUri fields. Acceptable values include the following. For gemini-2.0-flash-lite and gemini-2.0-flash, the maximum length of an audio file is 8.4 hours and the maximum length of a video file (without audio) is one hour. For more information, see Gemini audio and video requirements. Text files must be UTF-8 encoded. The contents of the text file count toward the token limit. There is no limit on image resolution. + * @enum {string} + */ + GeminiMimeType: + | 'application/pdf' + | 'audio/mpeg' + | 'audio/mp3' + | 'audio/wav' + | 'image/png' + | 'image/jpeg' + | 'image/webp' + | 'text/plain' + | 'video/mov' + | 'video/mpeg' + | 'video/mp4' + | 'video/mpg' + | 'video/avi' + | 'video/wmv' + | 'video/mpegps' + | 'video/flv' + GeminiPromptFeedback: { + safetyRatings?: components['schemas']['GeminiSafetyRating'][] + blockReason?: string + blockReasonMessage?: string + } + GeminiTextPart: { + /** + * @description A text prompt or code snippet. + * @example Answer as concisely as possible + */ + text?: string + } + GeminiPart: { + /** + * @description A text prompt or code snippet. + * @example Write a story about a robot learning to paint + */ + text?: string + inlineData?: components['schemas']['GeminiInlineData'] + } + GeminiFunctionDeclaration: { + name: string + description?: string + /** @description JSON schema for the function parameters */ + parameters: Record + } + GeminiSafetyRating: { + category?: components['schemas']['GeminiSafetyCategory'] + /** + * @description The probability that the content violates the specified safety category + * @enum {string} + */ + probability?: 'NEGLIGIBLE' | 'LOW' | 'MEDIUM' | 'HIGH' | 'UNKNOWN' + } + GeminiCitationMetadata: { + citations?: components['schemas']['GeminiCitation'][] + } + /** @description Inline data in raw bytes. For gemini-2.0-flash-lite and gemini-2.0-flash, you can specify up to 3000 images by using inlineData. + * */ + GeminiInlineData: { + mimeType?: components['schemas']['GeminiMimeType'] + /** + * Format: byte + * @description The base64 encoding of the image, PDF, or video to include inline in the prompt. When including media inline, you must also specify the media type (mimeType) of the data. Size limit: 20MB + * + */ + data?: string + } + GeminiCitation: { + startIndex?: number + endIndex?: number + uri?: string + title?: string + license?: string + /** Format: date */ + publicationDate?: string + authors?: string[] + } + Rodin3DGenerateRequest: { + /** @description The reference images to generate 3D Assets. */ + images: string + /** @description Seed. */ + seed?: number + tier?: components['schemas']['RodinTierType'] + material?: components['schemas']['RodinMaterialType'] + quality?: components['schemas']['RodinQualityType'] + mesh_mode?: components['schemas']['RodinMeshModeType'] + } + /** + * @description Rodin Tier para options + * @enum {string} + */ + RodinTierType: 'Regular' | 'Sketch' | 'Detail' | 'Smooth' + /** + * @description Rodin Material para options + * @enum {string} + */ + RodinMaterialType: 'PBR' | 'Shaded' + /** + * @description Rodin Quality para options + * @enum {string} + */ + RodinQualityType: 'extra-low' | 'low' | 'medium' | 'high' + /** + * @description Rodin Mesh_Mode para options + * @enum {string} + */ + RodinMeshModeType: 'Quad' | 'Raw' + Rodin3DCheckStatusRequest: { + /** @description subscription from generate endpoint */ + subscription_key: string + } + Rodin3DDownloadRequest: { + /** @description Task UUID */ + task_uuid: string + } + Rodin3DGenerateResponse: { + /** @description message */ + message?: string + /** @description prompt */ + prompt?: string + /** @description Time */ + submit_time?: string + /** @description Task UUID */ + uuid?: string + jobs?: components['schemas']['RodinGenerateJobsData'] + } + RodinGenerateJobsData: { + /** @description subjobs uuid. */ + uuids?: string[] + /** @description Subscription Key. */ + subscription_key?: string + } + Rodin3DCheckStatusResponse: { + /** @description Details for the generation status. */ + jobs?: components['schemas']['RodinCheckStatusJobItem'][] + } + RodinCheckStatusJobItem: { + /** @description sub uuid */ + uuid?: string + status?: components['schemas']['RodinStatusOptions'] + } + /** @enum {string} */ + RodinStatusOptions: 'Done' | 'Failed' | 'Generating' | 'Waiting' + Rodin3DDownloadResponse: { + list?: components['schemas']['RodinResourceItem'][] + } + RodinResourceItem: { + /** @description Download url */ + url?: string + /** @description File name */ + name?: string + } + CreateAPIKeyRequest: { + name: string + description?: string + } + /** @example { + * "id": "2a1b2d4eafe2bc6ab4cd4d5c6133f513", + * "name": "internal_error", + * "errors": [ + * "An unexpected server error has occurred, please try again later." + * ] + * } */ + StabilityImageGenrationUpscaleFast_Response_500: { + /** + * @description A unique identifier associated with this error. Please include this in any [support tickets](https://kb.stability.ai/knowledge-base/kb-tickets/new) + * you file, as it will greatly assist us in diagnosing the root cause of the problem. + * @example a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4 + */ + id: string + /** + * @description Short-hand name for an error, useful for discriminating between errors with the same status code. + * @example bad_request + */ + name: string + /** + * @description One or more error messages indicating what went wrong. + * @example [ + * "some-field: is required" + * ] + */ + errors: string[] + } + /** @description Common properties for model responses */ + ModelResponseProperties: { + /** @description The model used to generate the response */ + model?: string + /** @description Instructions for the model on how to generate the response */ + instructions?: string + /** @description Maximum number of tokens to generate */ + max_output_tokens?: number + /** + * @description Controls randomness in the response + * @default 1 + */ + temperature: number + /** + * @description Controls diversity of the response via nucleus sampling + * @default 1 + */ + top_p: number + /** + * @description How to handle truncation of the response + * @default disabled + * @enum {string} + */ + truncation: 'disabled' | 'auto' + } + /** + * Input file + * @description A file input to the model. + */ + InputFileContent: { + /** + * @description The type of the input item. Always `input_file`. + * @default input_file + * @enum {string} + */ + type: 'input_file' + /** @description The ID of the file to be sent to the model. */ + file_id?: string + /** @description The name of the file to be sent to the model. */ + filename?: string + /** @description The content of the file to be sent to the model. + * */ + file_data?: string + } + ResponseProperties: { + /** @description The unique ID of the previous response to the model. Use this to + * create multi-turn conversations. Learn more about + * [conversation state](/docs/guides/conversation-state). + * */ + previous_response_id?: string + /** @description Model ID used to generate the response, like `gpt-4o` or `o3`. OpenAI + * offers a wide range of models with different capabilities, performance + * characteristics, and price points. Refer to the [model guide](/docs/models) + * to browse and compare available models. + * */ + model?: components['schemas']['OpenAIModels'] + reasoning?: components['schemas']['Reasoning'] + /** @description An upper bound for the number of tokens that can be generated for a response, including visible output tokens and [reasoning tokens](/docs/guides/reasoning). + * */ + max_output_tokens?: number + /** @description Inserts a system (or developer) message as the first item in the model's context. + * + * When using along with `previous_response_id`, the instructions from a previous + * response will not be carried over to the next response. This makes it simple + * to swap out system (or developer) messages in new responses. + * */ + instructions?: string + text?: { + format?: components['schemas']['TextResponseFormatConfiguration'] + } + tools?: components['schemas']['Tool'][] + /** @description How the model should select which tool (or tools) to use when generating + * a response. See the `tools` parameter to see how to specify which tools + * the model can call. + * */ + tool_choice?: + | components['schemas']['ToolChoiceOptions'] + | components['schemas']['ToolChoiceTypes'] + | components['schemas']['ToolChoiceFunction'] + /** + * @description The truncation strategy to use for the model response. + * - `auto`: If the context of this response and previous ones exceeds + * the model's context window size, the model will truncate the + * response to fit the context window by dropping input items in the + * middle of the conversation. + * - `disabled` (default): If a model response will exceed the context window + * size for a model, the request will fail with a 400 error. + * + * @default disabled + * @enum {string} + */ + truncation: 'auto' | 'disabled' + } + /** @description An object specifying the format that the model must output. + * + * Configuring `{ "type": "json_schema" }` enables Structured Outputs, + * which ensures the model will match your supplied JSON schema. Learn more in the + * [Structured Outputs guide](/docs/guides/structured-outputs). + * + * The default format is `{ "type": "text" }` with no additional options. + * + * **Not recommended for gpt-4o and newer models:** + * + * Setting to `{ "type": "json_object" }` enables the older JSON mode, which + * ensures the message the model generates is valid JSON. Using `json_schema` + * is preferred for models that support it. + * */ + TextResponseFormatConfiguration: + | components['schemas']['ResponseFormatText'] + | components['schemas']['TextResponseFormatJsonSchema'] + | components['schemas']['ResponseFormatJsonObject'] + /** + * JSON object + * @description JSON object response format. An older method of generating JSON responses. + * Using `json_schema` is recommended for models that support it. Note that the + * model will not generate JSON without a system or user message instructing it + * to do so. + * + */ + ResponseFormatJsonObject: { + /** + * @description The type of response format being defined. Always `json_object`. + * @enum {string} + */ + type: 'json_object' + } + /** + * JSON schema + * @description JSON Schema response format. Used to generate structured JSON responses. + * Learn more about [Structured Outputs](/docs/guides/structured-outputs). + * + */ + ResponseFormatJsonSchema: { + /** @default json_schema */ + type: string + /** + * JSON schema + * @description Structured Outputs configuration options, including a JSON Schema. + * + */ + json_schema: { + /** @description A description of what the response format is for, used by the model to + * determine how to respond in the format. + * */ + description?: string + /** @description The name of the response format. Must be a-z, A-Z, 0-9, or contain + * underscores and dashes, with a maximum length of 64. + * */ + name: string + schema?: components['schemas']['ResponseFormatJsonSchemaSchema'] + /** + * @description Whether to enable strict schema adherence when generating the output. + * If set to true, the model will always follow the exact schema defined + * in the `schema` field. Only a subset of JSON Schema is supported when + * `strict` is `true`. To learn more, read the [Structured Outputs + * guide](/docs/guides/structured-outputs). + * + * @default false + */ + strict: boolean + } + } + /** + * JSON schema + * @description The schema for the response format, described as a JSON Schema object. + * Learn how to build JSON schemas [here](https://json-schema.org/). + * + */ + ResponseFormatJsonSchemaSchema: { + [key: string]: unknown + } + /** + * Text + * @description Default response format. Used to generate text responses. + * + */ + ResponseFormatText: { + /** + * @description The type of response format being defined. Always `text`. + * @enum {string} + */ + type: 'text' + } + /** + * JSON schema + * @description JSON Schema response format. Used to generate structured JSON responses. + * Learn more about [Structured Outputs](/docs/guides/structured-outputs). + * + */ + TextResponseFormatJsonSchema: { + /** + * @description The type of response format being defined. Always `json_schema`. + * @enum {string} + */ + type: 'json_schema' + /** @description A description of what the response format is for, used by the model to + * determine how to respond in the format. + * */ + description?: string + /** @description The name of the response format. Must be a-z, A-Z, 0-9, or contain + * underscores and dashes, with a maximum length of 64. + * */ + name: string + schema: components['schemas']['ResponseFormatJsonSchemaSchema'] + /** + * @description Whether to enable strict schema adherence when generating the output. + * If set to true, the model will always follow the exact schema defined + * in the `schema` field. Only a subset of JSON Schema is supported when + * `strict` is `true`. To learn more, read the [Structured Outputs + * guide](/docs/guides/structured-outputs). + * + * @default false + */ + strict: boolean + } + /** + * Reasoning + * @description **o-series models only** + * + * Configuration options for + * [reasoning models](https://platform.openai.com/docs/guides/reasoning). + * + */ + Reasoning: { + effort?: components['schemas']['ReasoningEffort'] + /** + * @description A summary of the reasoning performed by the model. This can be + * useful for debugging and understanding the model's reasoning process. + * One of `auto`, `concise`, or `detailed`. + * + * @enum {string} + */ + summary?: 'auto' | 'concise' | 'detailed' + /** + * @deprecated + * @description **Deprecated:** use `summary` instead. + * + * A summary of the reasoning performed by the model. This can be + * useful for debugging and understanding the model's reasoning process. + * One of `auto`, `concise`, or `detailed`. + * + * @enum {string} + */ + generate_summary?: 'auto' | 'concise' | 'detailed' + } + /** + * @description **o-series models only** + * + * Constrains effort on reasoning for + * [reasoning models](https://platform.openai.com/docs/guides/reasoning). + * Currently supported values are `low`, `medium`, and `high`. Reducing + * reasoning effort can result in faster responses and fewer tokens used + * on reasoning in a response. + * + * @default medium + * @enum {string} + */ + ReasoningEffort: 'low' | 'medium' | 'high' + /** + * Web search preview + * @description This tool searches the web for relevant results to use in a response. Learn more about the [web search tool](https://platform.openai.com/docs/guides/tools-web-search). + */ + WebSearchPreviewTool: { + /** + * @description The type of the web search tool. One of `web_search_preview` or `web_search_preview_2025_03_11`. (enum property replaced by openapi-typescript) + * @enum {string} + */ + type: 'WebSearchPreviewTool' + /** + * @description High level guidance for the amount of context window space to use for the search. One of `low`, `medium`, or `high`. `medium` is the default. + * @enum {string} + */ + search_context_size?: 'low' | 'medium' | 'high' + } + /** + * Computer use preview + * @description A tool that controls a virtual computer. Learn more about the [computer tool](https://platform.openai.com/docs/guides/tools-computer-use). + */ + ComputerUsePreviewTool: { + /** + * @description The type of the computer use tool. Always `computer_use_preview`. (enum property replaced by openapi-typescript) + * @enum {string} + */ + type: 'ComputerUsePreviewTool' + /** + * @description The type of computer environment to control. + * @enum {string} + */ + environment: 'windows' | 'mac' | 'linux' | 'ubuntu' | 'browser' + /** @description The width of the computer display. */ + display_width: number + /** @description The height of the computer display. */ + display_height: number + } + Tool: + | components['schemas']['FileSearchTool'] + | components['schemas']['FunctionTool'] + | components['schemas']['WebSearchPreviewTool'] + | components['schemas']['ComputerUsePreviewTool'] + /** @description Emitted when an error occurs. */ + ResponseErrorEvent: { + /** + * @description The type of the event. Always `error`. + * + * @enum {string} + */ + type: 'error' + /** @description The error code. + * */ + code: string + /** @description The error message. + * */ + message: string + /** @description The error parameter. + * */ + param: string + } + /** @description Emitted when a new output item is added. */ + ResponseOutputItemAddedEvent: { + /** + * @description The type of the event. Always `response.output_item.added`. + * + * @enum {string} + */ + type: 'response.output_item.added' + /** @description The index of the output item that was added. + * */ + output_index: number + /** @description The output item that was added. + * */ + item: components['schemas']['OutputItem'] + } + /** @description Emitted when an output item is marked done. */ + ResponseOutputItemDoneEvent: { + /** + * @description The type of the event. Always `response.output_item.done`. + * + * @enum {string} + */ + type: 'response.output_item.done' + /** @description The index of the output item that was marked done. + * */ + output_index: number + /** @description The output item that was marked done. + * */ + item: components['schemas']['OutputItem'] + } + /** + * Function tool + * @description Use this option to force the model to call a specific function. + * + */ + ToolChoiceFunction: { + /** + * @description For function calling, the type is always `function`. + * @enum {string} + */ + type: 'function' + /** @description The name of the function to call. */ + name: string + } + /** + * Tool choice mode + * @description Controls which (if any) tool is called by the model. + * + * `none` means the model will not call any tool and instead generates a message. + * + * `auto` means the model can pick between generating a message or calling one or + * more tools. + * + * `required` means the model must call one or more tools. + * + * @enum {string} + */ + ToolChoiceOptions: 'none' | 'auto' | 'required' + /** + * Hosted tool + * @description Indicates that the model should use a built-in tool to generate a response. + * [Learn more about built-in tools](/docs/guides/tools). + * + */ + ToolChoiceTypes: { + /** + * @description The type of hosted tool the model should to use. Learn more about + * [built-in tools](/docs/guides/tools). + * + * Allowed values are: + * - `file_search` + * - `web_search_preview` + * - `computer_use_preview` + * + * @enum {string} + */ + type: + | 'file_search' + | 'web_search_preview' + | 'computer_use_preview' + | 'web_search_preview_2025_03_11' + } + /** @description An event that is emitted when a response fails. + * */ + ResponseFailedEvent: { + /** + * @description The type of the event. Always `response.failed`. + * + * @enum {string} + */ + type: 'response.failed' + /** @description The response that failed. + * */ + response: components['schemas']['OpenAIResponse'] + } + /** @description Emitted when the response is in progress. */ + ResponseInProgressEvent: { + /** + * @description The type of the event. Always `response.in_progress`. + * + * @enum {string} + */ + type: 'response.in_progress' + /** @description The response that is in progress. + * */ + response: components['schemas']['OpenAIResponse'] + } + /** @description An event that is emitted when a response finishes as incomplete. + * */ + ResponseIncompleteEvent: { + /** + * @description The type of the event. Always `response.incomplete`. + * + * @enum {string} + */ + type: 'response.incomplete' + /** @description The response that was incomplete. + * */ + response: components['schemas']['OpenAIResponse'] + } + /** @description An event that is emitted when a response is created. */ + ResponseCreatedEvent: { + /** + * @description The type of the event. Always `response.created`. + * @enum {string} + */ + type: 'response.created' + /** @description The response that was created. */ + response: components['schemas']['OpenAIResponse'] + } + /** @description Emitted when the model response is complete. */ + ResponseCompletedEvent: { + /** + * @description The type of the event. Always `response.completed`. + * @enum {string} + */ + type: 'response.completed' + /** @description Properties of the completed response. */ + response: components['schemas']['OpenAIResponse'] + } + /** @description Emitted when a new content part is added. */ + ResponseContentPartAddedEvent: { + /** + * @description The type of the event. Always `response.content_part.added`. + * @enum {string} + */ + type: 'response.content_part.added' + /** @description The ID of the output item that the content part was added to. */ + item_id: string + /** @description The index of the output item that the content part was added to. */ + output_index: number + /** @description The index of the content part that was added. */ + content_index: number + /** @description The content part that was added. */ + part: components['schemas']['OutputContent'] + } + /** @description Emitted when a content part is done. */ + ResponseContentPartDoneEvent: { + /** + * @description The type of the event. Always `response.content_part.done`. + * @enum {string} + */ + type: 'response.content_part.done' + /** @description The ID of the output item that the content part was added to. */ + item_id: string + /** @description The index of the output item that the content part was added to. */ + output_index: number + /** @description The index of the content part that is done. */ + content_index: number + /** @description The content part that is done. */ + part: components['schemas']['OutputContent'] + } + ResponseTool: + | components['schemas']['WebSearchTool'] + | components['schemas']['FileSearchTool'] + | components['schemas']['FunctionTool'] + WebSearchTool: { + /** + * @description The type of tool + * @enum {string} + */ + type: 'web_search' + /** @description Optional list of domains to restrict search to */ + domains?: string[] + } + FileSearchTool: { + /** + * @description The type of tool (enum property replaced by openapi-typescript) + * @enum {string} + */ + type: 'FileSearchTool' + /** @description IDs of vector stores to search in */ + vector_store_ids: string[] + } + FunctionTool: { + /** + * @description The type of tool (enum property replaced by openapi-typescript) + * @enum {string} + */ + type: 'FunctionTool' + /** @description Name of the function */ + name: string + /** @description Description of what the function does */ + description?: string + /** @description JSON Schema object describing the function parameters */ + parameters: Record + } + OutputItem: + | components['schemas']['OutputMessage'] + | components['schemas']['FileSearchToolCall'] + | components['schemas']['FunctionToolCall'] + | components['schemas']['WebSearchToolCall'] + | components['schemas']['ComputerToolCall'] + | components['schemas']['ReasoningItem'] + /** + * Web search tool call + * @description The results of a web search tool call. See the + * [web search guide](/docs/guides/tools-web-search) for more information. + * + */ + WebSearchToolCall: { + /** @description The unique ID of the web search tool call. + * */ + id: string + /** + * @description The type of the web search tool call. Always `web_search_call`. + * (enum property replaced by openapi-typescript) + * @enum {string} + */ + type: 'WebSearchToolCall' + /** + * @description The status of the web search tool call. + * + * @enum {string} + */ + status: 'in_progress' | 'searching' | 'completed' | 'failed' + } + /** + * File search tool call + * @description The results of a file search tool call. See the + * [file search guide](/docs/guides/tools-file-search) for more information. + * + */ + FileSearchToolCall: { + /** @description The unique ID of the file search tool call. + * */ + id: string + /** + * @description The type of the file search tool call. Always `file_search_call`. + * (enum property replaced by openapi-typescript) + * @enum {string} + */ + type: 'FileSearchToolCall' + /** + * @description The status of the file search tool call. One of `in_progress`, + * `searching`, `incomplete` or `failed`, + * + * @enum {string} + */ + status: + | 'in_progress' + | 'searching' + | 'completed' + | 'incomplete' + | 'failed' + /** @description The queries used to search for files. + * */ + queries: string[] + /** @description The results of the file search tool call. + * */ + results?: { + /** @description The unique ID of the file. + * */ + file_id?: string + /** @description The text that was retrieved from the file. + * */ + text?: string + /** @description The name of the file. + * */ + filename?: string + /** + * Format: float + * @description The relevance score of the file - a value between 0 and 1. + * + */ + score?: number + }[] + } + /** + * Function tool call + * @description A tool call to run a function. See the + * [function calling guide](/docs/guides/function-calling) for more information. + * + */ + FunctionToolCall: { + /** @description The unique ID of the function tool call. + * */ + id?: string + /** + * @description The type of the function tool call. Always `function_call`. + * + * @enum {string} + */ + type: 'function_call' + /** @description The unique ID of the function tool call generated by the model. + * */ + call_id: string + /** @description The name of the function to run. + * */ + name: string + /** @description A JSON string of the arguments to pass to the function. + * */ + arguments: string + /** + * @description The status of the item. One of `in_progress`, `completed`, or + * `incomplete`. Populated when items are returned via API. + * + * @enum {string} + */ + status?: 'in_progress' | 'completed' | 'incomplete' + } + OutputMessage: { + /** + * @description The type of output item (enum property replaced by openapi-typescript) + * @enum {string} + */ + type: 'OutputMessage' + /** + * @description The role of the message + * @enum {string} + */ + role: 'assistant' + /** @description The content of the message */ + content: components['schemas']['OutputContent'][] + } + OutputContent: + | components['schemas']['OutputTextContent'] + | components['schemas']['OutputAudioContent'] + OutputTextContent: { + /** + * @description The type of output content + * @enum {string} + */ + type: 'output_text' + /** @description The text content */ + text: string + } + OutputAudioContent: { + /** + * @description The type of output content + * @enum {string} + */ + type: 'output_audio' + /** @description Base64-encoded audio data */ + data: string + /** @description Transcript of the audio */ + transcript: string + } + /** @description Represents token usage details including input tokens, output tokens, + * a breakdown of output tokens, and the total tokens used. + * */ + ResponseUsage: { + /** @description The number of input tokens. */ + input_tokens: number + /** @description A detailed breakdown of the input tokens. */ + input_tokens_details: { + /** @description The number of tokens that were retrieved from the cache. + * [More on prompt caching](/docs/guides/prompt-caching). + * */ + cached_tokens: number + } + /** @description The number of output tokens. */ + output_tokens: number + /** @description A detailed breakdown of the output tokens. */ + output_tokens_details: { + /** @description The number of reasoning tokens. */ + reasoning_tokens: number + } + /** @description The total number of tokens used. */ + total_tokens: number + } + /** @description A response from the model */ + OpenAIResponse: components['schemas']['ModelResponseProperties'] & + components['schemas']['ResponseProperties'] & { + /** @description Unique identifier for this Response. */ + id?: string + /** + * @description The object type of this resource - always set to `response`. + * @enum {string} + */ + object?: 'response' + /** + * @description The status of the response generation. One of `completed`, `failed`, `in_progress`, or `incomplete`. + * @enum {string} + */ + status?: 'completed' | 'failed' | 'in_progress' | 'incomplete' + /** @description Unix timestamp (in seconds) of when this Response was created. */ + created_at?: number + error?: components['schemas']['ResponseError'] + /** @description Details about why the response is incomplete. + * */ + incomplete_details?: { + /** + * @description The reason why the response is incomplete. + * @enum {string} + */ + reason?: 'max_output_tokens' | 'content_filter' + } | null + /** @description An array of content items generated by the model. + * + * - The length and order of items in the `output` array is dependent + * on the model's response. + * - Rather than accessing the first item in the `output` array and + * assuming it's an `assistant` message with the content generated by + * the model, you might consider using the `output_text` property where + * supported in SDKs. + * */ + output?: components['schemas']['OutputItem'][] + /** @description SDK-only convenience property that contains the aggregated text output + * from all `output_text` items in the `output` array, if any are present. + * Supported in the Python and JavaScript SDKs. + * */ + output_text?: string | null + usage?: components['schemas']['ResponseUsage'] + /** + * @description Whether to allow the model to run tool calls in parallel. + * + * @default true + */ + parallel_tool_calls: boolean + } + /** @description An error object returned when the model fails to generate a Response. */ + ResponseError: { + code: components['schemas']['ResponseErrorCode'] + /** @description A human-readable description of the error. */ + message: string + } + /** + * @description The error code for the response. + * @enum {string} + */ + ResponseErrorCode: + | 'server_error' + | 'rate_limit_exceeded' + | 'invalid_prompt' + | 'vector_store_timeout' + | 'invalid_image' + | 'invalid_image_format' + | 'invalid_base64_image' + | 'invalid_image_url' + | 'image_too_large' + | 'image_too_small' + | 'image_parse_error' + | 'image_content_policy_violation' + | 'invalid_image_mode' + | 'image_file_too_large' + | 'unsupported_image_media_type' + | 'empty_image_file' + | 'failed_to_download_image' + | 'image_file_not_found' + /** @description Events that can be emitted during response streaming */ + OpenAIResponseStreamEvent: + | components['schemas']['ResponseCreatedEvent'] + | components['schemas']['ResponseInProgressEvent'] + | components['schemas']['ResponseCompletedEvent'] + | components['schemas']['ResponseFailedEvent'] + | components['schemas']['ResponseIncompleteEvent'] + | components['schemas']['ResponseOutputItemAddedEvent'] + | components['schemas']['ResponseOutputItemDoneEvent'] + | components['schemas']['ResponseContentPartAddedEvent'] + | components['schemas']['ResponseContentPartDoneEvent'] + | components['schemas']['ResponseErrorEvent'] + InputMessage: { + /** @enum {string} */ + type?: 'message' + /** @enum {string} */ + role?: 'user' | 'system' | 'developer' + /** @enum {string} */ + status?: 'in_progress' | 'completed' | 'incomplete' + content?: components['schemas']['InputMessageContentList'] + } + /** + * Input item content list + * @description A list of one or many input items to the model, containing different content + * types. + * + */ + InputMessageContentList: components['schemas']['InputContent'][] + InputContent: + | components['schemas']['InputTextContent'] + | components['schemas']['InputImageContent'] + | components['schemas']['InputFileContent'] + /** + * Input text + * @description A text input to the model. + */ + InputTextContent: { + /** + * @description The type of the input item. Always `input_text`. + * @default input_text + * @enum {string} + */ + type: 'input_text' + /** @description The text input to the model. */ + text: string + } + /** + * Input image + * @description An image input to the model. Learn about [image inputs](/docs/guides/vision). + */ + InputImageContent: { + /** + * @description The type of the input item. Always `input_image`. + * @default input_image + * @enum {string} + */ + type: 'input_image' + /** @description The URL of the image to be sent to the model. A fully qualified URL or base64 encoded image in a data URL. */ + image_url?: string + /** @description The ID of the file to be sent to the model. */ + file_id?: string + /** + * @description The detail level of the image to be sent to the model. One of `high`, `low`, or `auto`. Defaults to `auto`. + * @enum {string} + */ + detail: 'low' | 'high' | 'auto' + } + InputMessageResource: components['schemas']['InputMessage'] & { + /** @description The unique ID of the message input. + * */ + id: string + } & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + type: 'InputMessageResource' + } + /** @description Content item used to generate a response. + * */ + ItemResource: + | components['schemas']['InputMessageResource'] + | components['schemas']['OutputMessage'] + | components['schemas']['FileSearchToolCall'] + | components['schemas']['ComputerToolCall'] + | components['schemas']['WebSearchToolCall'] + | components['schemas']['FunctionToolCallResource'] + FunctionToolCallResource: components['schemas']['FunctionToolCall'] & { + /** @description The unique ID of the function tool call. + * */ + id: string + } & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + type: 'FunctionToolCallResource' + } + /** + * Computer tool call + * @description A tool call to a computer use tool. See the + * [computer use guide](/docs/guides/tools-computer-use) for more information. + * + */ + ComputerToolCall: { + /** + * @description The type of the computer call. Always `computer_call`. (enum property replaced by openapi-typescript) + * @enum {string} + */ + type: 'ComputerToolCall' + /** @description The unique ID of the computer call. */ + id: string + /** @description An identifier used when responding to the tool call with output. + * */ + call_id: string + action: Record + /** + * @description The status of the item. One of `in_progress`, `completed`, or + * `incomplete`. Populated when items are returned via API. + * + * @enum {string} + */ + status: 'in_progress' | 'completed' | 'incomplete' + } + /** @description A list of Response items. */ + ResponseItemList: { + /** + * @description The type of object returned, must be `list`. + * @enum {string} + */ + object: 'list' + /** @description A list of items used to generate this response. */ + data: components['schemas']['ItemResource'][] + /** @description Whether there are more items available. */ + has_more: boolean + /** @description The ID of the first item in the list. */ + first_id: string + /** @description The ID of the last item in the list. */ + last_id: string + } + /** + * @description Specify additional output data to include in the model response. Currently + * supported values are: + * - `file_search_call.results`: Include the search results of + * the file search tool call. + * - `message.input_image.image_url`: Include image urls from the input message. + * - `computer_call_output.output.image_url`: Include image urls from the computer call output. + * + * @enum {string} + */ + Includable: + | 'file_search_call.results' + | 'message.input_image.image_url' + | 'computer_call_output.output.image_url' + CreateModelResponseProperties: components['schemas']['ModelResponseProperties'] + InputItem: + | components['schemas']['EasyInputMessage'] + | components['schemas']['Item'] + /** @description Content item used to generate a response. + * */ + Item: + | components['schemas']['InputMessage'] + | components['schemas']['OutputMessage'] + | components['schemas']['FileSearchToolCall'] + | components['schemas']['ComputerToolCall'] + | components['schemas']['WebSearchToolCall'] + | components['schemas']['FunctionToolCall'] + | components['schemas']['ReasoningItem'] + /** + * Reasoning + * @description A description of the chain of thought used by a reasoning model while generating + * a response. + * + */ + ReasoningItem: { + /** + * @description The type of the object. Always `reasoning`. + * + * @enum {string} + */ + type: 'reasoning' + /** @description The unique identifier of the reasoning content. + * */ + id: string + /** @description Reasoning text contents. + * */ + summary: { + /** + * @description The type of the object. Always `summary_text`. + * + * @enum {string} + */ + type: 'summary_text' + /** @description A short summary of the reasoning used by the model when generating + * the response. + * */ + text: string + }[] + /** + * @description The status of the item. One of `in_progress`, `completed`, or + * `incomplete`. Populated when items are returned via API. + * + * @enum {string} + */ + status?: 'in_progress' | 'completed' | 'incomplete' + } + /** + * Input message + * @description A message input to the model with a role indicating instruction following + * hierarchy. Instructions given with the `developer` or `system` role take + * precedence over instructions given with the `user` role. Messages with the + * `assistant` role are presumed to have been generated by the model in previous + * interactions. + * + */ + EasyInputMessage: { + /** + * @description The role of the message input. One of `user`, `assistant`, `system`, or + * `developer`. + * + * @enum {string} + */ + role: 'user' | 'assistant' | 'system' | 'developer' + /** @description Text, image, or audio input to the model, used to generate a response. + * Can also contain previous assistant responses. + * */ + content: string | components['schemas']['InputMessageContentList'] + /** + * @description The type of the message input. Always `message`. + * + * @enum {string} + */ + type?: 'message' + } + OpenAICreateResponse: components['schemas']['CreateModelResponseProperties'] & + components['schemas']['ResponseProperties'] & { + /** @description Text, image, or file inputs to the model, used to generate a response. + * + * Learn more: + * - [Text inputs and outputs](/docs/guides/text) + * - [Image inputs](/docs/guides/images) + * - [File inputs](/docs/guides/pdf-files) + * - [Conversation state](/docs/guides/conversation-state) + * - [Function calling](/docs/guides/function-calling) + * */ + input: string | components['schemas']['InputItem'][] + /** @description Specify additional output data to include in the model response. Currently + * supported values are: + * - `file_search_call.results`: Include the search results of + * the file search tool call. + * - `message.input_image.image_url`: Include image urls from the input message. + * - `computer_call_output.output.image_url`: Include image urls from the computer call output. + * */ + include?: components['schemas']['Includable'][] | null + usage?: components['schemas']['ResponseUsage'] + /** + * @description Whether to allow the model to run tool calls in parallel. + * + * @default true + */ + parallel_tool_calls: boolean | null + /** + * @description Whether to store the generated model response for later retrieval via + * API. + * + * @default true + */ + store: boolean | null + /** + * @description If set to true, the model response data will be streamed to the client + * as it is generated using [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format). + * See the [Streaming section below](/docs/api-reference/responses-streaming) + * for more information. + * + * @default false + */ + stream: boolean | null + } + /** @enum {string} */ + OpenAIModels: + | 'gpt-4' + | 'gpt-4-0314' + | 'gpt-4-0613' + | 'gpt-4-32k' + | 'gpt-4-32k-0314' + | 'gpt-4-32k-0613' + | 'gpt-4-0125-preview' + | 'gpt-4-turbo' + | 'gpt-4-turbo-2024-04-09' + | 'gpt-4-turbo-preview' + | 'gpt-4-1106-preview' + | 'gpt-4-vision-preview' + | 'gpt-3.5-turbo' + | 'gpt-3.5-turbo-16k' + | 'gpt-3.5-turbo-0301' + | 'gpt-3.5-turbo-0613' + | 'gpt-3.5-turbo-1106' + | 'gpt-3.5-turbo-0125' + | 'gpt-3.5-turbo-16k-0613' + | 'gpt-4.1' + | 'gpt-4.1-mini' + | 'gpt-4.1-nano' + | 'gpt-4.1-2025-04-14' + | 'gpt-4.1-mini-2025-04-14' + | 'gpt-4.1-nano-2025-04-14' + | 'o1' + | 'o1-mini' + | 'o1-preview' + | 'o1-pro' + | 'o1-2024-12-17' + | 'o1-preview-2024-09-12' + | 'o1-mini-2024-09-12' + | 'o1-pro-2025-03-19' + | 'o3' + | 'o3-mini' + | 'o3-2025-04-16' + | 'o3-mini-2025-01-31' + | 'o4-mini' + | 'o4-mini-2025-04-16' + | 'gpt-4o' + | 'gpt-4o-mini' + | 'gpt-4o-2024-11-20' + | 'gpt-4o-2024-08-06' + | 'gpt-4o-2024-05-13' + | 'gpt-4o-mini-2024-07-18' + | 'gpt-4o-audio-preview' + | 'gpt-4o-audio-preview-2024-10-01' + | 'gpt-4o-audio-preview-2024-12-17' + | 'gpt-4o-mini-audio-preview' + | 'gpt-4o-mini-audio-preview-2024-12-17' + | 'gpt-4o-search-preview' + | 'gpt-4o-mini-search-preview' + | 'gpt-4o-search-preview-2025-03-11' + | 'gpt-4o-mini-search-preview-2025-03-11' + | 'computer-use-preview' + | 'computer-use-preview-2025-03-11' + | 'chatgpt-4o-latest' + MoonvalleyTextToVideoInferenceParams: { + /** + * @description Height of the generated video in pixels + * @default 1080 + */ + height: number + /** + * @description Width of the generated video in pixels + * @default 1920 + */ + width: number + /** + * @description Number of frames to generate + * @default 64 + */ + num_frames: number + /** + * @description Frames per second of the generated video + * @default 24 + */ + fps: number + /** + * Format: float + * @description Guidance scale for generation control + * @default 10 + */ + guidance_scale: number + /** @description Random seed for generation (default: random) */ + seed?: number + /** + * @description Number of denoising steps + * @default 80 + */ + steps: number + /** + * @description Whether to use timestep transformation + * @default true + */ + use_timestep_transform: boolean + /** + * Format: float + * @description Shift value for generation control + * @default 3 + */ + shift_value: number + /** + * @description Whether to use guidance scheduling + * @default true + */ + use_guidance_schedule: boolean + /** + * @description Whether to add quality guidance + * @default true + */ + add_quality_guidance: boolean + /** + * Format: float + * @description CLIP value for generation control + * @default 3 + */ + clip_value: number + /** + * @description Whether to use negative prompts + * @default false + */ + use_negative_prompts: boolean + /** @description Negative prompt text */ + negative_prompt?: string + /** + * @description Number of warmup steps (calculated based on num_frames) + * @default 0 + */ + warmup_steps: number + /** + * @description Number of cooldown steps (calculated based on num_frames) + * @default 75 + */ + cooldown_steps: number + /** + * Format: float + * @description Caching coefficient for optimization + * @default 0.3 + */ + caching_coefficient: number + /** + * @description Number of caching warmup steps + * @default 3 + */ + caching_warmup: number + /** + * @description Number of caching cooldown steps + * @default 3 + */ + caching_cooldown: number + /** + * @description Index of the conditioning frame + * @default 0 + */ + conditioning_frame_index: number + } + MoonvalleyVideoToVideoInferenceParams: { + /** + * Format: float + * @description Guidance scale for generation control + * @default 15 + */ + guidance_scale: number + /** @description Random seed for generation (default: random) */ + seed?: number + /** + * @description Number of denoising steps + * @default 80 + */ + steps: number + /** + * @description Whether to use timestep transformation + * @default true + */ + use_timestep_transform: boolean + /** + * Format: float + * @description Shift value for generation control + * @default 3 + */ + shift_value: number + /** + * @description Whether to use guidance scheduling + * @default true + */ + use_guidance_schedule: boolean + /** + * @description Whether to add quality guidance + * @default true + */ + add_quality_guidance: boolean + /** + * Format: float + * @description CLIP value for generation control + * @default 3 + */ + clip_value: number + /** + * @description Whether to use negative prompts + * @default false + */ + use_negative_prompts: boolean + /** @description Negative prompt text */ + negative_prompt?: string + /** + * @description Number of warmup steps (calculated based on num_frames) + * @default 24 + */ + warmup_steps: number + /** + * @description Number of cooldown steps (calculated based on num_frames) + * @default 36 + */ + cooldown_steps: number + /** + * Format: float + * @description Caching coefficient for optimization + * @default 0.3 + */ + caching_coefficient: number + /** + * @description Number of caching warmup steps + * @default 3 + */ + caching_warmup: number + /** + * @description Number of caching cooldown steps + * @default 3 + */ + caching_cooldown: number + /** + * @description Index of the conditioning frame + * @default 0 + */ + conditioning_frame_index: number + } + MoonvalleyTextToImageRequest: { + prompt_text?: string + image_url?: string + inference_params?: components['schemas']['MoonvalleyTextToVideoInferenceParams'] + webhook_url?: string + } + MoonvalleyTextToVideoRequest: { + prompt_text?: string + image_url?: string + inference_params?: components['schemas']['MoonvalleyTextToVideoInferenceParams'] + webhook_url?: string + } + MoonvalleyVideoToVideoRequest: { + /** @description Describes the video to generate */ + prompt_text: string + /** @description Url to control video */ + video_url: string + /** + * @description Supported types for video control + * @enum {string} + */ + control_type: 'motion_control' | 'pose_control' + /** @description Parameters for video-to-video generation inference */ + inference_params?: components['schemas']['MoonvalleyVideoToVideoInferenceParams'] + /** @description Optional webhook URL for notifications */ + webhook_url?: string + } + MoonvalleyPromptResponse: { + id?: string + status?: string + prompt_text?: string + output_url?: string + inference_params?: Record + model_params?: Record + meta?: Record + frame_conditioning?: Record + error?: Record + } + MoonvalleyImageToVideoRequest: components['schemas']['MoonvalleyTextToVideoRequest'] & { + keyframes?: { + [key: string]: { + image_url?: string + } + } + } + MoonvalleyResizeVideoRequest: components['schemas']['MoonvalleyVideoToVideoRequest'] & { + frame_position?: number[] + frame_resolution?: number[] + scale?: number[] + } + MoonvalleyUploadFileRequest: { + /** Format: binary */ + file?: string + } + MoonvalleyUploadFileResponse: { + access_url?: string + } + /** @description GitHub release webhook payload based on official webhook documentation */ + GithubReleaseWebhook: { + /** + * @description The action performed on the release + * @enum {string} + */ + action: + | 'published' + | 'unpublished' + | 'created' + | 'edited' + | 'deleted' + | 'prereleased' + | 'released' + /** @description The release object */ + release: { + /** @description The ID of the release */ + id: number + /** @description The node ID of the release */ + node_id: string + /** @description The API URL of the release */ + url: string + /** @description The HTML URL of the release */ + html_url: string + /** @description The URL to the release assets */ + assets_url?: string + /** @description The URL to upload release assets */ + upload_url?: string + /** @description The tag name of the release */ + tag_name: string + /** @description The branch or commit the release was created from */ + target_commitish: string + /** @description The name of the release */ + name?: string | null + /** @description The release notes/body */ + body?: string | null + /** @description Whether the release is a draft */ + draft: boolean + /** @description Whether the release is a prerelease */ + prerelease: boolean + /** + * Format: date-time + * @description When the release was created + */ + created_at: string + /** + * Format: date-time + * @description When the release was published + */ + published_at?: string | null + author: components['schemas']['GithubUser'] + /** @description URL to the tarball */ + tarball_url: string + /** @description URL to the zipball */ + zipball_url: string + /** @description Array of release assets */ + assets: components['schemas']['GithubReleaseAsset'][] + } + repository: components['schemas']['GithubRepository'] + sender: components['schemas']['GithubUser'] + organization?: components['schemas']['GithubOrganization'] + installation?: components['schemas']['GithubInstallation'] + enterprise?: components['schemas']['GithubEnterprise'] + } + /** @description A GitHub user */ + GithubUser: { + /** @description The user's login name */ + login: string + /** @description The user's ID */ + id: number + /** @description The user's node ID */ + node_id: string + /** @description URL to the user's avatar */ + avatar_url: string + /** @description The user's gravatar ID */ + gravatar_id?: string | null + /** @description The API URL of the user */ + url: string + /** @description The HTML URL of the user */ + html_url: string + /** + * @description The type of user + * @enum {string} + */ + type: 'Bot' | 'User' | 'Organization' + /** @description Whether the user is a site admin */ + site_admin: boolean + } + /** @description A GitHub repository */ + GithubRepository: { + /** @description The repository ID */ + id: number + /** @description The repository node ID */ + node_id: string + /** @description The name of the repository */ + name: string + /** @description The full name of the repository (owner/repo) */ + full_name: string + /** @description Whether the repository is private */ + private: boolean + owner: components['schemas']['GithubUser'] + /** @description The HTML URL of the repository */ + html_url: string + /** @description The repository description */ + description?: string | null + /** @description Whether the repository is a fork */ + fork: boolean + /** @description The API URL of the repository */ + url: string + /** @description The clone URL of the repository */ + clone_url: string + /** @description The git URL of the repository */ + git_url: string + /** @description The SSH URL of the repository */ + ssh_url: string + /** @description The default branch of the repository */ + default_branch: string + /** + * Format: date-time + * @description When the repository was created + */ + created_at: string + /** + * Format: date-time + * @description When the repository was last updated + */ + updated_at: string + /** + * Format: date-time + * @description When the repository was last pushed to + */ + pushed_at: string + } + /** @description A GitHub release asset */ + GithubReleaseAsset: { + /** @description The asset ID */ + id: number + /** @description The asset node ID */ + node_id: string + /** @description The name of the asset */ + name: string + /** @description The label of the asset */ + label?: string | null + /** @description The content type of the asset */ + content_type: string + /** + * @description The state of the asset + * @enum {string} + */ + state: 'uploaded' | 'open' + /** @description The size of the asset in bytes */ + size: number + /** @description The number of downloads */ + download_count: number + /** + * Format: date-time + * @description When the asset was created + */ + created_at: string + /** + * Format: date-time + * @description When the asset was last updated + */ + updated_at: string + /** @description The browser download URL */ + browser_download_url: string + uploader: components['schemas']['GithubUser'] + } + /** @description A GitHub organization */ + GithubOrganization: { + /** @description The organization's login name */ + login: string + /** @description The organization ID */ + id: number + /** @description The organization node ID */ + node_id: string + /** @description The API URL of the organization */ + url: string + /** @description The API URL of the organization's repositories */ + repos_url: string + /** @description The API URL of the organization's events */ + events_url: string + /** @description The API URL of the organization's hooks */ + hooks_url: string + /** @description The API URL of the organization's issues */ + issues_url: string + /** @description The API URL of the organization's members */ + members_url: string + /** @description The API URL of the organization's public members */ + public_members_url: string + /** @description URL to the organization's avatar */ + avatar_url: string + /** @description The organization description */ + description?: string | null + } + /** @description A GitHub App installation */ + GithubInstallation: { + /** @description The installation ID */ + id: number + account: components['schemas']['GithubUser'] + /** + * @description Repository selection for the installation + * @enum {string} + */ + repository_selection: 'selected' | 'all' + /** @description The API URL for access tokens */ + access_tokens_url: string + /** @description The API URL for repositories */ + repositories_url: string + /** @description The HTML URL of the installation */ + html_url: string + /** @description The GitHub App ID */ + app_id: number + /** @description The target ID */ + target_id: number + /** @description The target type */ + target_type: string + /** @description The installation permissions */ + permissions: Record + /** @description The events the installation subscribes to */ + events: string[] + /** + * Format: date-time + * @description When the installation was created + */ + created_at: string + /** + * Format: date-time + * @description When the installation was last updated + */ + updated_at: string + /** @description The single file name if applicable */ + single_file_name?: string | null + } + /** @description A GitHub enterprise */ + GithubEnterprise: { + /** @description The enterprise ID */ + id: number + /** @description The enterprise slug */ + slug: string + /** @description The enterprise name */ + name: string + /** @description The enterprise node ID */ + node_id: string + /** @description URL to the enterprise avatar */ + avatar_url: string + /** @description The enterprise description */ + description?: string | null + /** @description The enterprise website URL */ + website_url?: string | null + /** @description The HTML URL of the enterprise */ + html_url: string + /** + * Format: date-time + * @description When the enterprise was created + */ + created_at: string + /** + * Format: date-time + * @description When the enterprise was last updated + */ + updated_at: string + } + ReleaseNote: { + /** @description Unique identifier for the release note */ + id: number + /** + * @description The project this release note belongs to + * @enum {string} + */ + project: 'comfyui' | 'comfyui_frontend' | 'desktop' + /** @description The version of the release */ + version: string + /** + * @description The attention level for this release + * @enum {string} + */ + attention: 'low' | 'medium' | 'high' + /** @description The content of the release note in markdown format */ + content: string + /** + * Format: date-time + * @description When the release note was published + */ + published_at: string + } + } + responses: never + parameters: { + /** @description Unique UUID for each request. */ + PixverseAiTraceId: string + } + requestBodies: never + headers: never + pathItems: never +} +export type $defs = Record +export interface operations { + getUser: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody?: never + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['User'] + } + } + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Not Found */ + 404: { + headers: { + [name: string]: unknown + } + content?: never + } + } + } + searchCustomers: { + parameters: { + query?: { + /** @description Email address to search for */ + email?: string + /** @description Customer name to search for */ + name?: string + /** @description Stripe customer ID to search for */ + stripe_id?: string + /** @description Metronome customer ID to search for\ */ + metronome_id?: string + /** @description Page number to retrieve */ + page?: number + /** @description Number of customers to return per page */ + limit?: number + } + header?: never + path?: never + cookie?: never + } + requestBody?: never + responses: { + /** @description Customers matching the search criteria */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': { + /** @description Current page number */ + page?: number + /** @description Number of customers per page */ + limit?: number + /** @description Total number of pages available */ + totalPages?: number + customers?: components['schemas']['Customer'][] + /** @description Total number of matching customers */ + total?: number + } + } + } + /** @description Invalid request parameters */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Forbidden - insufficient permissions */ + 403: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + createCustomer: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody?: never + responses: { + /** @description Customer already exists */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['Customer'] + } + } + /** @description Customer created successfully */ + 201: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['Customer'] + } + } + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + getAuthenticatedCustomer: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody?: never + responses: { + /** @description Customer details retrieved successfully */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['Customer'] + } + } + /** @description Unauthorized or invalid token */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Customer not found */ + 404: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + getCustomerById: { + parameters: { + query?: never + header?: never + path: { + customer_id: string + } + cookie?: never + } + requestBody?: never + responses: { + /** @description Customer details retrieved successfully */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': { + customer?: components['schemas']['Customer'] + } + } + } + /** @description Unauthorized or invalid token */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Customer not found */ + 404: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + listCustomerAPIKeys: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody?: never + responses: { + /** @description List of API keys */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': { + api_keys?: components['schemas']['APIKey'][] + } + } + } + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Customer not found */ + 404: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + createCustomerAPIKey: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['CreateAPIKeyRequest'] + } + } + responses: { + /** @description API key created */ + 201: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': { + api_key?: components['schemas']['APIKeyWithPlaintext'] + } + } + } + /** @description Bad request */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Customer or API key not found */ + 404: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + deleteCustomerAPIKey: { + parameters: { + query?: never + header?: never + path: { + api_key_id: string + } + cookie?: never + } + requestBody?: never + responses: { + /** @description API key deleted */ + 204: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Customer or API key not found */ + 404: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + InitiateCreditPurchase: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody: { + content: { + 'application/json': { + /** + * Format: int64 + * @description the amount of the checkout transaction in micro value + */ + amount_micros: number + /** @description the currency used in the checkout transaction */ + currency: string + } + } + } + responses: { + /** @description Customer Checkout created successfully */ + 201: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': { + /** @description the url to redirect the customer */ + checkout_url?: string + } + } + } + /** @description Bad request, invalid token or user already exists */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Unauthorized or invalid token */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + AccessBillingPortal: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody?: { + content: { + 'application/json': { + /** @description Optional URL to redirect the customer after they're done with the billing portal */ + return_url?: string + } + } + } + responses: { + /** @description Billing portal session created successfully */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': { + /** @description The URL to redirect the customer to the billing portal */ + billing_portal_url?: string + } + } + } + /** @description Bad request, invalid input */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Unauthorized or invalid token */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + GetCustomerUsage: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody?: never + responses: { + /** @description Successful response */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': { + /** @description The dashboard URL for the customer's usage */ + url?: string + } + } + } + /** @description Unauthorized or invalid token */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Customer not found */ + 404: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + GetCustomerBalance: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody?: never + responses: { + /** @description Customer balance retrieved successfully */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': { + /** + * Format: double + * @description The remaining balance in microamount (1/1,000,000 of the currency unit) + */ + amount_micros: number + /** @description The currency code (e.g., "usd") */ + currency: string + } + } + } + /** @description Unauthorized or invalid token */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Customer not found */ + 404: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + GetCustomerBalanceById: { + parameters: { + query?: never + header?: never + path: { + /** @description The ID of the customer whose balance to retrieve */ + customer_id: string + } + cookie?: never + } + requestBody?: never + responses: { + /** @description Customer balance retrieved successfully */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': { + /** + * Format: double + * @description The remaining balance in microamount (1/1,000,000 of the currency unit) + */ + amount_micros: number + /** @description The currency code (e.g., "usd") */ + currency: string + } + } + } + /** @description Bad request */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Unauthorized or invalid token */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Customer not found */ + 404: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + createCustomerStorageResource: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody: { + content: { + 'application/json': { + /** @description The desired name of the file (e.g., 'profile.jpg') */ + file_name: string + /** @description The content type of the file (e.g., 'image/png') */ + content_type?: string + /** @description The hash of the file. If provided, an existing file with the same hash may be returned. */ + file_hash?: string + } + } + } + responses: { + /** @description Signed URL generated successfully */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['CustomerStorageResourceResponse'] + } + } + /** @description Bad request */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + GetCustomerEventsById: { + parameters: { + query?: { + /** @description Page number of the nodes list */ + page?: number + /** @description Number of nodes to return per page */ + limit?: number + /** @description Event type to filter */ + filter?: string + } + header?: never + path: { + customer_id: string + } + cookie?: never + } + requestBody?: never + responses: { + /** @description A paginated list of nodes */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': { + /** @description Total number of events available */ + total?: number + events?: components['schemas']['AuditLog'][] + /** @description Current page number */ + page?: number + /** @description Maximum number of nodes per page */ + limit?: number + /** @description Total number of pages available */ + totalPages?: number + } + } + } + /** @description Invalid input, object invalid */ + 400: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Not found */ + 404: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + GetCustomerEvents: { + parameters: { + query?: { + /** @description Page number of the nodes list */ + page?: number + /** @description Number of nodes to return per page */ + limit?: number + /** @description Event type to filter */ + filter?: string + } + header?: never + path?: never + cookie?: never + } + requestBody?: never + responses: { + /** @description A paginated list of nodes */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': { + /** @description Total number of events available */ + total?: number + events?: components['schemas']['AuditLog'][] + /** @description Current page number */ + page?: number + /** @description Maximum number of nodes per page */ + limit?: number + /** @description Total number of pages available */ + totalPages?: number + } + } + } + /** @description Invalid input, object invalid */ + 400: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Not found */ + 404: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + getWorkflowResult: { + parameters: { + query?: never + header?: never + path: { + workflowResultId: string + } + cookie?: never + } + requestBody?: never + responses: { + /** @description Commit details */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ActionJobResult'] + } + } + /** @description Commit not found */ + 404: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + listPublishersForUser: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody?: never + responses: { + /** @description A list of publishers */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['Publisher'][] + } + } + /** @description Bad request, invalid input data */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + getPermissionOnPublisher: { + parameters: { + query?: never + header?: never + path: { + publisherId: string + } + cookie?: never + } + requestBody?: never + responses: { + /** @description A list of permissions */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': { + canEdit?: boolean + } + } + } + /** @description Bad request, invalid input data */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + validatePublisher: { + parameters: { + query: { + /** @description The publisher username to validate. */ + username: string + } + header?: never + path?: never + cookie?: never + } + requestBody?: never + responses: { + /** @description Username validation result */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': { + /** @description True if the username is available, false otherwise. */ + isAvailable?: boolean + } + } + } + /** @description Invalid input, such as missing username in the query. */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + listPublishers: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody?: never + responses: { + /** @description A list of publishers */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['Publisher'][] + } + } + /** @description Bad request, invalid input data */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + createPublisher: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['Publisher'] + } + } + responses: { + /** @description Publisher created successfully */ + 201: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['Publisher'] + } + } + /** @description Bad request, invalid input data */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Forbidden */ + 403: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + getPublisher: { + parameters: { + query?: never + header?: never + path: { + publisherId: string + } + cookie?: never + } + requestBody?: never + responses: { + /** @description Publisher retrieved successfully */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['Publisher'] + } + } + /** @description Publisher not found */ + 404: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + updatePublisher: { + parameters: { + query?: never + header?: never + path: { + publisherId: string + } + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['Publisher'] + } + } + responses: { + /** @description Publisher updated successfully */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['Publisher'] + } + } + /** @description Bad request, invalid input data */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Publisher not found */ + 404: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + deletePublisher: { + parameters: { + query?: never + header?: never + path: { + publisherId: string + } + cookie?: never + } + requestBody?: never + responses: { + /** @description Publisher deleted successfully */ + 204: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Publisher not found */ + 404: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + BanPublisher: { + parameters: { + query?: never + header?: never + path: { + publisherId: string + } + cookie?: never + } + requestBody?: never + responses: { + /** @description Publisher Banned Successfully */ + 204: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Forbidden */ + 403: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Publisher not found */ + 404: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + claimMyNode: { + parameters: { + query?: never + header?: never + path: { + publisherId: string + nodeId: string + } + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['ClaimMyNodeRequest'] + } + } + responses: { + /** @description Node claimed successfully */ + 204: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Bad request, invalid input data */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Forbidden - various authorization and permission issues + * Includes: + * - The authenticated user does not have permission to claim the node + * - The node is already claimed by another publisher + * - The GH_TOKEN is invalid + * - The repository is not owned by the authenticated GitHub user + * */ + 403: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Too many requests - GitHub API rate limit exceeded */ + 429: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Service unavailable - GitHub API is currently unavailable */ + 503: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + listNodesForPublisherV2: { + parameters: { + query?: { + /** @description Number of nodes to return per page */ + include_banned?: boolean + /** @description Page number of the nodes list */ + page?: number + /** @description Number of nodes to return per page */ + limit?: number + } + header?: never + path: { + publisherId: string + } + cookie?: never + } + requestBody?: never + responses: { + /** @description List of all nodes */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': { + /** @description Total number of nodes available */ + total?: number + nodes?: components['schemas']['Node'][] + /** @description Current page number */ + page?: number + /** @description Maximum number of nodes per page */ + limit?: number + /** @description Total number of pages available */ + totalPages?: number + } + } + } + /** @description Bad request, invalid input data. */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + listNodesForPublisher: { + parameters: { + query?: { + /** @description Number of nodes to return per page */ + include_banned?: boolean + } + header?: never + path: { + publisherId: string + } + cookie?: never + } + requestBody?: never + responses: { + /** @description List of all nodes */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['Node'][] + } + } + /** @description Bad request, invalid input data. */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + createNode: { + parameters: { + query?: never + header?: never + path: { + publisherId: string + } + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['Node'] + } + } + responses: { + /** @description Node created successfully */ + 201: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['Node'] + } + } + /** @description Bad request, invalid input data. */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + updateNode: { + parameters: { + query?: never + header?: never + path: { + publisherId: string + nodeId: string + } + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['Node'] + } + } + responses: { + /** @description Node updated successfully */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['Node'] + } + } + /** @description Bad request, invalid input data */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Forbidden */ + 403: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Node not found */ + 404: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + deleteNode: { + parameters: { + query?: never + header?: never + path: { + publisherId: string + nodeId: string + } + cookie?: never + } + requestBody?: never + responses: { + /** @description Node deleted successfully */ + 204: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Forbidden */ + 403: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Node not found */ + 404: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + getPermissionOnPublisherNodes: { + parameters: { + query?: never + header?: never + path: { + publisherId: string + nodeId: string + } + cookie?: never + } + requestBody?: never + responses: { + /** @description A list of permissions */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': { + canEdit?: boolean + } + } + } + /** @description Bad request, invalid input data */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + publishNodeVersion: { + parameters: { + query?: never + header?: never + path: { + publisherId: string + nodeId: string + } + cookie?: never + } + requestBody: { + content: { + 'application/json': { + personal_access_token: string + node_version: components['schemas']['NodeVersion'] + node: components['schemas']['Node'] + } + } + } + responses: { + /** @description New version published successfully */ + 201: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': { + /** @description The signed URL to upload the node version token. */ + signedUrl?: string + node_version?: components['schemas']['NodeVersion'] + } + } + } + /** @description Bad request, invalid input data. */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Forbidden */ + 403: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + updateNodeVersion: { + parameters: { + query?: never + header?: never + path: { + publisherId: string + nodeId: string + versionId: string + } + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['NodeVersionUpdateRequest'] + } + } + responses: { + /** @description Version updated successfully */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['NodeVersion'] + } + } + /** @description Bad request, invalid input data. */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Forbidden */ + 403: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Version not found */ + 404: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + deleteNodeVersion: { + parameters: { + query?: never + header?: never + path: { + publisherId: string + nodeId: string + versionId: string + } + cookie?: never + } + requestBody?: never + responses: { + /** @description Version unpublished (deleted) successfully */ + 204: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Version does not belong to the publisher */ + 403: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Version not found */ + 404: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['Error'] + } + } + /** @description Version not found */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + BanPublisherNode: { + parameters: { + query?: never + header?: never + path: { + publisherId: string + nodeId: string + } + cookie?: never + } + requestBody?: never + responses: { + /** @description Node Banned Successfully */ + 204: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Forbidden */ + 403: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Publisher or Node not found */ + 404: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + listPersonalAccessTokens: { + parameters: { + query?: never + header?: never + path: { + publisherId: string + } + cookie?: never + } + requestBody?: never + responses: { + /** @description List of all personal access tokens */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['PersonalAccessToken'][] + } + } + /** @description Forbidden */ + 403: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description No tokens found */ + 404: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + createPersonalAccessToken: { + parameters: { + query?: never + header?: never + path: { + publisherId: string + } + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['PersonalAccessToken'] + } + } + responses: { + /** @description Token created successfully */ + 201: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': { + /** @description The newly created personal access token. */ + token?: string + } + } + } + /** @description Bad request, invalid input data. */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Forbidden */ + 403: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + deletePersonalAccessToken: { + parameters: { + query?: never + header?: never + path: { + publisherId: string + tokenId: string + } + cookie?: never + } + requestBody?: never + responses: { + /** @description Token deleted successfully */ + 204: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Forbidden */ + 403: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Token not found */ + 404: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + searchNodes: { + parameters: { + query?: { + /** @description Page number of the nodes list */ + page?: number + /** @description Number of nodes to return per page */ + limit?: number + /** @description Keyword to search the nodes */ + search?: string + /** @description Keyword to search the nodes by repository URL */ + repository_url_search?: string + /** @description Keyword to search the nodes by comfy node name */ + comfy_node_search?: string + /** @description Filter nodes by supported operating systems */ + supported_os?: string + /** @description Filter nodes by supported accelerator */ + supported_accelerator?: string + /** @description Number of nodes to return per page */ + include_banned?: boolean + } + header?: never + path?: never + cookie?: never + } + requestBody?: never + responses: { + /** @description A paginated list of nodes */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': { + /** @description Total number of nodes available */ + total?: number + nodes?: components['schemas']['Node'][] + /** @description Current page number */ + page?: number + /** @description Maximum number of nodes per page */ + limit?: number + /** @description Total number of pages available */ + totalPages?: number + } + } + } + /** @description Invalid input, object invalid */ + 400: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Not found */ + 404: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + reindexNodes: { + parameters: { + query?: { + /** @description Maximum number of nodes to send to algolia at a time */ + max_batch?: number + } + header?: never + path?: never + cookie?: never + } + requestBody?: never + responses: { + /** @description Reindex completed successfully. */ + 200: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Bad request. */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + updateGithubStars: { + parameters: { + query?: { + /** @description Maximum number of nodes to update in one batch */ + max_batch?: number + } + header?: never + path?: never + cookie?: never + } + requestBody?: never + responses: { + /** @description Update GithubStars request triggered successfully */ + 200: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Bad request. */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + listAllNodes: { + parameters: { + query?: { + /** @description Page number of the nodes list */ + page?: number + /** @description Number of nodes to return per page */ + limit?: number + /** @description Filter nodes by supported operating systems */ + supported_os?: string + /** @description Filter nodes by supported accelerator */ + supported_accelerator?: string + /** @description Number of nodes to return per page */ + include_banned?: boolean + /** @description Retrieve nodes created or updated after this timestamp (ISO 8601 format) */ + timestamp?: string + /** @description Whether to fetch fresh result from database or use cached one if false */ + latest?: boolean + /** @description Database column to use as ascending ordering. Add `;desc` as suffix on each column for descending sort */ + sort?: string[] + /** @description node_id to use as filter */ + node_id?: string[] + /** @description Comfy UI version */ + comfyui_version?: string + /** @description The platform requesting the nodes */ + form_factor?: string + } + header?: never + path?: never + cookie?: never + } + requestBody?: never + responses: { + /** @description A paginated list of nodes */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': { + /** @description Total number of nodes available */ + total?: number + nodes?: components['schemas']['Node'][] + /** @description Current page number */ + page?: number + /** @description Maximum number of nodes per page */ + limit?: number + /** @description Total number of pages available */ + totalPages?: number + } + } + } + /** @description Invalid input, object invalid */ + 400: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Not found */ + 404: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + getNodeByComfyNodeName: { + parameters: { + query?: never + header?: never + path: { + /** @description The name of the ComfyUI node */ + comfyNodeName: string + } + cookie?: never + } + requestBody?: never + responses: { + /** @description Node details */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['Node'] + } + } + /** @description No node found containing the specified ComfyUI node name */ + 404: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + getNode: { + parameters: { + query?: { + /** @description Whether to include the translation or not */ + include_translations?: boolean + } + header?: never + path: { + nodeId: string + } + cookie?: never + } + requestBody?: never + responses: { + /** @description Node details */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['Node'] + } + } + /** @description Forbidden */ + 403: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Node not found */ + 404: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + postNodeReview: { + parameters: { + query: { + /** @description number of star given to the node version */ + star: number + } + header?: never + path: { + nodeId: string + } + cookie?: never + } + requestBody?: never + responses: { + /** @description Detailed information about a specific node */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['Node'] + } + } + /** @description Bad Request */ + 400: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Node version not found */ + 404: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['Error'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + installNode: { + parameters: { + query?: { + /** @description Specific version of the node to retrieve. If omitted, the latest version is returned. */ + version?: string + } + header?: never + path: { + /** @description The unique identifier of the node. */ + nodeId: string + } + cookie?: never + } + requestBody?: never + responses: { + /** @description Node data returned successfully. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['NodeVersion'] + } + } + /** @description Invalid input, such as a bad version format. */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Forbidden */ + 403: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Node not found. */ + 404: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + CreateNodeTranslations: { + parameters: { + query?: never + header?: never + path: { + /** @description The unique identifier of the node. */ + nodeId: string + } + cookie?: never + } + requestBody: { + content: { + 'application/json': { + data?: { + [key: string]: { + [key: string]: unknown + } + } + } + } + } + responses: { + /** @description Detailed information about a specific node */ + 201: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Bad Request */ + 400: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Node version not found */ + 404: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['Error'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + listNodeVersions: { + parameters: { + query?: { + statuses?: components['schemas']['NodeVersionStatus'][] + include_status_reason?: boolean + } + header?: never + path: { + nodeId: string + } + cookie?: never + } + requestBody?: never + responses: { + /** @description List of all node versions */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['NodeVersion'][] + } + } + /** @description Node banned */ + 403: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Node not found */ + 404: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['Error'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + getNodeVersion: { + parameters: { + query?: never + header?: never + path: { + nodeId: string + /** @description The version of the node. (Not a UUID). */ + versionId: string + } + cookie?: never + } + requestBody?: never + responses: { + /** @description Detailed information about a specific node version */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['NodeVersion'] + } + } + /** @description Node version not found */ + 404: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['Error'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + getBulkNodeVersions: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['BulkNodeVersionsRequest'] + } + } + responses: { + /** @description Successfully retrieved node versions */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['BulkNodeVersionsResponse'] + } + } + /** @description Bad request, invalid input */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + listAllNodeVersions: { + parameters: { + query?: { + nodeId?: string + statuses?: components['schemas']['NodeVersionStatus'][] + include_status_reason?: boolean + /** @description The page number to retrieve. */ + page?: number + /** @description The number of items to include per page. */ + pageSize?: number + /** @description search for status_reason, case insensitive */ + status_reason?: string + } + header?: never + path?: never + cookie?: never + } + requestBody?: never + responses: { + /** @description List of all node versions */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': { + /** @description Total number of node versions available */ + total?: number + versions?: components['schemas']['NodeVersion'][] + /** @description Current page number */ + page?: number + /** @description Maximum number of node versions per page. Maximum is 100. */ + pageSize?: number + /** @description Total number of pages available */ + totalPages?: number + } + } + } + /** @description Invalid input, object invalid */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Node banned */ + 403: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + adminCreateNode: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['Node'] + } + } + responses: { + /** @description Node created successfully */ + 201: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['Node'] + } + } + /** @description Bad request, invalid input data. */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Duplicate error. */ + 409: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + adminUpdateNode: { + parameters: { + query?: never + header?: never + path: { + nodeId: string + } + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['Node'] + } + } + responses: { + /** @description Node updated successfully */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['Node'] + } + } + /** @description Bad request, invalid input data. */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Forbidden */ + 403: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Node not found */ + 404: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + adminUpdateNodeVersion: { + parameters: { + query?: never + header?: never + path: { + nodeId: string + versionNumber: string + } + cookie?: never + } + requestBody: { + content: { + 'application/json': { + status?: components['schemas']['NodeVersionStatus'] + /** @description The reason for the status change. */ + status_reason?: string + /** @description Supported versions of ComfyUI frontend */ + supported_comfyui_frontend_version?: string + /** @description Supported versions of ComfyUI */ + supported_comfyui_version?: string + /** @description List of operating systems that this node supports */ + supported_os?: string[] + /** @description List of accelerators (e.g. CUDA, DirectML, ROCm) that this node supports */ + supported_accelerators?: string[] + } + } + } + responses: { + /** @description Version updated successfully */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['NodeVersion'] + } + } + /** @description Bad request, invalid input data. */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Forbidden */ + 403: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Version not found */ + 404: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + getReleaseNotes: { + parameters: { + query: { + /** @description The project to get release notes for */ + project: 'comfyui' | 'comfyui_frontend' | 'desktop' + /** @description The current version to filter release notes */ + current_version?: string + /** @description The locale for the release notes */ + locale?: 'en' | 'es' | 'fr' | 'ja' | 'ko' | 'ru' | 'zh' + /** @description The platform requesting the release notes */ + form_factor?: string + } + header?: never + path?: never + cookie?: never + } + requestBody?: never + responses: { + /** @description Release notes retrieved successfully */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ReleaseNote'][] + } + } + /** @description Bad request */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + processReleaseWebhook: { + parameters: { + query?: never + header: { + /** @description The name of the event that triggered the delivery */ + 'X-GitHub-Event': 'release' + /** @description A globally unique identifier (GUID) to identify the event */ + 'X-GitHub-Delivery': string + /** @description The unique identifier of the webhook */ + 'X-GitHub-Hook-ID': string + /** @description HMAC hex digest of the request body using SHA-256 hash function */ + 'X-Hub-Signature-256'?: string + /** @description The type of resource where the webhook was created */ + 'X-GitHub-Hook-Installation-Target-Type'?: string + /** @description The unique identifier of the resource where the webhook was created */ + 'X-GitHub-Hook-Installation-Target-ID'?: string + } + path?: never + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['GithubReleaseWebhook'] + } + } + responses: { + /** @description Webhook processed successfully */ + 200: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Bad request */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Validation failed or endpoint has been spammed */ + 422: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + securityScan: { + parameters: { + query?: { + minAge?: string + minSecurityScanAge?: string + maxNodes?: number + } + header?: never + path?: never + cookie?: never + } + requestBody?: never + responses: { + /** @description Scan completed successfully */ + 200: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Bad request, invalid input data. */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Forbidden */ + 403: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + ListComfyNodes: { + parameters: { + query?: { + /** @description The page number to retrieve. */ + page?: number + /** @description The number of items to include per page. */ + limit?: number + } + header?: never + path: { + nodeId: string + version: string + } + cookie?: never + } + requestBody?: never + responses: { + /** @description Comy Nodes obtained successfully */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': { + comfy_nodes?: components['schemas']['ComfyNode'][] + totalNumberOfPages?: number + } + } + } + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Forbidden */ + 403: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Version not found */ + 404: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + CreateComfyNodes: { + parameters: { + query?: never + header?: never + path: { + nodeId: string + version: string + } + cookie?: never + } + requestBody: { + content: { + 'application/json': { + success?: boolean + status?: string + reason?: string + cloud_build_info?: components['schemas']['ComfyNodeCloudBuildInfo'] + nodes?: { + [key: string]: components['schemas']['ComfyNode'] + } + } + } + } + responses: { + /** @description Comy Nodes created successfully */ + 204: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Forbidden */ + 403: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Version not found */ + 404: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Existing Comfy Nodes exists */ + 409: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + GetComfyNode: { + parameters: { + query?: never + header?: never + path: { + nodeId: string + version: string + comfyNodeName: string + } + cookie?: never + } + requestBody?: never + responses: { + /** @description Comy Nodes created successfully */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ComfyNode'] + } + } + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Forbidden */ + 403: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Version not found */ + 404: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + ComfyNodesBackfill: { + parameters: { + query?: { + max_node?: number + } + header?: never + path?: never + cookie?: never + } + requestBody?: never + responses: { + /** @description Backfill triggered */ + 204: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Bad request, invalid input data. */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Forbidden */ + 403: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + dummyProxy: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody?: { + content: { + 'application/json': { + message?: string + } + } + } + responses: { + /** @description Reindex completed successfully. */ + 200: { + headers: { + [name: string]: unknown + } + content?: never + } + } + } + minimaxVideoGeneration: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['MinimaxVideoGenerationRequest'] + } + } + responses: { + /** @description Successful response from Minimax proxy */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['MinimaxVideoGenerationResponse'] + } + } + /** @description Bad Request (invalid input to proxy) */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Payment Required */ + 402: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Rate limit exceeded (either from proxy or Minimax) */ + 429: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Internal Server Error (proxy or upstream issue) */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Bad Gateway (error communicating with Minimax) */ + 502: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Gateway Timeout (Minimax took too long to respond) */ + 504: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + getMinimaxVideoGeneration: { + parameters: { + query: { + /** @description The task ID to be queried */ + task_id: string + } + header?: never + path?: never + cookie?: never + } + requestBody?: never + responses: { + /** @description Successful response with task status */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['MinimaxTaskResultResponse'] + } + } + /** @description Bad Request (invalid input to proxy) */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Payment Required */ + 402: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Rate limit exceeded (either from proxy or Minimax) */ + 429: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Internal Server Error (proxy or upstream issue) */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Bad Gateway (error communicating with Minimax) */ + 502: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Gateway Timeout (Minimax took too long to respond) */ + 504: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + retrieveMinimaxFile: { + parameters: { + query: { + /** @description Unique identifier for the file, obtained from the generation response */ + file_id: number + } + header?: never + path?: never + cookie?: never + } + requestBody?: never + responses: { + /** @description Successful response with file download URL */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['MinimaxFileRetrieveResponse'] + } + } + /** @description Bad Request (invalid input to proxy) */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Payment Required */ + 402: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Rate limit exceeded (either from proxy or Minimax) */ + 429: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Internal Server Error (proxy or upstream issue) */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Bad Gateway (error communicating with Minimax) */ + 502: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Gateway Timeout (Minimax took too long to respond) */ + 504: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + ideogramGenerate: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['IdeogramGenerateRequest'] + } + } + responses: { + /** @description Successful response from Ideogram proxy */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['IdeogramGenerateResponse'] + } + } + /** @description Bad Request (invalid input to proxy) */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Payment Required */ + 402: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Rate limit exceeded (either from proxy or Ideogram) */ + 429: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Internal Server Error (proxy or upstream issue) */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Bad Gateway (error communicating with Ideogram) */ + 502: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Gateway Timeout (Ideogram took too long to respond) */ + 504: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + ideogramV3Generate: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** @description Parameters for Ideogram V3 image generation */ + requestBody: { + content: { + 'application/json': components['schemas']['IdeogramV3Request'] + } + } + responses: { + /** @description Successful response from Ideogram proxy */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['IdeogramGenerateResponse'] + } + } + /** @description Internal Server Error (proxy or upstream issue) */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + ideogramV3Edit: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** @description Parameters for Ideogram V3 image editing */ + requestBody: { + content: { + 'multipart/form-data': components['schemas']['IdeogramV3EditRequest'] + } + } + responses: { + /** @description Successful response from Ideogram proxy */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['IdeogramGenerateResponse'] + } + } + /** @description Bad Request (invalid input to proxy) */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Prompt or Initial Image failed the safety checks. */ + 422: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Rate limit exceeded (either from proxy or Ideogram) */ + 429: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Internal Server Error (proxy or upstream issue) */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + ideogramV3Remix: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody: { + content: { + 'multipart/form-data': components['schemas']['IdeogramV3RemixRequest'] + } + } + responses: { + /** @description Remix generated successfully */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['IdeogramV3IdeogramResponse'] + } + } + /** @description Bad Request */ + 400: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Forbidden */ + 403: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Unprocessable Entity */ + 422: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Too Many Requests */ + 429: { + headers: { + [name: string]: unknown + } + content?: never + } + } + } + ideogramV3Reframe: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody: { + content: { + 'multipart/form-data': components['schemas']['IdeogramV3ReframeRequest'] + } + } + responses: { + /** @description Reframed image successfully returned */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['IdeogramV3IdeogramResponse'] + } + } + /** @description Bad Request */ + 400: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Unprocessable Entity */ + 422: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Too Many Requests */ + 429: { + headers: { + [name: string]: unknown + } + content?: never + } + } + } + ideogramV3ReplaceBackground: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody: { + content: { + 'multipart/form-data': components['schemas']['IdeogramV3ReplaceBackgroundRequest'] + } + } + responses: { + /** @description Background replaced successfully */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['IdeogramV3IdeogramResponse'] + } + } + /** @description Bad Request */ + 400: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Unprocessable Entity */ + 422: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Too Many Requests */ + 429: { + headers: { + [name: string]: unknown + } + content?: never + } + } + } + klingQueryResourcePackages: { + parameters: { + query: { + start_time: number + end_time: number + resource_pack_name?: string + } + header?: never + path?: never + cookie?: never + } + requestBody?: never + responses: { + /** @description Successful response (Request successful) */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingResourcePackageResponse'] + } + } + /** @description Invalid request parameters */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Authentication failed */ + 401: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Unauthorized access to requested resource */ + 403: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Account exception or Rate limit exceeded */ + 429: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Service temporarily unavailable */ + 503: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Server timeout */ + 504: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + } + } + klingText2VideoQueryTaskList: { + parameters: { + query?: { + /** @description Page number */ + pageNum?: number + /** @description Data volume per page */ + pageSize?: number + } + header?: never + path?: never + cookie?: never + } + requestBody?: never + responses: { + /** @description Successful response (Request successful) */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingText2VideoResponse'] + } + } + /** @description Invalid request parameters */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Authentication failed */ + 401: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Unauthorized access to requested resource */ + 403: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Account exception or Rate limit exceeded */ + 429: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Service temporarily unavailable */ + 503: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Server timeout */ + 504: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + } + } + klingCreateVideoFromText: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** @description Create task for generating video from text */ + requestBody: { + content: { + 'application/json': components['schemas']['KlingText2VideoRequest'] + } + } + responses: { + /** @description Successful response (Request successful) */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingText2VideoResponse'] + } + } + /** @description Invalid request parameters */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Authentication failed */ + 401: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Unauthorized access to requested resource */ + 403: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Account exception or Rate limit exceeded */ + 429: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Service temporarily unavailable */ + 503: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Server timeout */ + 504: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + } + } + klingText2VideoQuerySingleTask: { + parameters: { + query?: never + header?: never + path: { + /** @description Task ID or external_task_id */ + id: string + } + cookie?: never + } + requestBody?: never + responses: { + /** @description Successful response (Request successful) */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingText2VideoResponse'] + } + } + /** @description Invalid request parameters */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Authentication failed */ + 401: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Unauthorized access to requested resource */ + 403: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Account exception or Rate limit exceeded */ + 429: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Service temporarily unavailable */ + 503: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Server timeout */ + 504: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + } + } + klingImage2VideoQueryTaskList: { + parameters: { + query?: { + /** @description Page number */ + pageNum?: number + /** @description Data volume per page */ + pageSize?: number + } + header?: never + path?: never + cookie?: never + } + requestBody?: never + responses: { + /** @description Successful response (Request successful) */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingImage2VideoResponse'] + } + } + /** @description Invalid request parameters */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Authentication failed */ + 401: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Unauthorized access to requested resource */ + 403: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Account exception or Rate limit exceeded */ + 429: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Service temporarily unavailable */ + 503: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Server timeout */ + 504: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + } + } + klingCreateVideoFromImage: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** @description Create task for generating video from image */ + requestBody: { + content: { + 'application/json': components['schemas']['KlingImage2VideoRequest'] + } + } + responses: { + /** @description Successful response (Request successful) */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingImage2VideoResponse'] + } + } + /** @description Invalid request parameters */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Authentication failed */ + 401: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Unauthorized access to requested resource */ + 403: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Account exception or Rate limit exceeded */ + 429: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Service temporarily unavailable */ + 503: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Server timeout */ + 504: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + } + } + klingImage2VideoQuerySingleTask: { + parameters: { + query?: never + header?: never + path: { + /** @description Task ID or external_task_id */ + id: string + } + cookie?: never + } + requestBody?: never + responses: { + /** @description Successful response (Request successful) */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingImage2VideoResponse'] + } + } + /** @description Invalid request parameters */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Authentication failed */ + 401: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Unauthorized access to requested resource */ + 403: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Account exception or Rate limit exceeded */ + 429: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Service temporarily unavailable */ + 503: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Server timeout */ + 504: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + } + } + klingVideoExtendQueryTaskList: { + parameters: { + query?: { + /** @description Page number */ + pageNum?: number + /** @description Data volume per page */ + pageSize?: number + } + header?: never + path?: never + cookie?: never + } + requestBody?: never + responses: { + /** @description Successful response (Request successful) */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingVideoExtendResponse'] + } + } + /** @description Invalid request parameters */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Authentication failed */ + 401: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Unauthorized access to requested resource */ + 403: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Account exception or Rate limit exceeded */ + 429: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Service temporarily unavailable */ + 503: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Server timeout */ + 504: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + } + } + klingExtendVideo: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** @description Create task for extending video duration */ + requestBody: { + content: { + 'application/json': components['schemas']['KlingVideoExtendRequest'] + } + } + responses: { + /** @description Successful response (Request successful) */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingVideoExtendResponse'] + } + } + /** @description Invalid request parameters */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Authentication failed */ + 401: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Unauthorized access to requested resource */ + 403: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Account exception or Rate limit exceeded */ + 429: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Service temporarily unavailable */ + 503: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Server timeout */ + 504: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + } + } + klingVideoExtendQuerySingleTask: { + parameters: { + query?: never + header?: never + path: { + /** @description Task ID */ + id: string + } + cookie?: never + } + requestBody?: never + responses: { + /** @description Successful response (Request successful) */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingVideoExtendResponse'] + } + } + /** @description Invalid request parameters */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Authentication failed */ + 401: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Unauthorized access to requested resource */ + 403: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Account exception or Rate limit exceeded */ + 429: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Service temporarily unavailable */ + 503: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Server timeout */ + 504: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + } + } + klingLipSyncQueryTaskList: { + parameters: { + query?: { + /** @description Page number */ + pageNum?: number + /** @description Data volume per page */ + pageSize?: number + } + header?: never + path?: never + cookie?: never + } + requestBody?: never + responses: { + /** @description Successful response (Request successful) */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingLipSyncResponse'] + } + } + /** @description Invalid request parameters */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Authentication failed */ + 401: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Unauthorized access to requested resource */ + 403: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Account exception or Rate limit exceeded */ + 429: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Service temporarily unavailable */ + 503: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Server timeout */ + 504: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + } + } + klingCreateLipSyncVideo: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** @description Create task for generating lip-sync video */ + requestBody: { + content: { + 'application/json': components['schemas']['KlingLipSyncRequest'] + } + } + responses: { + /** @description Successful response (Request successful) */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingLipSyncResponse'] + } + } + /** @description Invalid request parameters */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Authentication failed */ + 401: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Unauthorized access to requested resource */ + 403: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Account exception or Rate limit exceeded */ + 429: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Service temporarily unavailable */ + 503: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Server timeout */ + 504: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + } + } + klingLipSyncQuerySingleTask: { + parameters: { + query?: never + header?: never + path: { + /** @description Task ID or external_task_id */ + id: string + } + cookie?: never + } + requestBody?: never + responses: { + /** @description Successful response (Request successful) */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingLipSyncResponse'] + } + } + /** @description Invalid request parameters */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Authentication failed */ + 401: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Unauthorized access to requested resource */ + 403: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Account exception or Rate limit exceeded */ + 429: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Service temporarily unavailable */ + 503: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Server timeout */ + 504: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + } + } + klingVideoEffectsQueryTaskList: { + parameters: { + query?: { + /** @description Page number */ + pageNum?: number + /** @description Data volume per page */ + pageSize?: number + } + header?: never + path?: never + cookie?: never + } + requestBody?: never + responses: { + /** @description Successful response (Request successful) */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingVideoEffectsResponse'] + } + } + /** @description Invalid request parameters */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Authentication failed */ + 401: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Unauthorized access to requested resource */ + 403: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Account exception or Rate limit exceeded */ + 429: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Service temporarily unavailable */ + 503: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Server timeout */ + 504: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + } + } + klingCreateVideoEffects: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** @description Create task for generating video with effects */ + requestBody: { + content: { + 'application/json': components['schemas']['KlingVideoEffectsRequest'] + } + } + responses: { + /** @description Successful response (Request successful) */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingVideoEffectsResponse'] + } + } + /** @description Invalid request parameters */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Authentication failed */ + 401: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Unauthorized access to requested resource */ + 403: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Account exception or Rate limit exceeded */ + 429: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Service temporarily unavailable */ + 503: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Server timeout */ + 504: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + } + } + klingVideoEffectsQuerySingleTask: { + parameters: { + query?: never + header?: never + path: { + /** @description Task ID or external_task_id */ + id: string + } + cookie?: never + } + requestBody?: never + responses: { + /** @description Successful response (Request successful) */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingVideoEffectsResponse'] + } + } + /** @description Invalid request parameters */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Authentication failed */ + 401: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Unauthorized access to requested resource */ + 403: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Account exception or Rate limit exceeded */ + 429: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Service temporarily unavailable */ + 503: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Server timeout */ + 504: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + } + } + klingImageGenerationsQueryTaskList: { + parameters: { + query?: { + /** @description Page number */ + pageNum?: number + /** @description Data volume per page */ + pageSize?: number + } + header?: never + path?: never + cookie?: never + } + requestBody?: never + responses: { + /** @description Successful response (Request successful) */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingImageGenerationsResponse'] + } + } + /** @description Invalid request parameters */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Authentication failed */ + 401: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Unauthorized access to requested resource */ + 403: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Account exception or Rate limit exceeded */ + 429: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Service temporarily unavailable */ + 503: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Server timeout */ + 504: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + } + } + klingCreateImageGeneration: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** @description Create task for generating images */ + requestBody: { + content: { + 'application/json': components['schemas']['KlingImageGenerationsRequest'] + } + } + responses: { + /** @description Successful response (Request successful) */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingImageGenerationsResponse'] + } + } + /** @description Invalid request parameters */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Authentication failed */ + 401: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Unauthorized access to requested resource */ + 403: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Account exception or Rate limit exceeded */ + 429: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Service temporarily unavailable */ + 503: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Server timeout */ + 504: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + } + } + klingImageGenerationsQuerySingleTask: { + parameters: { + query?: never + header?: never + path: { + /** @description Task ID */ + id: string + } + cookie?: never + } + requestBody?: never + responses: { + /** @description Successful response (Request successful) */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingImageGenerationsResponse'] + } + } + /** @description Invalid request parameters */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Authentication failed */ + 401: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Unauthorized access to requested resource */ + 403: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Account exception or Rate limit exceeded */ + 429: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Service temporarily unavailable */ + 503: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Server timeout */ + 504: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + } + } + klingVirtualTryOnQueryTaskList: { + parameters: { + query?: { + /** @description Page number */ + pageNum?: number + /** @description Data volume per page */ + pageSize?: number + } + header?: never + path?: never + cookie?: never + } + requestBody?: never + responses: { + /** @description Successful response (Request successful) */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingVirtualTryOnResponse'] + } + } + /** @description Invalid request parameters */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Authentication failed */ + 401: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Unauthorized access to requested resource */ + 403: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Account exception or Rate limit exceeded */ + 429: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Service temporarily unavailable */ + 503: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Server timeout */ + 504: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + } + } + klingCreateVirtualTryOn: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** @description Create task for virtual try-on of clothing on human images */ + requestBody: { + content: { + 'application/json': components['schemas']['KlingVirtualTryOnRequest'] + } + } + responses: { + /** @description Successful response (Request successful) */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingVirtualTryOnResponse'] + } + } + /** @description Invalid request parameters */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Authentication failed */ + 401: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Unauthorized access to requested resource */ + 403: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Account exception or Rate limit exceeded */ + 429: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Service temporarily unavailable */ + 503: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Server timeout */ + 504: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + } + } + klingVirtualTryOnQuerySingleTask: { + parameters: { + query?: never + header?: never + path: { + /** @description Task ID */ + id: string + } + cookie?: never + } + requestBody?: never + responses: { + /** @description Successful response (Request successful) */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingVirtualTryOnResponse'] + } + } + /** @description Invalid request parameters */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Authentication failed */ + 401: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Unauthorized access to requested resource */ + 403: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Account exception or Rate limit exceeded */ + 429: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Service temporarily unavailable */ + 503: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + /** @description Server timeout */ + 504: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['KlingErrorResponse'] + } + } + } + } + bflFluxKontextProGenerate: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['BFLFluxKontextProGenerateRequest'] + } + } + responses: { + /** @description Successful response from BFL Flux Kontext Pro proxy */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['BFLFluxKontextProGenerateResponse'] + } + } + /** @description Bad Request (invalid input to proxy) */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Payment Required */ + 402: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Rate limit exceeded (either from proxy or BFL) */ + 429: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Internal Server Error (proxy or upstream issue) */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Bad Gateway (error communicating with BFL) */ + 502: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Gateway Timeout (BFL took too long to respond) */ + 504: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + bflFluxKontextMaxGenerate: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['BFLFluxKontextMaxGenerateRequest'] + } + } + responses: { + /** @description Successful response from BFL Flux Kontext Max proxy */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['BFLFluxKontextMaxGenerateResponse'] + } + } + /** @description Bad Request (invalid input to proxy) */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Payment Required */ + 402: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Rate limit exceeded (either from proxy or BFL) */ + 429: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Internal Server Error (proxy or upstream issue) */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Bad Gateway (error communicating with BFL) */ + 502: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Gateway Timeout (BFL took too long to respond) */ + 504: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + bflFluxPro1_1Generate: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['BFLFluxPro1_1GenerateRequest'] + } + } + responses: { + /** @description Successful response from BFL Flux Pro proxy */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['BFLFluxPro1_1GenerateResponse'] + } + } + /** @description Bad Request (invalid input to proxy) */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Payment Required */ + 402: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Rate limit exceeded (either from proxy or BFL) */ + 429: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Internal Server Error (proxy or upstream issue) */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Bad Gateway (error communicating with BFL) */ + 502: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Gateway Timeout (BFL took too long to respond) */ + 504: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + bflFluxProGenerate: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['BFLFluxProGenerateRequest'] + } + } + responses: { + /** @description Successful response from BFL Flux Pro proxy */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['BFLFluxProGenerateResponse'] + } + } + /** @description Bad Request (invalid input to proxy) */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Payment Required */ + 402: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Rate limit exceeded (either from proxy or BFL) */ + 429: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Internal Server Error (proxy or upstream issue) */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Bad Gateway (error communicating with BFL) */ + 502: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Gateway Timeout (BFL took too long to respond) */ + 504: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + BFLExpand_v1_flux_pro_1_0_expand_post: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['BFLFluxProExpandInputs'] + } + } + responses: { + /** @description Successful Response */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': + | components['schemas']['BFLAsyncResponse'] + | components['schemas']['BFLAsyncWebhookResponse'] + } + } + /** @description Validation Error */ + 422: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['BFLHTTPValidationError'] + } + } + } + } + BFLFill_v1_flux_pro_1_0_fill_post: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['BFLFluxProFillInputs'] + } + } + responses: { + /** @description Successful Response */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': + | components['schemas']['BFLAsyncResponse'] + | components['schemas']['BFLAsyncWebhookResponse'] + } + } + /** @description Validation Error */ + 422: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['BFLHTTPValidationError'] + } + } + } + } + BFLPro_canny_v1_flux_pro_1_0_canny_post: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['BFLCannyInputs'] + } + } + responses: { + /** @description Successful Response */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': + | components['schemas']['BFLAsyncResponse'] + | components['schemas']['BFLAsyncWebhookResponse'] + } + } + /** @description Validation Error */ + 422: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['BFLHTTPValidationError'] + } + } + } + } + BFLPro_depth_v1_flux_pro_1_0_depth_post: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['BFLDepthInputs'] + } + } + responses: { + /** @description Successful Response */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': + | components['schemas']['BFLAsyncResponse'] + | components['schemas']['BFLAsyncWebhookResponse'] + } + } + /** @description Validation Error */ + 422: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['BFLHTTPValidationError'] + } + } + } + } + lumaCreateGeneration: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** @description The generation request object */ + requestBody: { + content: { + 'application/json': components['schemas']['LumaGenerationRequest'] + } + } + responses: { + /** @description Generation created */ + 201: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['LumaGeneration'] + } + } + /** @description Error */ + default: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['LumaError'] + } + } + } + } + lumaGetGeneration: { + parameters: { + query?: never + header?: never + path: { + /** @description The ID of the generation */ + id: string + } + cookie?: never + } + requestBody?: never + responses: { + /** @description Generation found */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['LumaGeneration'] + } + } + /** @description Error */ + default: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['LumaError'] + } + } + } + } + lumaGenerateImage: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + /** @description The image generation request object */ + requestBody: { + content: { + 'application/json': components['schemas']['LumaImageGenerationRequest'] + } + } + responses: { + /** @description Image generated */ + 201: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['LumaGeneration'] + } + } + /** @description Error */ + default: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['LumaError'] + } + } + } + } + PixverseGenerateTextVideo: { + parameters: { + query?: never + header: { + /** @description Unique UUID for each request. */ + 'Ai-trace-id': components['parameters']['PixverseAiTraceId'] + } + path?: never + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['PixverseTextVideoRequest'] + } + } + responses: { + /** @description Success */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['PixverseVideoResponse'] + } + } + /** @description Bad Request (invalid input to proxy) */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Payment Required */ + 402: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Rate limit exceeded */ + 429: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Internal Server Error (proxy or upstream issue) */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + PixverseGenerateImageVideo: { + parameters: { + query?: never + header: { + /** @description Unique UUID for each request. */ + 'Ai-trace-id': components['parameters']['PixverseAiTraceId'] + } + path?: never + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['PixverseImageVideoRequest'] + } + } + responses: { + /** @description Success */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['PixverseVideoResponse'] + } + } + /** @description Bad Request (invalid input to proxy) */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Payment Required */ + 402: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Rate limit exceeded */ + 429: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Internal Server Error (proxy or upstream issue) */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + PixverseGenerateTransitionVideo: { + parameters: { + query?: never + header: { + /** @description Unique UUID for each request. */ + 'Ai-trace-id': components['parameters']['PixverseAiTraceId'] + } + path?: never + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['PixverseTransitionVideoRequest'] + } + } + responses: { + /** @description Success */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['PixverseVideoResponse'] + } + } + /** @description Bad Request (invalid input to proxy) */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Payment Required */ + 402: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Rate limit exceeded */ + 429: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Internal Server Error (proxy or upstream issue) */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + PixverseUploadImage: { + parameters: { + query?: never + header: { + /** @description Unique UUID for each request. */ + 'Ai-trace-id': components['parameters']['PixverseAiTraceId'] + } + path?: never + cookie?: never + } + requestBody: { + content: { + 'multipart/form-data': { + /** Format: binary */ + image?: string + } + } + } + responses: { + /** @description Image uploaded */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['PixverseImageUploadResponse'] + } + } + /** @description Bad Request (invalid input to proxy) */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Payment Required */ + 402: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Rate limit exceeded */ + 429: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Internal Server Error (proxy or upstream issue) */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + PixverseGetVideoResult: { + parameters: { + query?: never + header: { + /** @description Unique UUID for each request. */ + 'Ai-trace-id': components['parameters']['PixverseAiTraceId'] + } + path: { + id: number + } + cookie?: never + } + requestBody?: never + responses: { + /** @description Result fetched */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['PixverseVideoResultResponse'] + } + } + } + } + metronomeZeroBalance: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody: { + content: { + 'application/json': { + /** @description the id of the webhook */ + id: string + /** @description the type of the webhook */ + type: string + properties: { + /** @description the metronome customer id */ + customer_id?: string + /** @description the customer remaining balance */ + remaining_balance?: number + } + } + } + } + responses: { + /** @description Webhook processed successfully */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['IdeogramGenerateResponse'] + } + } + /** @description Bad Request */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Internal Server Error (proxy or upstream issue) */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + StripeInvoiceStatus: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['StripeEvent'] + } + } + responses: { + /** @description Webhook processed successfully */ + 200: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Bad Request */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Internal Server Error (proxy or upstream issue) */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + recraftImageGeneration: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['RecraftImageGenerationRequest'] + } + } + responses: { + /** @description Successful response from Recraft proxy */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['RecraftImageGenerationResponse'] + } + } + /** @description Bad Request (invalid input to proxy) */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Payment Required */ + 402: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Rate limit exceeded */ + 429: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Internal Server Error (proxy or upstream issue) */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Bad Gateway (error communicating with Recraft) */ + 502: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Gateway Timeout (Recraft took too long to respond) */ + 504: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + recraftVectorize: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody: { + content: { + 'multipart/form-data': { + /** + * Format: binary + * @description Image file to process + */ + file: string + } + } + } + responses: { + /** @description Background removed successfully */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['RecraftImageGenerationResponse'] + } + } + /** @description Bad request - Invalid parameters or file */ + 400: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Unauthorized - Invalid or missing API token */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + } + } + recraftCrispUpscale: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody: { + content: { + 'multipart/form-data': { + /** + * Format: binary + * @description Image file to process + */ + file: string + } + } + } + responses: { + /** @description Background removed successfully */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['RecraftImageGenerationResponse'] + } + } + /** @description Bad request - Invalid parameters or file */ + 400: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Unauthorized - Invalid or missing API token */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + } + } + recraftRemoveBackground: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody: { + content: { + 'multipart/form-data': { + /** + * Format: binary + * @description Image file to process + */ + file: string + } + } + } + responses: { + /** @description Background removed successfully */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': { + image?: { + /** + * Format: uri + * @description URL of the processed image + */ + url?: string + } + } + } + } + /** @description Bad request - Invalid parameters or file */ + 400: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Unauthorized - Invalid or missing API token */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + } + } + RecraftImageToImage: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody?: { + content: { + 'multipart/form-data': components['schemas']['RecraftImageToImageRequest'] + } + } + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['RecraftGenerateImageResponse'] + } + } + } + } + RecraftInpaintImage: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody?: { + content: { + 'multipart/form-data': components['schemas']['RecraftTransformImageWithMaskRequest'] + } + } + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['RecraftGenerateImageResponse'] + } + } + } + } + RecraftReplaceBackground: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody?: { + content: { + 'multipart/form-data': components['schemas']['RecraftTransformImageWithMaskRequest'] + } + } + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['RecraftGenerateImageResponse'] + } + } + } + } + RecraftCreativeUpscale: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody?: { + content: { + 'multipart/form-data': components['schemas']['RecraftProcessImageRequest'] + } + } + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['RecraftProcessImageResponse'] + } + } + } + } + runwayImageToVideo: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['RunwayImageToVideoRequest'] + } + } + responses: { + /** @description Successful response */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['RunwayImageToVideoResponse'] + } + } + /** @description Bad request */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Payment Required */ + 402: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + runwayGetTaskStatus: { + parameters: { + query?: never + header?: never + path: { + /** @description ID of the task to check */ + task_id: string + } + cookie?: never + } + requestBody?: never + responses: { + /** @description Successful response */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['RunwayTaskStatusResponse'] + } + } + /** @description Bad request */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Payment Required */ + 402: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Task not found */ + 404: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + runwayTextToImage: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['RunwayTextToImageRequest'] + } + } + responses: { + /** @description Successful response */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['RunwayTextToImageResponse'] + } + } + /** @description Bad request */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Payment Required */ + 402: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + veoGenerate: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['Veo2GenVidRequest'] + } + } + responses: { + /** @description Video generation successful */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['Veo2GenVidResponse'] + } + } + /** @description Bad request */ + 400: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Forbidden */ + 403: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content?: never + } + } + } + veoPoll: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['Veo2GenVidPollRequest'] + } + } + responses: { + /** @description Operation status and result */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['Veo2GenVidPollResponse'] + } + } + /** @description Bad request */ + 400: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Operation not found */ + 404: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Internal error */ + 500: { + headers: { + [name: string]: unknown + } + content?: never + } + } + } + veoGenerateNew: { + parameters: { + query?: never + header?: never + path: { + /** @description The ID of the model to use for generation */ + modelId: string + } + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['VeoGenVidRequest'] + } + } + responses: { + /** @description Video generation successful */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['VeoGenVidResponse'] + } + } + /** @description Bad request */ + 400: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Forbidden */ + 403: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content?: never + } + } + } + veoPollNew: { + parameters: { + query?: never + header?: never + path: { + /** @description The ID of the model to use for generation */ + modelId: string + } + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['VeoGenVidPollRequest'] + } + } + responses: { + /** @description Operation status and result */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['VeoGenVidPollResponse'] + } + } + /** @description Bad request */ + 400: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Operation not found */ + 404: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Internal error */ + 500: { + headers: { + [name: string]: unknown + } + content?: never + } + } + } + createOpenAIResponse: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['OpenAICreateResponse'] + } + } + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['OpenAIResponse'] + 'text/event-stream': components['schemas']['OpenAIResponseStreamEvent'] + } + } + } + } + getOpenAIResponse: { + parameters: { + query?: { + /** @description Additional fields to include in the response. See the `include` + * parameter for Response creation above for more information. + * */ + include?: components['schemas']['Includable'][] + } + header?: never + path: { + /** @description The ID of the response to retrieve. */ + id: string + } + cookie?: never + } + requestBody?: never + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['OpenAIResponse'] + } + } + } + } + openAIGenerateImage: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['OpenAIImageGenerationRequest'] + } + } + responses: { + /** @description Image generated successfully */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['OpenAIImageGenerationResponse'] + } + } + /** @description Bad request */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Payment Required */ + 402: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + openAIEditImage: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody: { + content: { + 'multipart/form-data': components['schemas']['OpenAIImageEditRequest'] + } + } + responses: { + /** @description Image edited successfully */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['OpenAIImageGenerationResponse'] + } + } + /** @description Bad request */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Payment Required */ + 402: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ErrorResponse'] + } + } + } + } + PikaGenerate_pikadditions_generate_pikadditions_post: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody: { + content: { + 'multipart/form-data': components['schemas']['PikaBody_generate_pikadditions_generate_pikadditions_post'] + } + } + responses: { + /** @description Successful Response */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['PikaGenerateResponse'] + } + } + /** @description Validation Error */ + 422: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['PikaHTTPValidationError'] + } + } + } + } + PikaGenerate_pikaswaps_generate_pikaswaps_post: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody: { + content: { + 'multipart/form-data': components['schemas']['PikaBody_generate_pikaswaps_generate_pikaswaps_post'] + } + } + responses: { + /** @description Successful Response */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['PikaGenerateResponse'] + } + } + /** @description Validation Error */ + 422: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['PikaHTTPValidationError'] + } + } + } + } + PikaGenerate_pikaffects_generate_pikaffects_post: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody: { + content: { + 'multipart/form-data': components['schemas']['PikaBody_generate_pikaffects_generate_pikaffects_post'] + } + } + responses: { + /** @description Successful Response */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['PikaGenerateResponse'] + } + } + /** @description Validation Error */ + 422: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['PikaHTTPValidationError'] + } + } + } + } + PikaGenerate_2_2_t2v_generate_2_2_t2v_post: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody: { + content: { + 'application/x-www-form-urlencoded': components['schemas']['PikaBody_generate_2_2_t2v_generate_2_2_t2v_post'] + } + } + responses: { + /** @description Successful Response */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['PikaGenerateResponse'] + } + } + /** @description Validation Error */ + 422: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['PikaHTTPValidationError'] + } + } + } + } + PikaGenerate_2_2_keyframe_generate_2_2_pikaframes_post: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody: { + content: { + 'multipart/form-data': components['schemas']['PikaBody_generate_2_2_keyframe_generate_2_2_pikaframes_post'] + } + } + responses: { + /** @description Successful Response */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['PikaGenerateResponse'] + } + } + /** @description Validation Error */ + 422: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['PikaHTTPValidationError'] + } + } + } + } + PikaGenerate_2_2_c2v_generate_2_2_pikascenes_post: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody: { + content: { + 'multipart/form-data': components['schemas']['PikaBody_generate_2_2_c2v_generate_2_2_pikascenes_post'] + } + } + responses: { + /** @description Successful Response */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['PikaGenerateResponse'] + } + } + /** @description Validation Error */ + 422: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['PikaHTTPValidationError'] + } + } + } + } + PikaGenerate_2_2_i2v_generate_2_2_i2v_post: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody: { + content: { + 'multipart/form-data': components['schemas']['PikaBody_generate_2_2_i2v_generate_2_2_i2v_post'] + } + } + responses: { + /** @description Successful Response */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['PikaGenerateResponse'] + } + } + /** @description Validation Error */ + 422: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['PikaHTTPValidationError'] + } + } + } + } + PikaGet_video_videos__video_id__get: { + parameters: { + query?: never + header?: never + path: { + video_id: string + } + cookie?: never + } + requestBody?: never + responses: { + /** @description Successful Response */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['PikaVideoResponse'] + } + } + /** @description Validation Error */ + 422: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['PikaHTTPValidationError'] + } + } + } + } + StabilityImageGenrationUltra: { + parameters: { + query?: never + header: { + authorization: string + 'content-type': string + accept?: 'image/*' | 'application/json' + 'stability-client-id'?: components['schemas']['StabilityStabilityClientID'] + 'stability-client-user-id'?: components['schemas']['StabilityStabilityClientUserID'] + 'stability-client-version'?: components['schemas']['StabilityStabilityClientVersion'] + } + path?: never + cookie?: never + } + requestBody?: { + content: { + 'multipart/form-data': { + /** @description What you wish to see in the output image. A strong, descriptive prompt that clearly defines elements, colors, and subjects will lead to better results. To control the weight of a given word use the format `(word:weight)`, where `word` is the word you'd like to control the weight of and `weight` is a value between 0 and 1. For example: `The sky was a crisp (blue:0.3) and (green:0.8)` would convey a sky that was blue and green, but more green than blue. */ + prompt: string + /** @description A blurb of text describing what you **do not** wish to see in the output image. This is an advanced feature. */ + negative_prompt?: string + /** + * @description Controls the aspect ratio of the generated image. + * @default 1:1 + * @enum {string} + */ + aspect_ratio?: + | '21:9' + | '16:9' + | '3:2' + | '5:4' + | '1:1' + | '4:5' + | '2:3' + | '9:16' + | '9:21' + /** + * @description A specific value that is used to guide the 'randomness' of the generation. (Omit this parameter or pass `0` to use a random seed.) + * @default 0 + */ + seed?: number + /** + * @description Dictates the `content-type` of the generated image. + * @default png + * @enum {string} + */ + output_format?: 'jpeg' | 'png' | 'webp' + /** + * Format: binary + * @description The image to use as the starting point for the generation. > **Important:** The `strength` parameter is required when `image` is provided. Supported Formats: - jpeg - png - webp Validation Rules: - Width must be between 64 and 16,384 pixels - Height must be between 64 and 16,384 pixels - Total pixel count must be at least 4,096 pixels + * @example ./some/image.png + */ + image?: string + /** + * @description Guides the image model towards a particular style. + * @enum {string} + */ + style_preset?: + | 'enhance' + | 'anime' + | 'photographic' + | 'digital-art' + | 'comic-book' + | 'fantasy-art' + | 'line-art' + | 'analog-film' + | 'neon-punk' + | 'isometric' + | 'low-poly' + | 'origami' + | 'modeling-compound' + | 'cinematic' + | '3d-model' + | 'pixel-art' + | 'tile-texture' + /** @description Sometimes referred to as _denoising_, this parameter controls how much influence the + * `image` parameter has on the generated image. A value of 0 would yield an image that + * is identical to the input. A value of 1 would be as if you passed in no image at all. + * + * > **Important:** This parameter is required when `image` is provided. */ + strength?: number + } + } + } + responses: { + /** @description Generation was successful. */ + 200: { + headers: { + /** @description A unique identifier for this request. */ + 'x-request-id'?: string + /** @description The format of the generated image. + * To receive the bytes of the image directly, specify `image/*` in the accept header. To receive the bytes base64 encoded inside of a JSON payload, specify `application/json`. */ + 'content-type'?: string + /** @description Indicates the reason the generation finished. - `SUCCESS` = successful generation. - `CONTENT_FILTERED` = successful generation, however the output violated our content moderation policy and has been blurred as a result. > **NOTE:** This header is absent on JSON encoded responses because it is present in the body as `finish_reason`. */ + 'finish-reason'?: 'SUCCESS' | 'CONTENT_FILTERED' + /** + * @description The seed used as random noise for this generation. > **NOTE:** This header is absent on JSON encoded responses because it is present in the body as `seed`. + * @example 343940597 + */ + seed?: string + [name: string]: unknown + } + content: { + /** @example The bytes of the generated jpeg */ + 'image/jpeg': string + 'application/json; type=image/jpeg': { + /** + * @description The generated image, encoded to base64. + * @example AAAAIGZ0eXBpc29tAAACAGlzb21pc28yYXZjMW1... + */ + image: string + /** + * @description The seed used as random noise for this generation. + * @default 0 + * @example 343940597 + */ + seed: number + /** + * @description The reason the generation finished. - `SUCCESS` = successful generation. - `CONTENT_FILTERED` = successful generation, however the output violated our content moderation policy and has been blurred as a result. + * @example SUCCESS + * @enum {string} + */ + finish_reason: 'SUCCESS' | 'CONTENT_FILTERED' + } + /** @example The bytes of the generated png */ + 'image/png': string + 'application/json; type=image/png': { + /** + * @description The generated image, encoded to base64. + * @example AAAAIGZ0eXBpc29tAAACAGlzb21pc28yYXZjMW1... + */ + image: string + /** + * @description The seed used as random noise for this generation. + * @default 0 + * @example 343940597 + */ + seed: number + /** + * @description The reason the generation finished. - `SUCCESS` = successful generation. - `CONTENT_FILTERED` = successful generation, however the output violated our content moderation policy and has been blurred as a result. + * @example SUCCESS + * @enum {string} + */ + finish_reason: 'SUCCESS' | 'CONTENT_FILTERED' + } + /** @example The bytes of the generated webp */ + 'image/webp': string + 'application/json; type=image/webp': { + /** + * @description The generated image, encoded to base64. + * @example AAAAIGZ0eXBpc29tAAACAGlzb21pc28yYXZjMW1... + */ + image: string + /** + * @description The seed used as random noise for this generation. + * @default 0 + * @example 343940597 + */ + seed: number + /** + * @description The reason the generation finished. - `SUCCESS` = successful generation. - `CONTENT_FILTERED` = successful generation, however the output violated our content moderation policy and has been blurred as a result. + * @example SUCCESS + * @enum {string} + */ + finish_reason: 'SUCCESS' | 'CONTENT_FILTERED' + } + } + } + /** @description Invalid parameter(s), see the `errors` field for details. */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': { + /** + * @description A unique identifier associated with this error. Please include this in any [support tickets](https://kb.stability.ai/knowledge-base/kb-tickets/new) you file, as it will greatly assist us in diagnosing the root cause of the problem. + * @example a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4 + */ + id: string + /** + * @description Short-hand name for an error, useful for discriminating between errors with the same status code. + * @example bad_request + */ + name: string + /** + * @description One or more error messages indicating what went wrong. + * @example [ + * "some-field: is required" + * ] + */ + errors: string[] + } + } + } + /** @description Your request was flagged by our content moderation system. */ + 403: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['StabilityContentModerationResponse'] + } + } + /** @description Your request was larger than 10MiB. */ + 413: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': { + /** + * @description A unique identifier associated with this error. Please include this in any [support tickets](https://kb.stability.ai/knowledge-base/kb-tickets/new) you file, as it will greatly assist us in diagnosing the root cause of the problem. + * @example a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4 + */ + id: string + /** + * @description Short-hand name for an error, useful for discriminating between errors with the same status code. + * @example bad_request + */ + name: string + /** + * @description One or more error messages indicating what went wrong. + * @example [ + * "some-field: is required" + * ] + */ + errors: string[] + } + } + } + /** @description Your request was well-formed, but rejected. See the `errors` field for details. */ + 422: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': { + /** + * @description A unique identifier associated with this error. Please include this in any [support tickets](https://kb.stability.ai/knowledge-base/kb-tickets/new) you file, as it will greatly assist us in diagnosing the root cause of the problem. + * @example a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4 + */ + id: string + /** + * @description Short-hand name for an error, useful for discriminating between errors with the same status code. + * @example bad_request + */ + name: string + /** + * @description One or more error messages indicating what went wrong. + * @example [ + * "some-field: is required" + * ] + */ + errors: string[] + } + } + } + /** @description You have made more than 150 requests in 10 seconds. */ + 429: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': { + /** + * @description A unique identifier associated with this error. Please include this in any [support tickets](https://kb.stability.ai/knowledge-base/kb-tickets/new) you file, as it will greatly assist us in diagnosing the root cause of the problem. + * @example a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4 + */ + id: string + /** + * @description Short-hand name for an error, useful for discriminating between errors with the same status code. + * @example bad_request + */ + name: string + /** + * @description One or more error messages indicating what went wrong. + * @example [ + * "some-field: is required" + * ] + */ + errors: string[] + } + } + } + /** @description An internal error occurred. If the problem persists [contact support](https://kb.stability.ai/knowledge-base/kb-tickets/new). */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': { + /** + * @description A unique identifier associated with this error. Please include this in any [support tickets](https://kb.stability.ai/knowledge-base/kb-tickets/new) you file, as it will greatly assist us in diagnosing the root cause of the problem. + * @example a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4 + */ + id: string + /** + * @description Short-hand name for an error, useful for discriminating between errors with the same status code. + * @example bad_request + */ + name: string + /** + * @description One or more error messages indicating what went wrong. + * @example [ + * "some-field: is required" + * ] + */ + errors: string[] + } + } + } + } + } + StabilityImageGenrationSD3: { + parameters: { + query?: never + header: { + authorization: string + 'content-type': string + accept?: 'image/*' | 'application/json' + 'stability-client-id'?: components['schemas']['StabilityStabilityClientID'] + 'stability-client-user-id'?: components['schemas']['StabilityStabilityClientUserID'] + 'stability-client-version'?: components['schemas']['StabilityStabilityClientVersion'] + } + path?: never + cookie?: never + } + requestBody?: { + content: { + 'multipart/form-data': components['schemas']['StabilityImageGenerationSD3_Request'] + } + } + responses: { + /** @description Generation was successful. */ + 200: { + headers: { + /** @description A unique identifier for this request. */ + 'x-request-id'?: string + /** @description The format of the generated image. + * + * To receive the bytes of the image directly, specify `image/*` in the accept header. To receive the bytes base64 encoded inside of a JSON payload, specify `application/json`. */ + 'content-type'?: string + /** @description Indicates the reason the generation finished. + * + * - `SUCCESS` = successful generation. + * - `CONTENT_FILTERED` = successful generation, however the output violated our content moderation + * policy and has been blurred as a result. + * + * > **NOTE:** This header is absent on JSON encoded responses because it is present in the body as `finish_reason`. */ + 'finish-reason'?: 'SUCCESS' | 'CONTENT_FILTERED' + /** + * @description The seed used as random noise for this generation. + * + * > **NOTE:** This header is absent on JSON encoded responses because it is present in the body as `seed`. + * @example 343940597 + */ + seed?: string + [name: string]: unknown + } + content: { + /** @example The bytes of the generated png */ + 'image/png': string + 'application/json; type=image/png': components['schemas']['StabilityImageGenrationSD3_Response_200'] + /** @example The bytes of the generated jpeg */ + 'image/jpeg': string + 'application/json; type=image/jpeg': components['schemas']['StabilityImageGenrationSD3_Response_200'] + } + } + /** @description Invalid parameter(s), see the `errors` field for details. */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['StabilityImageGenrationSD3_Response_400'] + } + } + /** @description Your request was flagged by our content moderation system. */ + 403: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['StabilityContentModerationResponse'] + } + } + /** @description Your request was larger than 10MiB. */ + 413: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['StabilityImageGenrationSD3_Response_413'] + } + } + /** @description Your request was well-formed, but rejected. See the `errors` field for details. */ + 422: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['StabilityImageGenrationSD3_Response_422'] + } + } + /** @description You have made more than 150 requests in 10 seconds. */ + 429: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['StabilityImageGenrationSD3_Response_429'] + } + } + /** @description An internal error occurred. If the problem persists [contact support](https://kb.stability.ai/knowledge-base/kb-tickets/new). */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['StabilityImageGenrationSD3_Response_500'] + } + } + } + } + StabilityImageGenrationUpscaleConservative: { + parameters: { + query?: never + header: { + authorization: string + 'content-type': string + accept?: 'image/*' | 'application/json' + 'stability-client-id'?: components['schemas']['StabilityStabilityClientID'] + 'stability-client-user-id'?: components['schemas']['StabilityStabilityClientUserID'] + 'stability-client-version'?: components['schemas']['StabilityStabilityClientVersion'] + } + path?: never + cookie?: never + } + requestBody?: { + content: { + 'multipart/form-data': components['schemas']['StabilityImageGenrationUpscaleConservative_Request'] + } + } + responses: { + /** @description Upscale was successful. */ + 200: { + headers: { + /** @description A unique identifier for this request. */ + 'x-request-id'?: string + /** @description The format of the generated image. + * + * To receive the bytes of the image directly, specify `image/*` in the accept header. To receive the bytes base64 encoded inside of a JSON payload, specify `application/json`. */ + 'content-type'?: string + /** @description Indicates the reason the generation finished. + * + * - `SUCCESS` = successful generation. + * - `CONTENT_FILTERED` = successful generation, however the output violated our content moderation + * policy and has been blurred as a result. + * + * > **NOTE:** This header is absent on JSON encoded responses because it is present in the body as `finish_reason`. */ + 'finish-reason'?: 'SUCCESS' | 'CONTENT_FILTERED' + /** + * @description The seed used as random noise for this generation. + * + * > **NOTE:** This header is absent on JSON encoded responses because it is present in the body as `seed`. + * @example 343940597 + */ + seed?: string + [name: string]: unknown + } + content: { + /** @example The bytes of the generated jpeg */ + 'image/jpeg': string + 'application/json; type=image/jpeg': components['schemas']['StabilityImageGenrationUpscaleConservative_Response_200'] + /** @example The bytes of the generated png */ + 'image/png': string + 'application/json; type=image/png': components['schemas']['StabilityImageGenrationUpscaleConservative_Response_200'] + /** @example The bytes of the generated webp */ + 'image/webp': string + 'application/json; type=image/webp': components['schemas']['StabilityImageGenrationUpscaleConservative_Response_200'] + } + } + /** @description Invalid parameter(s), see the `errors` field for details. */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['StabilityImageGenrationUpscaleConservative_Response_400'] + } + } + /** @description Your request was flagged by our content moderation system. */ + 403: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['StabilityContentModerationResponse'] + } + } + /** @description Your request was larger than 10MiB. */ + 413: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['StabilityImageGenrationUpscaleConservative_Response_413'] + } + } + /** @description Your request was well-formed, but rejected. See the `errors` field for details. */ + 422: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['StabilityImageGenrationUpscaleConservative_Response_422'] + } + } + /** @description You have made more than 150 requests in 10 seconds. */ + 429: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['StabilityImageGenrationUpscaleConservative_Response_429'] + } + } + /** @description An internal error occurred. If the problem persists [contact support](https://kb.stability.ai/knowledge-base/kb-tickets/new). */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['StabilityImageGenrationUpscaleConservative_Response_500'] + } + } + } + } + StabilityImageGenrationUpscaleCreative: { + parameters: { + query?: never + header: { + authorization: string + 'content-type': string + 'stability-client-id'?: components['schemas']['StabilityStabilityClientID'] + 'stability-client-user-id'?: components['schemas']['StabilityStabilityClientUserID'] + 'stability-client-version'?: components['schemas']['StabilityStabilityClientVersion'] + } + path?: never + cookie?: never + } + requestBody?: { + content: { + 'multipart/form-data': components['schemas']['StabilityImageGenrationUpscaleCreative_Request'] + } + } + responses: { + /** @description Upscale was started. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['StabilityImageGenrationUpscaleCreative_Response_200'] + } + } + /** @description Invalid parameter(s), see the `errors` field for details. */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['StabilityImageGenrationUpscaleCreative_Response_400'] + } + } + /** @description Your request was flagged by our content moderation system. */ + 403: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['StabilityContentModerationResponse'] + } + } + /** @description Your request was larger than 10MiB. */ + 413: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['StabilityImageGenrationUpscaleCreative_Response_413'] + } + } + /** @description Your request was well-formed, but rejected. See the `errors` field for details. */ + 422: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['StabilityImageGenrationUpscaleCreative_Response_422'] + } + } + /** @description You have made more than 150 requests in 10 seconds. */ + 429: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['StabilityImageGenrationUpscaleCreative_Response_429'] + } + } + /** @description An internal error occurred. If the problem persists [contact support](https://kb.stability.ai/knowledge-base/kb-tickets/new). */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['StabilityImageGenrationUpscaleCreative_Response_500'] + } + } + } + } + StabilityImageGenerationUpscaleFast: { + parameters: { + query?: never + header: { + authorization: string + 'content-type': string + accept?: 'image/*' | 'application/json' + 'stability-client-id'?: components['schemas']['StabilityStabilityClientID'] + 'stability-client-user-id'?: components['schemas']['StabilityStabilityClientUserID'] + 'stability-client-version'?: components['schemas']['StabilityStabilityClientVersion'] + } + path?: never + cookie?: never + } + requestBody?: { + content: { + 'multipart/form-data': components['schemas']['StabilityImageGenrationUpscaleFast_Request'] + } + } + responses: { + /** @description Upscale was successful. */ + 200: { + headers: { + /** @description A unique identifier for this request. */ + 'x-request-id'?: string + /** @description The format of the generated image. + * + * To receive the bytes of the image directly, specify `image/*` in the accept header. To receive the bytes base64 encoded inside of a JSON payload, specify `application/json`. */ + 'content-type'?: string + /** @description Indicates the reason the generation finished. + * + * - `SUCCESS` = successful generation. + * - `CONTENT_FILTERED` = successful generation, however the output violated our content moderation + * policy and has been blurred as a result. + * + * > **NOTE:** This header is absent on JSON encoded responses because it is present in the body as `finish_reason`. */ + 'finish-reason'?: 'SUCCESS' | 'CONTENT_FILTERED' + /** + * @description The seed used as random noise for this generation. + * + * > **NOTE:** This header is absent on JSON encoded responses because it is present in the body as `seed`. + * @example 343940597 + */ + seed?: string + [name: string]: unknown + } + content: { + /** @example The bytes of the generated jpeg */ + 'image/jpeg': string + 'application/json; type=image/jpeg': components['schemas']['StabilityImageGenrationUpscaleFast_Response_200'] + /** @example The bytes of the generated png */ + 'image/png': string + 'application/json; type=image/png': components['schemas']['StabilityImageGenrationUpscaleFast_Response_200'] + /** @example The bytes of the generated webp */ + 'image/webp': string + 'application/json; type=image/webp': components['schemas']['StabilityImageGenrationUpscaleFast_Response_200'] + } + } + /** @description Invalid parameter(s), see the `errors` field for details. */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['StabilityImageGenrationUpscaleFast_Response_400'] + } + } + /** @description Your request was flagged by our content moderation system. */ + 403: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['StabilityContentModerationResponse'] + } + } + /** @description Your request was larger than 10MiB. */ + 413: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['StabilityImageGenrationUpscaleFast_Response_413'] + } + } + /** @description Your request was well-formed, but rejected. See the `errors` field for details. */ + 422: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['StabilityImageGenrationUpscaleFast_Response_422'] + } + } + /** @description You have made more than 150 requests in 10 seconds. */ + 429: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['StabilityImageGenrationUpscaleFast_Response_429'] + } + } + /** @description An internal error occurred. If the problem persists [contact support](https://kb.stability.ai/knowledge-base/kb-tickets/new). */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['StabilityImageGenrationUpscaleFast_Response_500'] + } + } + } + } + StabilityGetResult: { + parameters: { + query?: never + header?: { + /** @description Set to image/* to receive image bytes. */ + Accept?: string + } + path: { + /** @description The ID of the generation result to retrieve. */ + id: string + } + cookie?: never + } + requestBody?: never + responses: { + /** @description The generated image as JPEG bytes. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'image/jpeg': string + 'application/json; type=image/jpeg': { + /** + * @description The generated image, encoded to base64. + * @example AAAAAIGZ0eXBpc29tAAACAGlzb21pc28yYXZjMW1... + */ + image: string + /** + * @description The seed used as random noise for this generation. + * @default 0 + * @example 343940597 + */ + seed: number + /** + * @description The reason the generation finished. + * + * - `SUCCESS` = successful generation. + * - `CONTENT_FILTERED` = successful generation, however the output violated our content moderation + * policy and has been blurred as a result. + * @example SUCCESS + * @enum {string} + */ + finish_reason: 'SUCCESS' | 'CONTENT_FILTERED' + } + /** @example The bytes of the generated png */ + 'image/png': string + 'application/json; type=image/png': { + /** + * @description The generated image, encoded to base64. + * @example AAAAAIGZ0eXBpc29tAAACAGlzb21pc28yYXZjMW1... + */ + image: string + /** + * @description The seed used as random noise for this generation. + * @default 0 + * @example 343940597 + */ + seed: number + /** + * @description The reason the generation finished. + * + * - `SUCCESS` = successful generation. + * - `CONTENT_FILTERED` = successful generation, however the output violated our content moderation + * policy and has been blurred as a result. + * @example SUCCESS + * @enum {string} + */ + finish_reason: 'SUCCESS' | 'CONTENT_FILTERED' + } + /** @example The bytes of the generated webp */ + 'image/webp': string + 'application/json; type=image/webp': { + /** + * @description The generated image, encoded to base64. + * @example AAAAAIGZ0eXBpc29tAAACAGlzb21pc28yYXZjMW1... + */ + image: string + /** + * @description The seed used as random noise for this generation. + * @default 0 + * @example 343940597 + */ + seed: number + /** + * @description The reason the generation finished. + * + * - `SUCCESS` = successful generation. + * - `CONTENT_FILTERED` = successful generation, however the output violated our content moderation + * policy and has been blurred as a result. + * @example SUCCESS + * @enum {string} + */ + finish_reason: 'SUCCESS' | 'CONTENT_FILTERED' + } + } + } + /** @description The generation is still in progress. */ + 202: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['StabilityGetResultResponse_202'] + } + } + /** @description Invalid result ID. */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['StabilityError'] + } + } + /** @description Result not found. */ + 404: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['StabilityError'] + } + } + /** @description An internal error occurred. If the problem persists [contact support](https://kb.stability.ai/knowledge-base/kb-tickets/new). */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['StabilityError'] + } + } + } + } + GeminiGenerateContent: { + parameters: { + query?: never + header?: never + path: { + /** @description Full resource name of the model. */ + model: string + } + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['GeminiGenerateContentRequest'] + } + } + responses: { + /** @description Generated content response. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['GeminiGenerateContentResponse'] + } + } + /** @description Bad Request */ + 400: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Forbidden */ + 403: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Not Found */ + 404: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Internal Server Error */ + 500: { + headers: { + [name: string]: unknown + } + content?: never + } + } + } + ImagenGenerateImages: { + parameters: { + query?: never + header?: never + path: { + /** @description image generation model */ + model: + | 'imagen-3.0-generate-002' + | 'imagen-3.0-generate-001' + | 'imagen-3.0-fast-generate-001' + | 'imagegeneration@006' + | 'imagegeneration@005' + | 'imagegeneration@002' + } + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['ImagenGenerateImageRequest'] + } + } + responses: { + /** @description Successful image generation */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['ImagenGenerateImageResponse'] + } + } + /** @description Client error */ + '4XX': { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Server error */ + '5XX': { + headers: { + [name: string]: unknown + } + content?: never + } + } + } + tripoGetTask: { + parameters: { + query?: never + header?: never + path: { + task_id: string + } + cookie?: never + } + requestBody?: never + responses: { + /** @description Request successful */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': { + code: components['schemas']['TripoResponseSuccessCode'] + data: components['schemas']['TripoTask'] + } + } + } + /** @description Invalid request parameters */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['TripoErrorResponse'] + } + } + /** @description Authentication failed */ + 401: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['TripoErrorResponse'] + } + } + /** @description Unauthorized access to requested resource */ + 403: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['TripoErrorResponse'] + } + } + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['TripoErrorResponse'] + } + } + /** @description Account exception or Rate limit exceeded */ + 429: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['TripoErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['TripoErrorResponse'] + } + } + /** @description Service temporarily unavailable */ + 503: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['TripoErrorResponse'] + } + } + /** @description Server timeout */ + 504: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['TripoErrorResponse'] + } + } + } + } + tripoUploadFile: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody?: { + content: { + 'multipart/form-data': { + /** Format: binary */ + file: string + } + } + } + responses: { + /** @description Request successful */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': { + code: components['schemas']['TripoResponseSuccessCode'] + data: { + image_token: string + } + } + } + } + /** @description Invalid request parameters */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['TripoErrorResponse'] + } + } + /** @description Authentication failed */ + 401: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['TripoErrorResponse'] + } + } + /** @description Unauthorized access to requested resource */ + 403: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['TripoErrorResponse'] + } + } + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['TripoErrorResponse'] + } + } + /** @description Account exception or Rate limit exceeded */ + 429: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['TripoErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['TripoErrorResponse'] + } + } + /** @description Service temporarily unavailable */ + 503: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['TripoErrorResponse'] + } + } + /** @description Server timeout */ + 504: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['TripoErrorResponse'] + } + } + } + } + tripoCreateTask: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody?: { + content: { + 'application/json': + | { + type: components['schemas']['TripoTextToModel'] + prompt: string + negative_prompt?: string + model_version?: components['schemas']['TripoModelVersion'] + face_limit?: number + /** @default true */ + texture?: boolean + /** @default true */ + pbr?: boolean + text_seed?: number + model_seed?: number + texture_seed?: number + /** @default standard */ + texture_quality?: components['schemas']['TripoTextureQuality'] + style?: components['schemas']['TripoModelStyle'] + /** @default false */ + auto_size?: boolean + /** @default false */ + quad?: boolean + } + | { + type: components['schemas']['TripoImageToModel'] + file: { + type: string + file_token: string + } + model_version?: components['schemas']['TripoModelVersion'] + face_limit?: number + /** @default true */ + texture?: boolean + /** @default true */ + pbr?: boolean + model_seed?: number + texture_seed?: number + /** @default standard */ + texture_quality?: components['schemas']['TripoTextureQuality'] + /** @default original_image */ + texture_alignment?: components['schemas']['TripoTextureAlignment'] + style?: components['schemas']['TripoModelStyle'] + /** @default false */ + auto_size?: boolean + /** @default default */ + orientation?: components['schemas']['TripoOrientation'] + /** @default false */ + quad?: boolean + } + | { + type: components['schemas']['TripoMultiviewToModel'] + files: { + type: string + file_token: string + }[] + mode?: components['schemas']['TripoMultiviewMode'] + model_version?: components['schemas']['TripoModelVersion'] + /** @default false */ + orthographic_projection?: boolean + face_limit?: number + /** @default true */ + texture?: boolean + /** @default true */ + pbr?: boolean + model_seed?: number + texture_seed?: number + /** @default standard */ + texture_quality?: components['schemas']['TripoTextureQuality'] + /** @default original_image */ + texture_alignment?: components['schemas']['TripoTextureAlignment'] + /** @default false */ + auto_size?: boolean + /** @default default */ + orientation?: components['schemas']['TripoOrientation'] + /** @default false */ + quad?: boolean + } + | { + type: components['schemas']['TripoTypeTextureModel'] + /** @default true */ + texture?: boolean + /** @default true */ + pbr?: boolean + model_seed?: number + texture_seed?: number + texture_quality?: components['schemas']['TripoTextureQuality'] + /** @default original_image */ + texture_alignment?: components['schemas']['TripoTextureAlignment'] + original_model_task_id: string + } + | { + type: components['schemas']['TripoTypeRefineModel'] + draft_model_task_id: string + } + | { + type: components['schemas']['TripoTypeAnimatePrerigcheck'] + original_model_task_id: string + } + | { + type: components['schemas']['TripoTypeAnimateRig'] + original_model_task_id: string + /** @default glb */ + out_format?: components['schemas']['TripoStandardFormat'] + topology?: components['schemas']['TripoTopology'] + /** @default tripo */ + spec?: components['schemas']['TripoSpec'] + } + | { + type: components['schemas']['TripoTypeAnimateRetarget'] + original_model_task_id: string + /** @default glb */ + out_format?: components['schemas']['TripoStandardFormat'] + animation: components['schemas']['TripoAnimation'] + /** @default true */ + bake_animation?: boolean + } + | { + type: components['schemas']['TripoTypeStylizeModel'] + style: components['schemas']['TripoStylizeOptions'] + original_model_task_id: string + /** @default 80 */ + block_size?: number + } + | { + type: components['schemas']['TripoTypeConvertModel'] + format: components['schemas']['TripoConvertFormat'] + original_model_task_id: string + /** @default false */ + quad?: boolean + /** @default false */ + force_symmetry?: boolean + /** @default 10000 */ + face_limit?: number + /** @default false */ + flatten_bottom?: boolean + /** @default 0.01 */ + flatten_bottom_threshold?: number + /** @default 4096 */ + texture_size?: number + /** @default JPEG */ + texture_format?: components['schemas']['TripoTextureFormat'] + /** @default false */ + pivot_to_center_bottom?: boolean + } + } + } + responses: { + /** @description Request successful */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['TripoSuccessTask'] + } + } + /** @description Invalid request parameters */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['TripoErrorResponse'] + } + } + /** @description Authentication failed */ + 401: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['TripoErrorResponse'] + } + } + /** @description Unauthorized access to requested resource */ + 403: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['TripoErrorResponse'] + } + } + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['TripoErrorResponse'] + } + } + /** @description Account exception or Rate limit exceeded */ + 429: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['TripoErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['TripoErrorResponse'] + } + } + /** @description Service temporarily unavailable */ + 503: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['TripoErrorResponse'] + } + } + /** @description Server timeout */ + 504: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['TripoErrorResponse'] + } + } + } + } + tripoGetBalance: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody?: never + responses: { + /** @description Request successful */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': { + code: components['schemas']['TripoResponseSuccessCode'] + data: components['schemas']['TripoBalance'] + } + } + } + /** @description Invalid request parameters */ + 400: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['TripoErrorResponse'] + } + } + /** @description Authentication failed */ + 401: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['TripoErrorResponse'] + } + } + /** @description Unauthorized access to requested resource */ + 403: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['TripoErrorResponse'] + } + } + /** @description Resource not found */ + 404: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['TripoErrorResponse'] + } + } + /** @description Account exception or Rate limit exceeded */ + 429: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['TripoErrorResponse'] + } + } + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['TripoErrorResponse'] + } + } + /** @description Service temporarily unavailable */ + 503: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['TripoErrorResponse'] + } + } + /** @description Server timeout */ + 504: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['TripoErrorResponse'] + } + } + } + } + rodinGenerate3DAsset: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody: { + content: { + 'multipart/form-data': components['schemas']['Rodin3DGenerateRequest'] + } + } + responses: { + /** @description 3D generate Task submitted successfully. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['Rodin3DGenerateResponse'] + } + } + /** @description Bad Request */ + 400: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Forbidden */ + 403: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Not Found */ + 404: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Internal Server Error */ + 500: { + headers: { + [name: string]: unknown + } + content?: never + } + } + } + rodinCheckStatus: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody: { + content: { + 'multipart/form-data': components['schemas']['Rodin3DCheckStatusRequest'] + } + } + responses: { + /** @description Get the status of the 3D Assets generation. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['Rodin3DCheckStatusResponse'] + } + } + /** @description Bad Request */ + 400: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Forbidden */ + 403: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Not Found */ + 404: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Internal Server Error */ + 500: { + headers: { + [name: string]: unknown + } + content?: never + } + } + } + rodinDownload: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody: { + content: { + 'multipart/form-data': components['schemas']['Rodin3DDownloadRequest'] + } + } + responses: { + /** @description Get the download list for the Rodin 3D Assets. */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['Rodin3DDownloadResponse'] + } + } + /** @description Bad Request */ + 400: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Forbidden */ + 403: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Not Found */ + 404: { + headers: { + [name: string]: unknown + } + content?: never + } + /** @description Internal Server Error */ + 500: { + headers: { + [name: string]: unknown + } + content?: never + } + } + } + MoonvalleyGetPrompt: { + parameters: { + query?: never + header?: never + path: { + prompt_id: string + } + cookie?: never + } + requestBody?: never + responses: { + /** @description Prompt details retrieved */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['MoonvalleyPromptResponse'] + } + } + } + } + MoonvalleyTextToVideo: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['MoonvalleyTextToVideoRequest'] + } + } + responses: { + /** @description Prompt created */ + 201: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['MoonvalleyPromptResponse'] + } + } + } + } + MoonvalleyTextToImage: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['MoonvalleyTextToImageRequest'] + } + } + responses: { + /** @description Prompt created */ + 201: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['MoonvalleyPromptResponse'] + } + } + } + } + MoonvalleyImageToVideo: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['MoonvalleyImageToVideoRequest'] + } + } + responses: { + /** @description Prompt created */ + 201: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['MoonvalleyPromptResponse'] + } + } + } + } + MoonvalleyVideoToVideo: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['MoonvalleyVideoToVideoRequest'] + } + } + responses: { + /** @description Prompt created */ + 201: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['MoonvalleyPromptResponse'] + } + } + } + } + MoonvalleyVideoToVideoResize: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody: { + content: { + 'application/json': components['schemas']['MoonvalleyResizeVideoRequest'] + } + } + responses: { + /** @description Prompt created */ + 201: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['MoonvalleyPromptResponse'] + } + } + } + } + MoonvalleyUpload: { + parameters: { + query?: never + header?: never + path?: never + cookie?: never + } + requestBody: { + content: { + 'multipart/form-data': components['schemas']['MoonvalleyUploadFileRequest'] + } + } + responses: { + /** @description File uploaded successfully */ + 200: { + headers: { + [name: string]: unknown + } + content: { + 'application/json': components['schemas']['MoonvalleyUploadFileResponse'] + } + } + } + } +} diff --git a/packages/registry-types/tsconfig.json b/packages/registry-types/tsconfig.json new file mode 100644 index 000000000..60c7df181 --- /dev/null +++ b/packages/registry-types/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "rootDir": "src", + "outDir": "dist" + }, + "include": ["src/**/*"] +} diff --git a/packages/shared-frontend-utils/package.json b/packages/shared-frontend-utils/package.json new file mode 100644 index 000000000..fa25c37a3 --- /dev/null +++ b/packages/shared-frontend-utils/package.json @@ -0,0 +1,22 @@ +{ + "name": "@comfyorg/shared-frontend-utils", + "private": true, + "version": "1.0.0", + "description": "Shared frontend utils for ComfyUI Frontend", + "scripts": { + "typecheck": "tsc --noEmit" + }, + "keywords": [], + "packageManager": "pnpm@10.17.1", + "type": "module", + "exports": { + "./formatUtil": "./src/formatUtil.ts", + "./networkUtil": "./src/networkUtil.ts" + }, + "dependencies": { + "axios": "^1.11.0" + }, + "devDependencies": { + "typescript": "^5.9.2" + } +} diff --git a/src/utils/formatUtil.ts b/packages/shared-frontend-utils/src/formatUtil.ts similarity index 93% rename from src/utils/formatUtil.ts rename to packages/shared-frontend-utils/src/formatUtil.ts index 9d4f0c270..a5d525c82 100644 --- a/src/utils/formatUtil.ts +++ b/packages/shared-frontend-utils/src/formatUtil.ts @@ -1,5 +1,4 @@ -import type { ResultItem } from '@/schemas/apiSchema' -import type { operations } from '@/types/comfyRegistryTypes' +import type { operations } from '@comfyorg/registry-types' export function formatCamelCase(str: string): string { // Check if the string is camel case @@ -194,27 +193,6 @@ export function isValidUrl(url: string): boolean { return false } } -const hasAnnotation = (filepath: string): boolean => - /\[(input|output|temp)\]/i.test(filepath) - -const createAnnotation = (filepath: string, rootFolder = 'input'): string => - !hasAnnotation(filepath) && rootFolder !== 'input' ? ` [${rootFolder}]` : '' - -const createPath = (filename: string, subfolder = ''): string => - subfolder ? `${subfolder}/${filename}` : filename - -/** Creates annotated filepath in format used by folder_paths.py */ -export function createAnnotatedPath( - item: string | ResultItem, - options: { rootFolder?: string; subfolder?: string } = {} -): string { - const { rootFolder = 'input', subfolder } = options - if (typeof item === 'string') - return `${createPath(item, subfolder)}${createAnnotation(item, rootFolder)}` - return `${createPath(item.filename ?? '', item.subfolder)}${ - item.type ? createAnnotation(item.type, rootFolder) : '' - }` -} /** * Parses a filepath into its filename and subfolder components. diff --git a/src/utils/networkUtil.ts b/packages/shared-frontend-utils/src/networkUtil.ts similarity index 81% rename from src/utils/networkUtil.ts rename to packages/shared-frontend-utils/src/networkUtil.ts index bc29d81e5..7ae597232 100644 --- a/src/utils/networkUtil.ts +++ b/packages/shared-frontend-utils/src/networkUtil.ts @@ -1,8 +1,5 @@ import axios from 'axios' -import { electronAPI } from './envUtil' -import { isValidUrl } from './formatUtil' - const VALID_STATUS_CODES = [200, 201, 301, 302, 307, 308] export const checkUrlReachable = async (url: string): Promise => { try { @@ -14,17 +11,6 @@ export const checkUrlReachable = async (url: string): Promise => { } } -/** - * Check if a mirror is reachable from the electron App. - * @param mirror - The mirror to check. - * @returns True if the mirror is reachable, false otherwise. - */ -export const checkMirrorReachable = async (mirror: string) => { - return ( - isValidUrl(mirror) && (await electronAPI().NetWork.canAccessUrl(mirror)) - ) -} - /** * Checks if the user is likely in mainland China by: * 1. Checking navigator.language diff --git a/packages/shared-frontend-utils/tsconfig.json b/packages/shared-frontend-utils/tsconfig.json new file mode 100644 index 000000000..60c7df181 --- /dev/null +++ b/packages/shared-frontend-utils/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "rootDir": "src", + "outDir": "dist" + }, + "include": ["src/**/*"] +} diff --git a/packages/tailwind-utils/package.json b/packages/tailwind-utils/package.json index f20d1ea65..8a62e71eb 100644 --- a/packages/tailwind-utils/package.json +++ b/packages/tailwind-utils/package.json @@ -6,10 +6,7 @@ "main": "./src/index.ts", "types": "./src/index.ts", "exports": { - ".": { - "import": "./src/index.ts", - "types": "./src/index.ts" - } + ".": "./src/index.ts" }, "scripts": { "typecheck": "tsc --noEmit" @@ -25,6 +22,6 @@ "tailwind-merge": "^2.2.0" }, "devDependencies": { - "typescript": "^5.4.5" + "typescript": "catalog:" } -} \ No newline at end of file +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2fb5c1a7d..41d81e9b2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4,12 +4,273 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false +catalogs: + default: + '@alloc/quick-lru': + specifier: ^5.2.0 + version: 5.2.0 + '@eslint/js': + specifier: ^9.35.0 + version: 9.35.0 + '@iconify-json/lucide': + specifier: ^1.1.178 + version: 1.2.66 + '@iconify/json': + specifier: ^2.2.380 + version: 2.2.380 + '@iconify/tailwind': + specifier: ^1.1.3 + version: 1.2.0 + '@intlify/eslint-plugin-vue-i18n': + specifier: ^4.1.0 + version: 4.1.0 + '@lobehub/i18n-cli': + specifier: ^1.25.1 + version: 1.25.1 + '@nx/eslint': + specifier: 21.4.1 + version: 21.4.1 + '@nx/playwright': + specifier: 21.4.1 + version: 21.4.1 + '@nx/storybook': + specifier: 21.4.1 + version: 21.4.1 + '@nx/vite': + specifier: 21.4.1 + version: 21.4.1 + '@pinia/testing': + specifier: ^0.1.5 + version: 0.1.5 + '@playwright/test': + specifier: ^1.52.0 + version: 1.52.0 + '@primeuix/forms': + specifier: 0.0.2 + version: 0.0.2 + '@primeuix/styled': + specifier: 0.3.2 + version: 0.3.2 + '@primeuix/utils': + specifier: ^0.3.2 + version: 0.3.2 + '@primevue/core': + specifier: ^4.2.5 + version: 4.2.5 + '@primevue/forms': + specifier: ^4.2.5 + version: 4.2.5 + '@primevue/icons': + specifier: 4.2.5 + version: 4.2.5 + '@primevue/themes': + specifier: ^4.2.5 + version: 4.2.5 + '@sentry/vue': + specifier: ^8.48.0 + version: 8.48.0 + '@storybook/addon-docs': + specifier: ^9.1.1 + version: 9.1.1 + '@storybook/vue3': + specifier: ^9.1.1 + version: 9.1.1 + '@storybook/vue3-vite': + specifier: ^9.1.1 + version: 9.1.1 + '@tailwindcss/vite': + specifier: ^4.1.12 + version: 4.1.12 + '@trivago/prettier-plugin-sort-imports': + specifier: ^5.2.0 + version: 5.2.2 + '@types/fs-extra': + specifier: ^11.0.4 + version: 11.0.4 + '@types/jsdom': + specifier: ^21.1.7 + version: 21.1.7 + '@types/node': + specifier: ^20.14.8 + version: 20.14.10 + '@types/semver': + specifier: ^7.7.0 + version: 7.7.0 + '@types/three': + specifier: ^0.169.0 + version: 0.169.0 + '@vitejs/plugin-vue': + specifier: ^5.1.4 + version: 5.1.4 + '@vitest/coverage-v8': + specifier: ^3.2.4 + version: 3.2.4 + '@vitest/ui': + specifier: ^3.0.0 + version: 3.2.4 + '@vue/test-utils': + specifier: ^2.4.6 + version: 2.4.6 + '@vueuse/core': + specifier: ^11.0.0 + version: 11.0.0 + '@vueuse/integrations': + specifier: ^13.9.0 + version: 13.9.0 + algoliasearch: + specifier: ^5.21.0 + version: 5.21.0 + axios: + specifier: ^1.11.0 + version: 1.11.0 + dotenv: + specifier: ^16.4.5 + version: 16.6.1 + eslint: + specifier: ^9.34.0 + version: 9.35.0 + eslint-config-prettier: + specifier: ^10.1.8 + version: 10.1.8 + eslint-plugin-prettier: + specifier: ^5.5.4 + version: 5.5.4 + eslint-plugin-storybook: + specifier: ^9.1.6 + version: 9.1.6 + eslint-plugin-unused-imports: + specifier: ^4.2.0 + version: 4.2.0 + eslint-plugin-vue: + specifier: ^10.4.0 + version: 10.4.0 + firebase: + specifier: ^11.6.0 + version: 11.6.0 + globals: + specifier: ^15.9.0 + version: 15.15.0 + happy-dom: + specifier: ^15.11.0 + version: 15.11.0 + husky: + specifier: ^9.0.11 + version: 9.0.11 + jiti: + specifier: 2.4.2 + version: 2.4.2 + jsdom: + specifier: ^26.1.0 + version: 26.1.0 + knip: + specifier: ^5.62.0 + version: 5.62.0 + lint-staged: + specifier: ^15.2.7 + version: 15.2.7 + nx: + specifier: 21.4.1 + version: 21.4.1 + pinia: + specifier: ^2.1.7 + version: 2.2.2 + postcss-html: + specifier: ^1.8.0 + version: 1.8.0 + prettier: + specifier: ^3.3.2 + version: 3.3.2 + primeicons: + specifier: ^7.0.0 + version: 7.0.0 + primevue: + specifier: ^4.2.5 + version: 4.2.5 + storybook: + specifier: ^9.1.6 + version: 9.1.6 + stylelint: + specifier: ^16.24.0 + version: 16.24.0 + tailwindcss: + specifier: ^4.1.12 + version: 4.1.12 + tailwindcss-primeui: + specifier: ^0.6.1 + version: 0.6.1 + tsx: + specifier: ^4.15.6 + version: 4.19.4 + tw-animate-css: + specifier: ^1.3.8 + version: 1.3.8 + typescript: + specifier: ^5.9.2 + version: 5.9.2 + typescript-eslint: + specifier: ^8.44.0 + version: 8.44.0 + unplugin-icons: + specifier: ^0.22.0 + version: 0.22.0 + unplugin-vue-components: + specifier: ^0.28.0 + version: 0.28.0 + vite: + specifier: ^5.4.19 + version: 5.4.19 + vite-plugin-dts: + specifier: ^4.5.4 + version: 4.5.4 + vite-plugin-html: + specifier: ^3.2.2 + version: 3.2.2 + vite-plugin-vue-devtools: + specifier: ^7.7.6 + version: 7.7.6 + vitest: + specifier: ^3.2.4 + version: 3.2.4 + vue: + specifier: ^3.5.13 + version: 3.5.13 + vue-component-type-helpers: + specifier: ^3.0.7 + version: 3.1.0 + vue-eslint-parser: + specifier: ^10.2.0 + version: 10.2.0 + vue-i18n: + specifier: ^9.14.3 + version: 9.14.3 + vue-router: + specifier: ^4.4.3 + version: 4.4.3 + vue-tsc: + specifier: ^3.0.7 + version: 3.0.7 + vuefire: + specifier: ^3.2.1 + version: 3.2.1 + yjs: + specifier: ^13.6.27 + version: 13.6.27 + zod: + specifier: ^3.23.8 + version: 3.24.1 + zod-to-json-schema: + specifier: ^3.24.1 + version: 3.24.1 + zod-validation-error: + specifier: ^3.3.0 + version: 3.3.0 + importers: .: dependencies: '@alloc/quick-lru': - specifier: ^5.2.0 + specifier: 'catalog:' version: 5.2.0 '@atlaskit/pragmatic-drag-and-drop': specifier: ^1.3.1 @@ -20,35 +281,38 @@ importers: '@comfyorg/design-system': specifier: workspace:* version: link:packages/design-system + '@comfyorg/registry-types': + specifier: workspace:* + version: link:packages/registry-types '@comfyorg/tailwind-utils': specifier: workspace:* version: link:packages/tailwind-utils '@iconify/json': - specifier: ^2.2.380 + specifier: 'catalog:' version: 2.2.380 '@primeuix/forms': - specifier: 0.0.2 + specifier: 'catalog:' version: 0.0.2 '@primeuix/styled': - specifier: 0.3.2 + specifier: 'catalog:' version: 0.3.2 '@primeuix/utils': - specifier: ^0.3.2 + specifier: 'catalog:' version: 0.3.2 '@primevue/core': - specifier: ^4.2.5 + specifier: 'catalog:' version: 4.2.5(vue@3.5.13(typescript@5.9.2)) '@primevue/forms': - specifier: ^4.2.5 + specifier: 'catalog:' version: 4.2.5(vue@3.5.13(typescript@5.9.2)) '@primevue/icons': - specifier: 4.2.5 + specifier: 'catalog:' version: 4.2.5(vue@3.5.13(typescript@5.9.2)) '@primevue/themes': - specifier: ^4.2.5 + specifier: 'catalog:' version: 4.2.5 '@sentry/vue': - specifier: ^8.48.0 + specifier: 'catalog:' version: 8.48.0(pinia@2.2.2(typescript@5.9.2)(vue@3.5.13(typescript@5.9.2)))(vue@3.5.13(typescript@5.9.2)) '@tiptap/core': specifier: ^2.10.4 @@ -72,10 +336,10 @@ importers: specifier: ^2.10.4 version: 2.10.4 '@vueuse/core': - specifier: ^11.0.0 + specifier: 'catalog:' version: 11.0.0(vue@3.5.13(typescript@5.9.2)) '@vueuse/integrations': - specifier: ^13.9.0 + specifier: 'catalog:' version: 13.9.0(axios@1.11.0)(fuse.js@7.0.0)(vue@3.5.13(typescript@5.9.2)) '@xterm/addon-fit': specifier: ^0.10.0 @@ -87,10 +351,10 @@ importers: specifier: ^5.5.0 version: 5.5.0 algoliasearch: - specifier: ^5.21.0 + specifier: 'catalog:' version: 5.21.0 axios: - specifier: ^1.8.2 + specifier: 'catalog:' version: 1.11.0 chart.js: specifier: ^4.5.0 @@ -99,7 +363,7 @@ importers: specifier: ^3.2.5 version: 3.2.5 dotenv: - specifier: ^16.4.5 + specifier: 'catalog:' version: 16.6.1 es-toolkit: specifier: ^1.39.9 @@ -114,7 +378,7 @@ importers: specifier: ^3.3.3 version: 3.3.3 firebase: - specifier: ^11.6.0 + specifier: 'catalog:' version: 11.6.0 fuse.js: specifier: ^7.0.0 @@ -132,13 +396,13 @@ importers: specifier: ^15.0.11 version: 15.0.11 pinia: - specifier: ^2.1.7 + specifier: 'catalog:' version: 2.2.2(typescript@5.9.2)(vue@3.5.13(typescript@5.9.2)) primeicons: - specifier: ^7.0.0 + specifier: 'catalog:' version: 7.0.0 primevue: - specifier: ^4.2.5 + specifier: 'catalog:' version: 4.2.5(vue@3.5.13(typescript@5.9.2)) reka-ui: specifier: ^2.5.0 @@ -153,219 +417,301 @@ importers: specifier: ^0.8.10 version: 0.8.10(@tiptap/core@2.10.4(@tiptap/pm@2.10.4)) vue: - specifier: ^3.5.13 + specifier: 'catalog:' version: 3.5.13(typescript@5.9.2) vue-i18n: - specifier: ^9.14.3 + specifier: 'catalog:' version: 9.14.3(vue@3.5.13(typescript@5.9.2)) vue-router: - specifier: ^4.4.3 + specifier: 'catalog:' version: 4.4.3(vue@3.5.13(typescript@5.9.2)) vuefire: - specifier: ^3.2.1 + specifier: 'catalog:' version: 3.2.1(consola@3.4.2)(firebase@11.6.0)(vue@3.5.13(typescript@5.9.2)) yjs: - specifier: ^13.6.27 + specifier: 'catalog:' version: 13.6.27 zod: - specifier: ^3.23.8 + specifier: 'catalog:' version: 3.24.1 zod-validation-error: - specifier: ^3.3.0 + specifier: 'catalog:' version: 3.3.0(zod@3.24.1) devDependencies: '@eslint/js': - specifier: ^9.35.0 + specifier: 'catalog:' version: 9.35.0 '@intlify/eslint-plugin-vue-i18n': - specifier: ^4.1.0 + specifier: 'catalog:' version: 4.1.0(eslint@9.35.0(jiti@2.4.2))(jsonc-eslint-parser@2.4.0)(vue-eslint-parser@10.2.0(eslint@9.35.0(jiti@2.4.2)))(yaml-eslint-parser@1.3.0) '@lobehub/i18n-cli': - specifier: ^1.25.1 + specifier: 'catalog:' version: 1.25.1(@types/react@19.1.9)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@19.1.1))(ws@8.18.3)(zod@3.24.1) '@nx/eslint': - specifier: 21.4.1 + specifier: 'catalog:' version: 21.4.1(@babel/traverse@7.28.3)(@zkochan/js-yaml@0.0.7)(eslint@9.35.0(jiti@2.4.2))(nx@21.4.1) '@nx/playwright': - specifier: 21.4.1 + specifier: 'catalog:' version: 21.4.1(@babel/traverse@7.28.3)(@playwright/test@1.52.0)(@zkochan/js-yaml@0.0.7)(eslint@9.35.0(jiti@2.4.2))(nx@21.4.1)(typescript@5.9.2) '@nx/storybook': - specifier: 21.4.1 + specifier: 'catalog:' version: 21.4.1(@babel/traverse@7.28.3)(@zkochan/js-yaml@0.0.7)(eslint@9.35.0(jiti@2.4.2))(nx@21.4.1)(storybook@9.1.6(@testing-library/dom@10.4.1)(prettier@3.3.2)(vite@5.4.19(@types/node@20.14.10)(lightningcss@1.30.1)(terser@5.39.2)))(typescript@5.9.2) '@nx/vite': - specifier: 21.4.1 + specifier: 'catalog:' version: 21.4.1(@babel/traverse@7.28.3)(nx@21.4.1)(typescript@5.9.2)(vite@5.4.19(@types/node@20.14.10)(lightningcss@1.30.1)(terser@5.39.2))(vitest@3.2.4) '@pinia/testing': - specifier: ^0.1.5 + specifier: 'catalog:' version: 0.1.5(pinia@2.2.2(typescript@5.9.2)(vue@3.5.13(typescript@5.9.2)))(vue@3.5.13(typescript@5.9.2)) '@playwright/test': - specifier: ^1.52.0 + specifier: 'catalog:' version: 1.52.0 '@storybook/addon-docs': - specifier: ^9.1.1 + specifier: 'catalog:' version: 9.1.1(@types/react@19.1.9)(storybook@9.1.6(@testing-library/dom@10.4.1)(prettier@3.3.2)(vite@5.4.19(@types/node@20.14.10)(lightningcss@1.30.1)(terser@5.39.2))) '@storybook/vue3': - specifier: ^9.1.1 + specifier: 'catalog:' version: 9.1.1(storybook@9.1.6(@testing-library/dom@10.4.1)(prettier@3.3.2)(vite@5.4.19(@types/node@20.14.10)(lightningcss@1.30.1)(terser@5.39.2)))(vue@3.5.13(typescript@5.9.2)) '@storybook/vue3-vite': - specifier: ^9.1.1 + specifier: 'catalog:' version: 9.1.1(storybook@9.1.6(@testing-library/dom@10.4.1)(prettier@3.3.2)(vite@5.4.19(@types/node@20.14.10)(lightningcss@1.30.1)(terser@5.39.2)))(vite@5.4.19(@types/node@20.14.10)(lightningcss@1.30.1)(terser@5.39.2))(vue@3.5.13(typescript@5.9.2)) '@tailwindcss/vite': - specifier: ^4.1.12 + specifier: 'catalog:' version: 4.1.12(vite@5.4.19(@types/node@20.14.10)(lightningcss@1.30.1)(terser@5.39.2)) '@trivago/prettier-plugin-sort-imports': - specifier: ^5.2.0 + specifier: 'catalog:' version: 5.2.2(@vue/compiler-sfc@3.5.13)(prettier@3.3.2) '@types/fs-extra': - specifier: ^11.0.4 + specifier: 'catalog:' version: 11.0.4 '@types/jsdom': - specifier: ^21.1.7 + specifier: 'catalog:' version: 21.1.7 '@types/node': - specifier: ^20.14.8 + specifier: 'catalog:' version: 20.14.10 '@types/semver': - specifier: ^7.7.0 + specifier: 'catalog:' version: 7.7.0 '@types/three': - specifier: ^0.169.0 + specifier: 'catalog:' version: 0.169.0 '@vitejs/plugin-vue': - specifier: ^5.1.4 + specifier: 'catalog:' version: 5.1.4(vite@5.4.19(@types/node@20.14.10)(lightningcss@1.30.1)(terser@5.39.2))(vue@3.5.13(typescript@5.9.2)) '@vitest/coverage-v8': - specifier: ^3.2.4 + specifier: 'catalog:' version: 3.2.4(vitest@3.2.4) '@vitest/ui': - specifier: ^3.0.0 + specifier: 'catalog:' version: 3.2.4(vitest@3.2.4) '@vue/test-utils': - specifier: ^2.4.6 + specifier: 'catalog:' version: 2.4.6 eslint: - specifier: ^9.34.0 + specifier: 'catalog:' version: 9.35.0(jiti@2.4.2) eslint-config-prettier: - specifier: ^10.1.8 + specifier: 'catalog:' version: 10.1.8(eslint@9.35.0(jiti@2.4.2)) eslint-plugin-prettier: - specifier: ^5.5.4 + specifier: 'catalog:' version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.35.0(jiti@2.4.2)))(eslint@9.35.0(jiti@2.4.2))(prettier@3.3.2) eslint-plugin-storybook: - specifier: ^9.1.6 + specifier: 'catalog:' version: 9.1.6(eslint@9.35.0(jiti@2.4.2))(storybook@9.1.6(@testing-library/dom@10.4.1)(prettier@3.3.2)(vite@5.4.19(@types/node@20.14.10)(lightningcss@1.30.1)(terser@5.39.2)))(typescript@5.9.2) eslint-plugin-unused-imports: - specifier: ^4.2.0 + specifier: 'catalog:' version: 4.2.0(@typescript-eslint/eslint-plugin@8.44.0(@typescript-eslint/parser@8.44.0(eslint@9.35.0(jiti@2.4.2))(typescript@5.9.2))(eslint@9.35.0(jiti@2.4.2))(typescript@5.9.2))(eslint@9.35.0(jiti@2.4.2)) eslint-plugin-vue: - specifier: ^10.4.0 + specifier: 'catalog:' version: 10.4.0(@typescript-eslint/parser@8.44.0(eslint@9.35.0(jiti@2.4.2))(typescript@5.9.2))(eslint@9.35.0(jiti@2.4.2))(vue-eslint-parser@10.2.0(eslint@9.35.0(jiti@2.4.2))) fs-extra: specifier: ^11.2.0 version: 11.2.0 globals: - specifier: ^15.9.0 + specifier: 'catalog:' version: 15.15.0 happy-dom: - specifier: ^15.11.0 + specifier: 'catalog:' version: 15.11.0 husky: - specifier: ^9.0.11 + specifier: 'catalog:' version: 9.0.11 jiti: - specifier: 2.4.2 + specifier: 'catalog:' version: 2.4.2 jsdom: - specifier: ^26.1.0 + specifier: 'catalog:' version: 26.1.0 knip: - specifier: ^5.62.0 + specifier: 'catalog:' version: 5.62.0(@types/node@20.14.10)(typescript@5.9.2) lint-staged: - specifier: ^15.2.7 + specifier: 'catalog:' version: 15.2.7 nx: - specifier: 21.4.1 + specifier: 'catalog:' version: 21.4.1 + postcss-html: + specifier: 'catalog:' + version: 1.8.0 prettier: - specifier: ^3.3.2 + specifier: 'catalog:' version: 3.3.2 storybook: - specifier: ^9.1.6 + specifier: 'catalog:' version: 9.1.6(@testing-library/dom@10.4.1)(prettier@3.3.2)(vite@5.4.19(@types/node@20.14.10)(lightningcss@1.30.1)(terser@5.39.2)) + stylelint: + specifier: 'catalog:' + version: 16.24.0(typescript@5.9.2) tailwindcss: - specifier: ^4.1.12 + specifier: 'catalog:' version: 4.1.12 tailwindcss-primeui: - specifier: ^0.6.1 + specifier: 'catalog:' version: 0.6.1(tailwindcss@4.1.12) tsx: - specifier: ^4.15.6 + specifier: 'catalog:' version: 4.19.4 tw-animate-css: - specifier: ^1.3.8 + specifier: 'catalog:' version: 1.3.8 typescript: - specifier: ^5.4.5 + specifier: 'catalog:' version: 5.9.2 typescript-eslint: - specifier: ^8.44.0 + specifier: 'catalog:' version: 8.44.0(eslint@9.35.0(jiti@2.4.2))(typescript@5.9.2) unplugin-icons: - specifier: ^0.22.0 + specifier: 'catalog:' version: 0.22.0(@vue/compiler-sfc@3.5.13) unplugin-vue-components: - specifier: ^0.28.0 + specifier: 'catalog:' version: 0.28.0(@babel/parser@7.28.4)(rollup@4.22.4)(vue@3.5.13(typescript@5.9.2)) uuid: specifier: ^11.1.0 version: 11.1.0 vite: - specifier: ^5.4.19 + specifier: 'catalog:' version: 5.4.19(@types/node@20.14.10)(lightningcss@1.30.1)(terser@5.39.2) vite-plugin-dts: - specifier: ^4.5.4 + specifier: 'catalog:' version: 4.5.4(@types/node@20.14.10)(rollup@4.22.4)(typescript@5.9.2)(vite@5.4.19(@types/node@20.14.10)(lightningcss@1.30.1)(terser@5.39.2)) vite-plugin-html: - specifier: ^3.2.2 + specifier: 'catalog:' version: 3.2.2(vite@5.4.19(@types/node@20.14.10)(lightningcss@1.30.1)(terser@5.39.2)) vite-plugin-vue-devtools: - specifier: ^7.7.6 + specifier: 'catalog:' version: 7.7.6(rollup@4.22.4)(vite@5.4.19(@types/node@20.14.10)(lightningcss@1.30.1)(terser@5.39.2))(vue@3.5.13(typescript@5.9.2)) vitest: - specifier: ^3.2.4 + specifier: 'catalog:' version: 3.2.4(@types/debug@4.1.12)(@types/node@20.14.10)(@vitest/ui@3.2.4)(happy-dom@15.11.0)(jsdom@26.1.0)(lightningcss@1.30.1)(terser@5.39.2) vue-component-type-helpers: - specifier: ^3.0.7 - version: 3.0.7 + specifier: 'catalog:' + version: 3.1.0 vue-eslint-parser: - specifier: ^10.2.0 + specifier: 'catalog:' version: 10.2.0(eslint@9.35.0(jiti@2.4.2)) vue-tsc: - specifier: ^3.0.7 + specifier: 'catalog:' version: 3.0.7(typescript@5.9.2) zip-dir: specifier: ^2.0.0 version: 2.0.0 zod-to-json-schema: - specifier: ^3.24.1 + specifier: 'catalog:' version: 3.24.1(zod@3.24.1) + apps/desktop-ui: + dependencies: + '@comfyorg/comfyui-electron-types': + specifier: 0.4.73-0 + version: 0.4.73-0 + '@comfyorg/shared-frontend-utils': + specifier: workspace:* + version: link:../../packages/shared-frontend-utils + '@primevue/core': + specifier: 'catalog:' + version: 4.2.5(vue@3.5.13(typescript@5.9.2)) + '@primevue/themes': + specifier: 'catalog:' + version: 4.2.5 + '@vueuse/core': + specifier: 'catalog:' + version: 11.0.0(vue@3.5.13(typescript@5.9.2)) + pinia: + specifier: 'catalog:' + version: 2.2.2(typescript@5.9.2)(vue@3.5.13(typescript@5.9.2)) + primeicons: + specifier: 'catalog:' + version: 7.0.0 + primevue: + specifier: 'catalog:' + version: 4.2.5(vue@3.5.13(typescript@5.9.2)) + vue: + specifier: 'catalog:' + version: 3.5.13(typescript@5.9.2) + vue-i18n: + specifier: 'catalog:' + version: 9.14.3(vue@3.5.13(typescript@5.9.2)) + vue-router: + specifier: 'catalog:' + version: 4.4.3(vue@3.5.13(typescript@5.9.2)) + devDependencies: + '@tailwindcss/vite': + specifier: 'catalog:' + version: 4.1.12(vite@5.4.19(@types/node@20.14.10)(lightningcss@1.30.1)(terser@5.39.2)) + '@vitejs/plugin-vue': + specifier: 'catalog:' + version: 5.1.4(vite@5.4.19(@types/node@20.14.10)(lightningcss@1.30.1)(terser@5.39.2))(vue@3.5.13(typescript@5.9.2)) + dotenv: + specifier: 'catalog:' + version: 16.6.1 + unplugin-icons: + specifier: 'catalog:' + version: 0.22.0(@vue/compiler-sfc@3.5.13) + unplugin-vue-components: + specifier: 'catalog:' + version: 0.28.0(@babel/parser@7.28.4)(rollup@4.22.4)(vue@3.5.13(typescript@5.9.2)) + vite: + specifier: 'catalog:' + version: 5.4.19(@types/node@20.14.10)(lightningcss@1.30.1)(terser@5.39.2) + vite-plugin-html: + specifier: 'catalog:' + version: 3.2.2(vite@5.4.19(@types/node@20.14.10)(lightningcss@1.30.1)(terser@5.39.2)) + vite-plugin-vue-devtools: + specifier: 'catalog:' + version: 7.7.6(rollup@4.22.4)(vite@5.4.19(@types/node@20.14.10)(lightningcss@1.30.1)(terser@5.39.2))(vue@3.5.13(typescript@5.9.2)) + vue-tsc: + specifier: 'catalog:' + version: 3.0.7(typescript@5.9.2) + packages/design-system: dependencies: '@iconify-json/lucide': - specifier: ^1.1.178 + specifier: 'catalog:' version: 1.2.66 '@iconify/tailwind': - specifier: ^1.1.3 + specifier: 'catalog:' version: 1.2.0 devDependencies: tailwindcss: - specifier: ^3.4.17 - version: 3.4.17 + specifier: 'catalog:' + version: 4.1.12 typescript: - specifier: ^5.4.5 + specifier: 'catalog:' + version: 5.9.2 + + packages/registry-types: {} + + packages/shared-frontend-utils: + dependencies: + axios: + specifier: ^1.11.0 + version: 1.11.0 + devDependencies: + typescript: + specifier: ^5.9.2 version: 5.9.2 packages/tailwind-utils: @@ -378,7 +724,7 @@ importers: version: 2.6.0 devDependencies: typescript: - specifier: ^5.4.5 + specifier: 'catalog:' version: 5.9.2 packages: @@ -571,11 +917,6 @@ packages: resolution: {integrity: sha512-FCvFTm0sWV8Fxhpp2McP5/W53GPllQ9QeQ7SiqGWjMf/LVG07lFa5+pgK05IRhVwtvafT22KF+ZSnM9I545CvQ==} engines: {node: '>=6.9.0'} - '@babel/parser@7.28.3': - resolution: {integrity: sha512-7+Ey1mAgYqFAx2h0RuoxcQT5+MlG3GTV0TQrgr7/ZliKsm/MNDxVVutlWaziMq7wJNAz8MTqz55XLpWvva6StA==} - engines: {node: '>=6.0.0'} - hasBin: true - '@babel/parser@7.28.4': resolution: {integrity: sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==} engines: {node: '>=6.0.0'} @@ -1011,10 +1352,6 @@ packages: resolution: {integrity: sha512-7w4kZYHneL3A6NP2nxzHvT3HCZ7puDZZjFMqDpBPECub79sTtSO5CGXDkKrTQq8ksAwfD/XI2MRFX23njdDaIQ==} engines: {node: '>=6.9.0'} - '@babel/types@7.28.2': - resolution: {integrity: sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==} - engines: {node: '>=6.9.0'} - '@babel/types@7.28.4': resolution: {integrity: sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==} engines: {node: '>=6.9.0'} @@ -1023,6 +1360,15 @@ packages: resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==} engines: {node: '>=18'} + '@cacheable/memoize@2.0.3': + resolution: {integrity: sha512-hl9wfQgpiydhQEIv7fkjEzTGE+tcosCXLKFDO707wYJ/78FVOlowb36djex5GdbSyeHnG62pomYLMuV/OT8Pbw==} + + '@cacheable/memory@2.0.3': + resolution: {integrity: sha512-R3UKy/CKOyb1LZG/VRCTMcpiMDyLH7SH3JrraRdK6kf3GweWCOU3sgvE13W3TiDRbxnDKylzKJvhUAvWl9LQOA==} + + '@cacheable/utils@2.0.3': + resolution: {integrity: sha512-m7Rce68cMHlAUjvWBy9Ru1Nmw5gU0SjGGtQDdhpe6E0xnbcvrIY0Epy//JU1VYYBUTzrG9jvgmTauULGKzOkWA==} + '@comfyorg/comfyui-electron-types@0.4.73-0': resolution: {integrity: sha512-WlItGJQx9ZWShNG9wypx3kq+19pSig/U+s5sD2SAeEcMph4u8A/TS+lnRgdKhT58VT1uD7cMcj2SJpfdBPNWvw==} @@ -1054,6 +1400,22 @@ packages: resolution: {integrity: sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==} engines: {node: '>=18'} + '@csstools/media-query-list-parser@4.0.3': + resolution: {integrity: sha512-HAYH7d3TLRHDOUQK4mZKf9k9Ph/m8Akstg66ywKR4SFAigjs3yBiUeZtFxywiTm5moZMAp/5W/ZuFnNXXYLuuQ==} + engines: {node: '>=18'} + peerDependencies: + '@csstools/css-parser-algorithms': ^3.0.5 + '@csstools/css-tokenizer': ^3.0.4 + + '@csstools/selector-specificity@5.0.0': + resolution: {integrity: sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==} + engines: {node: '>=18'} + peerDependencies: + postcss-selector-parser: ^7.0.0 + + '@dual-bundle/import-meta-resolve@4.2.1': + resolution: {integrity: sha512-id+7YRUgoUX6CgV0DtuhirQWodeeA7Lf4i2x71JS/vtA5pRb/hIGWlw+G6MeXvsM+MXrz0VAydTGElX1rAfgPg==} + '@emnapi/core@1.4.5': resolution: {integrity: sha512-XsLw1dEOpkSX/WucdqUhPWP7hDxSvZiY+fsUC14h+FtQ2Ifni4znbBt8punRX+Uj2JG/uDb8nEHVKvrVlvdZ5Q==} @@ -1741,6 +2103,13 @@ packages: '@jridgewell/trace-mapping@0.3.30': resolution: {integrity: sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==} + '@keyv/bigmap@1.0.2': + resolution: {integrity: sha512-KR03xkEZlAZNF4IxXgVXb+uNIVNvwdh8UwI0cnc7WI6a+aQcDp8GL80qVfeB4E5NpsKJzou5jU0r6yLSSbMOtA==} + engines: {node: '>= 18'} + + '@keyv/serialize@1.1.1': + resolution: {integrity: sha512-dXn3FZhPv0US+7dtJsIi2R+c7qWYiReoEh5zUntWCf4oSpMNib8FDhSoed6m3QyZdx5hK7iLFkYk3rNxwt8vTA==} + '@kurkle/color@0.3.4': resolution: {integrity: sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==} @@ -2096,15 +2465,6 @@ packages: resolution: {integrity: sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==} engines: {node: '>= 8.0.0'} - '@rollup/pluginutils@5.1.4': - resolution: {integrity: sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==} - engines: {node: '>=14.0.0'} - peerDependencies: - rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 - peerDependenciesMeta: - rollup: - optional: true - '@rollup/pluginutils@5.3.0': resolution: {integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==} engines: {node: '>=14.0.0'} @@ -3129,16 +3489,10 @@ packages: resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} engines: {node: '>=12'} - any-promise@1.3.0: - resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} - anymatch@3.1.3: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} - arg@5.0.2: - resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} - argparse@1.0.10: resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} @@ -3156,6 +3510,10 @@ packages: resolution: {integrity: sha512-yOzOZcR9Tn7enTF66bqKorGGH0F36vcPaSWg8fO0c0UYb3LX3VMXj5ZxEqQLNOecAhlRJ7wYZja5i4jTlnbIfQ==} engines: {node: '>=4'} + array-union@2.1.0: + resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} + engines: {node: '>=8'} + asap@2.0.6: resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==} @@ -3173,6 +3531,10 @@ packages: ast-v8-to-istanbul@0.3.5: resolution: {integrity: sha512-9SdXjNheSiE8bALAQCQQuT6fgQaoxJh7IRYrRGZ8/9nv8WhJeC1aXAwN8TbaOssGOukUvyvnkgD9+Yuykvl1aA==} + astral-regex@2.0.0: + resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} + engines: {node: '>=8'} + async@3.2.5: resolution: {integrity: sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==} @@ -3236,6 +3598,9 @@ packages: balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + balanced-match@2.0.0: + resolution: {integrity: sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA==} + base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} @@ -3295,6 +3660,9 @@ packages: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} engines: {node: '>=8'} + cacheable@2.0.3: + resolution: {integrity: sha512-nZF80J3d8RMrroMSYm1E9pBllVDXWPuECZgEZxH+vusCY4MAXAJVrY0jutcHSgh3xYX3G2EUNnmtWGZVVjWCXw==} + call-bind-apply-helpers@1.0.2: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} engines: {node: '>= 0.4'} @@ -3314,10 +3682,6 @@ packages: camel-case@4.1.2: resolution: {integrity: sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==} - camelcase-css@2.0.1: - resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} - engines: {node: '>= 6'} - camelcase@8.0.0: resolution: {integrity: sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==} engines: {node: '>=16'} @@ -3421,6 +3785,9 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + colord@2.9.3: + resolution: {integrity: sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==} + colorette@2.0.20: resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} @@ -3447,10 +3814,6 @@ packages: commander@2.20.3: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} - commander@4.1.1: - resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} - engines: {node: '>= 6'} - commander@8.3.0: resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} engines: {node: '>= 12'} @@ -3529,9 +3892,17 @@ packages: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} + css-functions-list@3.2.3: + resolution: {integrity: sha512-IQOkD3hbR5KrN93MtcYuad6YPuTSUhntLHDuLEbFWE+ff2/XSZNdZG+LcbbIW5AXKg/WFIfYItIzVoHngHXZzA==} + engines: {node: '>=12 || >=16'} + css-select@4.3.0: resolution: {integrity: sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==} + css-tree@3.1.0: + resolution: {integrity: sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} + css-what@6.1.0: resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==} engines: {node: '>= 6'} @@ -3571,15 +3942,6 @@ packages: supports-color: optional: true - debug@4.4.1: - resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} @@ -3656,19 +4018,17 @@ packages: devlop@1.1.0: resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} - didyoumean@1.2.2: - resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} - diff-match-patch@1.0.5: resolution: {integrity: sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==} + dir-glob@3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + engines: {node: '>=8'} + dirty-json@0.9.2: resolution: {integrity: sha512-7SCDfnQtBObcngVXNPZcnxGxqqPTK4UqeXeKAch+RGH5qpqadWbV9FmN71x9Bb4tTs0TNFb4FT/4Kz4P4Cjqcw==} engines: {node: '>=6.0.0'} - dlv@1.1.3: - resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} - doctypes@1.1.0: resolution: {integrity: sha512-LLBi6pEqS6Do3EKQ3J0NqHWV5hhb78Pi8vvESYwyOy2c31ZEZVdtitdzsQsKb7878PEERhzUk0ftqGhG6Mz+pQ==} @@ -3681,6 +4041,9 @@ packages: dom-serializer@1.4.1: resolution: {integrity: sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==} + dom-serializer@2.0.0: + resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} + domelementtype@2.3.0: resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} @@ -3688,12 +4051,19 @@ packages: resolution: {integrity: sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==} engines: {node: '>= 4'} + domhandler@5.0.3: + resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} + engines: {node: '>= 4'} + dompurify@3.2.5: resolution: {integrity: sha512-mLPd29uoRe9HpvwP2TxClGQBzGXeEC/we/q+bFlmPPmj2p2Ugl3r6ATu/UU1v77DXNcehiBg9zsr1dREyA/dJQ==} domutils@2.8.0: resolution: {integrity: sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==} + domutils@3.2.2: + resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} + dot-case@3.0.4: resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==} @@ -4024,6 +4394,10 @@ packages: fast-uri@3.0.3: resolution: {integrity: sha512-aLrHthzCjH5He4Z2H9YZ+v6Ujb9ocRuW6ZzkJQOrTxleEijANq4v1TsaPaVG1PZcuurEzrLcWRyYBYXD5cEiaw==} + fastest-levenshtein@1.0.16: + resolution: {integrity: sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==} + engines: {node: '>= 4.9.1'} + fastq@1.17.1: resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} @@ -4057,6 +4431,9 @@ packages: resolution: {integrity: sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==} engines: {node: '>=18'} + file-entry-cache@10.1.4: + resolution: {integrity: sha512-5XRUFc0WTtUbjfGzEwXc42tiGxQHBmtbUG1h9L2apu4SulCGN3Hqm//9D6FAolf8MYNL7f/YlJl9vy08pj5JuA==} + file-entry-cache@8.0.0: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} @@ -4082,6 +4459,9 @@ packages: resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} engines: {node: '>=16'} + flat-cache@6.1.17: + resolution: {integrity: sha512-Jzse4YoiUJBVYTwz5Bwl4h/2VQM7e2KK3MVAMlXzX9uamIHAH/TXUlRKU1AQGQOryQhN0EsmufiiF40G057YXA==} + flat@5.0.2: resolution: {integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==} hasBin: true @@ -4209,6 +4589,14 @@ packages: resolution: {integrity: sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==} engines: {node: '>=18'} + global-modules@2.0.0: + resolution: {integrity: sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==} + engines: {node: '>=6'} + + global-prefix@3.0.0: + resolution: {integrity: sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==} + engines: {node: '>=6'} + globals@14.0.0: resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} engines: {node: '>=18'} @@ -4221,6 +4609,13 @@ packages: resolution: {integrity: sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==} engines: {node: '>=18'} + globby@11.1.0: + resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} + engines: {node: '>=10'} + + globjoin@0.1.4: + resolution: {integrity: sha512-xYfnw62CKG8nLkZBfWbhWwDw02CHty86jfPcc2cr3ZfeuK9ysoVPPEUxf21bAD/rWAgk52SuBrLJlefNy8mvFg==} + gopd@1.2.0: resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} engines: {node: '>= 0.4'} @@ -4274,6 +4669,9 @@ packages: hookable@5.5.3: resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==} + hookified@1.12.1: + resolution: {integrity: sha512-xnKGl+iMIlhrZmGHB729MqlmPoWBznctSQTYCpFKqNsCgimJQmithcW0xSQMMFzYnV2iKUh25alswn6epgxS0Q==} + hosted-git-info@7.0.2: resolution: {integrity: sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==} engines: {node: ^16.14.0 || >=18.0.0} @@ -4290,6 +4688,13 @@ packages: engines: {node: '>=12'} hasBin: true + html-tags@3.3.1: + resolution: {integrity: sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==} + engines: {node: '>=8'} + + htmlparser2@8.0.2: + resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==} + http-parser-js@0.5.10: resolution: {integrity: sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==} @@ -4471,6 +4876,10 @@ packages: resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} engines: {node: '>=12'} + is-plain-object@5.0.0: + resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==} + engines: {node: '>=0.10.0'} + is-potential-custom-element-name@1.0.1: resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} @@ -4557,10 +4966,6 @@ packages: resolution: {integrity: sha512-LUU2Gx8EhYxpdzTR6BmjL1ifgOAQJQELTHOiPv9KITaKjZvJ9Jmgigx01tuZ49id37LorpGc9dPBPlXTboXScw==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jiti@1.21.7: - resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==} - hasBin: true - jiti@2.4.2: resolution: {integrity: sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==} hasBin: true @@ -4677,6 +5082,9 @@ packages: keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + keyv@5.5.3: + resolution: {integrity: sha512-h0Un1ieD+HUrzBH6dJXhod3ifSghk5Hw/2Y4/KHBziPlZecrFyE9YOTPU6eOs0V9pYl8gOs86fkr/KN8lUX39A==} + kind-of@6.0.3: resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} engines: {node: '>=0.10.0'} @@ -4689,6 +5097,9 @@ packages: '@types/node': '>=18' typescript: '>=5.0.4' + known-css-properties@0.37.0: + resolution: {integrity: sha512-JCDrsP4Z1Sb9JwG0aJ8Eo2r7k4Ou5MwmThS/6lcIe1ICyb7UBJKGRIUUdqc2ASdE/42lgz6zFUnzAIhtXnBVrQ==} + kolorist@1.8.0: resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==} @@ -4784,10 +5195,6 @@ packages: resolution: {integrity: sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==} engines: {node: '>=14'} - lilconfig@3.1.3: - resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} - engines: {node: '>=14'} - lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} @@ -4834,6 +5241,9 @@ packages: lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + lodash.truncate@4.4.2: + resolution: {integrity: sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==} + lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} @@ -4883,9 +5293,6 @@ packages: resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} hasBin: true - magic-string@0.30.18: - resolution: {integrity: sha512-yi8swmWbO17qHhwIBNeeZxTceJMeBvWJaId6dyvTSOwTipqeHhMhOrz6513r1sOKnpvQ7zkhlG8tPrpilwTxHQ==} - magic-string@0.30.19: resolution: {integrity: sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==} @@ -4915,6 +5322,9 @@ packages: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} + mathml-tag-names@2.1.3: + resolution: {integrity: sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==} + mdast-util-find-and-replace@3.0.2: resolution: {integrity: sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==} @@ -4951,6 +5361,9 @@ packages: mdast-util-to-string@4.0.0: resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} + mdn-data@2.12.2: + resolution: {integrity: sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==} + mdurl@2.0.0: resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==} @@ -4963,6 +5376,10 @@ packages: media-encoder-host@9.0.20: resolution: {integrity: sha512-IyEYxw6az97RNuETOAZV4YZqNAPOiF9GKIp5mVZb4HOyWd6mhkWQ34ydOzhqAWogMyc4W05kjN/VCgTtgyFmsw==} + meow@13.2.0: + resolution: {integrity: sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==} + engines: {node: '>=18'} + merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} @@ -5130,9 +5547,6 @@ packages: engines: {node: '>=10'} hasBin: true - mlly@1.7.4: - resolution: {integrity: sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==} - mlly@1.8.0: resolution: {integrity: sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==} @@ -5150,8 +5564,10 @@ packages: resolution: {integrity: sha512-SsI/exkodHsh+ofCV7An2PZWRaJC7eFVl7gtHQlMWFEDmWtb7cELr/GK32Nhe/6dZQhbr81o+Moswx9aXN3RRg==} engines: {node: '>=18.2.0'} - mz@2.7.0: - resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true nanoid@3.3.8: resolution: {integrity: sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==} @@ -5244,10 +5660,6 @@ packages: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} - object-hash@3.0.0: - resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} - engines: {node: '>= 6'} - object-keys@1.1.1: resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} engines: {node: '>= 0.4'} @@ -5423,10 +5835,6 @@ packages: engines: {node: '>=0.10'} hasBin: true - pify@2.3.0: - resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} - engines: {node: '>=0.10.0'} - pinia@2.2.2: resolution: {integrity: sha512-ja2XqFWZC36mupU4z1ZzxeTApV7DOw44cV4dhQ9sGwun+N89v/XP7+j7q6TanS1u1tdbK4r+1BUx7heMaIdagA==} peerDependencies: @@ -5439,10 +5847,6 @@ packages: typescript: optional: true - pirates@4.0.7: - resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} - engines: {node: '>= 6'} - pkg-types@1.3.1: resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} @@ -5459,42 +5863,31 @@ packages: engines: {node: '>=18'} hasBin: true - postcss-import@15.1.0: - resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} - engines: {node: '>=14.0.0'} - peerDependencies: - postcss: ^8.0.0 + postcss-html@1.8.0: + resolution: {integrity: sha512-5mMeb1TgLWoRKxZ0Xh9RZDfwUUIqRrcxO2uXO+Ezl1N5lqpCiSU5Gk6+1kZediBfBHFtPCdopr2UZ2SgUsKcgQ==} + engines: {node: ^12 || >=14} - postcss-js@4.1.0: - resolution: {integrity: sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==} - engines: {node: ^12 || ^14 || >= 16} - peerDependencies: - postcss: ^8.4.21 + postcss-resolve-nested-selector@0.1.6: + resolution: {integrity: sha512-0sglIs9Wmkzbr8lQwEyIzlDOOC9bGmfVKcJTaxv3vMmd3uo4o4DerC3En0bnmgceeql9BfC8hRkp7cg0fjdVqw==} - postcss-load-config@4.0.2: - resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==} - engines: {node: '>= 14'} - peerDependencies: - postcss: '>=8.0.9' - ts-node: '>=9.0.0' - peerDependenciesMeta: - postcss: - optional: true - ts-node: - optional: true - - postcss-nested@6.2.0: - resolution: {integrity: sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==} + postcss-safe-parser@6.0.0: + resolution: {integrity: sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ==} engines: {node: '>=12.0'} peerDependencies: - postcss: ^8.2.14 + postcss: ^8.3.3 + + postcss-safe-parser@7.0.1: + resolution: {integrity: sha512-0AioNCJZ2DPYz5ABT6bddIqlhgwhpHZ/l65YAYo0BCIn0xiDpsnTHz0gnoTGk0OXZW0JRs+cDwL8u/teRdz+8A==} + engines: {node: '>=18.0'} + peerDependencies: + postcss: ^8.4.31 postcss-selector-parser@6.1.0: resolution: {integrity: sha512-UMz42UD0UY0EApS0ZL9o1XnLhSTtvvvLe5Dc2H2O56fvRZi+KulDyf5ctDhhtYJBGKStV2FL1fy6253cmLgqVQ==} engines: {node: '>=4'} - postcss-selector-parser@6.1.2: - resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==} + postcss-selector-parser@7.1.0: + resolution: {integrity: sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==} engines: {node: '>=4'} postcss-value-parser@4.2.0: @@ -5504,6 +5897,10 @@ packages: resolution: {integrity: sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ==} engines: {node: ^10 || ^12 || >=14} + postcss@8.5.6: + resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} + engines: {node: ^10 || ^12 || >=14} + prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} @@ -5696,9 +6093,6 @@ packages: resolution: {integrity: sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==} engines: {node: '>=0.10.0'} - read-cache@1.0.0: - resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} - readable-stream@2.3.8: resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} @@ -5783,6 +6177,10 @@ packages: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} + resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} @@ -5894,6 +6292,14 @@ packages: resolution: {integrity: sha512-FoqMu0NCGBLCcAkS1qA+XJIQTR6/JHfQXl+uGteNCQ76T91DMUjPa9xfmeqMY3z80nLSg9yQmNjK0Px6RWsH/A==} engines: {node: '>=18'} + slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + + slice-ansi@4.0.0: + resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==} + engines: {node: '>=10'} + slice-ansi@5.0.0: resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==} engines: {node: '>=12'} @@ -6017,14 +6423,14 @@ packages: stubborn-fs@1.2.5: resolution: {integrity: sha512-H2N9c26eXjzL/S/K+i/RHHcFanE74dptvvjM8iwzwbVcWY/zjBbgRqF3K0DY4+OD+uTTASTBvDoxPDaPN02D7g==} + stylelint@16.24.0: + resolution: {integrity: sha512-7ksgz3zJaSbTUGr/ujMXvLVKdDhLbGl3R/3arNudH7z88+XZZGNLMTepsY28WlnvEFcuOmUe7fg40Q3lfhOfSQ==} + engines: {node: '>=18.12.0'} + hasBin: true + subscribable-things@2.1.53: resolution: {integrity: sha512-zWvN9F/eYQWDKszXl4NXkyqPXvMDZDmXfcHiM5C5WQZTTY2OK+2TZeDlA9oio69FEPqPu9T6yeEcAhQ2uRmnaw==} - sucrase@3.35.0: - resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} - engines: {node: '>=16 || 14 >=14.17'} - hasBin: true - superjson@2.2.2: resolution: {integrity: sha512-5JRxVqC8I8NuOUjzBbvVJAKNM8qoVuH0O77h4WInc/qC2q5IreqKxYwgkga3PfA22OayK2ikceb/B26dztPl+Q==} engines: {node: '>=16'} @@ -6037,10 +6443,17 @@ packages: resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} engines: {node: '>=10'} + supports-hyperlinks@3.2.0: + resolution: {integrity: sha512-zFObLMyZeEwzAoKCyu1B91U79K2t7ApXuQfo8OuxwXLDgcKxuwM+YvcbIhm6QWqz7mHUH1TVytR1PwVVjEuMig==} + engines: {node: '>=14.18'} + supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} + svg-tags@1.0.0: + resolution: {integrity: sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==} + swr@2.3.6: resolution: {integrity: sha512-wfHRmHWk/isGNMwlLGlZX5Gzz/uTgo0o2IRuTMcf4CPuPFJZlq0rDaKUx+ozB5nBOReNV1kiOyzMfj+MBMikLw==} peerDependencies: @@ -6057,6 +6470,10 @@ packages: resolution: {integrity: sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==} engines: {node: ^14.18.0 || >=16.0.0} + table@6.9.0: + resolution: {integrity: sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==} + engines: {node: '>=10.0.0'} + tailwind-merge@2.6.0: resolution: {integrity: sha512-P+Vu1qXfzediirmHOC3xKGAYeZtPcV9g76X+xg2FD4tYgR71ewMA35Y3sCz3zhiN/dwefRpJX0yBcgwi1fXNQA==} @@ -6065,11 +6482,6 @@ packages: peerDependencies: tailwindcss: '>=3.1.0' - tailwindcss@3.4.17: - resolution: {integrity: sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==} - engines: {node: '>=14.0.0'} - hasBin: true - tailwindcss@4.1.12: resolution: {integrity: sha512-DzFtxOi+7NsFf7DBtI3BJsynR+0Yp6etH+nRPTbpWnS2pZBaSksv/JGctNwSWzbFjp0vxSqknaUylseZqMDGrA==} @@ -6094,13 +6506,6 @@ packages: resolution: {integrity: sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==} engines: {node: '>=18'} - thenify-all@1.6.0: - resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} - engines: {node: '>=0.8'} - - thenify@3.3.1: - resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} - three@0.170.0: resolution: {integrity: sha512-FQK+LEpYc0fBD+J8g6oSEyyNzjp+Q7Ks1C568WWaoMRLW+TkNNWmenWeGgJjV105Gd+p/2ql1ZcjYvNiPZBhuQ==} @@ -6187,9 +6592,6 @@ packages: resolution: {integrity: sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==} engines: {node: '>=6.10'} - ts-interface-checker@0.1.13: - resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} - ts-map@1.0.3: resolution: {integrity: sha512-vDWbsl26LIcPGmDpoVzjEP6+hvHZkBkLW7JpvwbCv/5IYPJlsbzCVXY3wsCeAxAUeTclNOUZxnLdGh3VBD/J6w==} @@ -6245,9 +6647,6 @@ packages: uc.micro@2.1.0: resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==} - ufo@1.5.4: - resolution: {integrity: sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==} - ufo@1.6.1: resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==} @@ -6504,11 +6903,11 @@ packages: vue-component-type-helpers@2.2.12: resolution: {integrity: sha512-YbGqHZ5/eW4SnkPNR44mKVc6ZKQoRs/Rux1sxC6rdwXb4qpbOSYfDr9DsTHolOTGmIKgM9j141mZbBeg05R1pw==} - vue-component-type-helpers@3.0.7: - resolution: {integrity: sha512-TvyUcFXmjZcXUvU+r1MOyn4/vv4iF+tPwg5Ig33l/FJ3myZkxeQpzzQMLMFWcQAjr6Xs7BRwVy/TwbmNZUA/4w==} + vue-component-type-helpers@3.1.0: + resolution: {integrity: sha512-cC1pYNRZkSS1iCvdlaMbbg2sjDwxX098FucEjtz9Yig73zYjWzQsnMe5M9H8dRNv55hAIDGUI29hF2BEUA4FMQ==} - vue-component-type-helpers@3.0.8: - resolution: {integrity: sha512-WyR30Eq15Y/+odrUUMax6FmPbZwAp/HnC7qgR1r3lVFAcqwQ4wUoV79Mbh4SxDy3NiqDa+G4TOKD5xXSgBHo5A==} + vue-component-type-helpers@3.1.1: + resolution: {integrity: sha512-B0kHv7qX6E7+kdc5nsaqjdGZ1KwNKSUQDWGy7XkTYT7wFsOpkEyaJ1Vq79TjwrrtuLRgizrTV7PPuC4rRQo+vw==} vue-demi@0.14.10: resolution: {integrity: sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==} @@ -6639,6 +7038,10 @@ packages: when-exit@2.1.4: resolution: {integrity: sha512-4rnvd3A1t16PWzrBUcSDZqcAmsUIy4minDXT/CZ8F2mVDgd65i4Aalimgz1aQkRGU0iH5eT5+6Rx2TK8o443Pg==} + which@1.3.1: + resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} + hasBin: true + which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} @@ -6679,6 +7082,10 @@ packages: wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + write-file-atomic@5.0.1: + resolution: {integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + ws@8.18.3: resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==} engines: {node: '>=10.0.0'} @@ -6936,12 +7343,12 @@ snapshots: '@babel/helper-compilation-targets': 7.27.2 '@babel/helper-module-transforms': 7.27.1(@babel/core@7.27.1) '@babel/helpers': 7.27.1 - '@babel/parser': 7.28.3 + '@babel/parser': 7.28.4 '@babel/template': 7.27.2 '@babel/traverse': 7.28.3 - '@babel/types': 7.28.2 + '@babel/types': 7.28.4 convert-source-map: 2.0.0 - debug: 4.4.1 + debug: 4.4.3 gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -6950,15 +7357,15 @@ snapshots: '@babel/generator@7.28.3': dependencies: - '@babel/parser': 7.28.3 - '@babel/types': 7.28.2 + '@babel/parser': 7.28.4 + '@babel/types': 7.28.4 '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.30 jsesc: 3.1.0 '@babel/helper-annotate-as-pure@7.27.3': dependencies: - '@babel/types': 7.28.2 + '@babel/types': 7.28.4 '@babel/helper-compilation-targets@7.27.2': dependencies: @@ -6993,7 +7400,7 @@ snapshots: '@babel/core': 7.27.1 '@babel/helper-compilation-targets': 7.27.2 '@babel/helper-plugin-utils': 7.27.1 - debug: 4.4.1 + debug: 4.4.3 lodash.debounce: 4.0.8 resolve: 1.22.10 transitivePeerDependencies: @@ -7004,14 +7411,14 @@ snapshots: '@babel/helper-member-expression-to-functions@7.27.1': dependencies: '@babel/traverse': 7.28.3 - '@babel/types': 7.28.2 + '@babel/types': 7.28.4 transitivePeerDependencies: - supports-color '@babel/helper-module-imports@7.27.1': dependencies: '@babel/traverse': 7.28.3 - '@babel/types': 7.28.2 + '@babel/types': 7.28.4 transitivePeerDependencies: - supports-color @@ -7026,7 +7433,7 @@ snapshots: '@babel/helper-optimise-call-expression@7.27.1': dependencies: - '@babel/types': 7.28.2 + '@babel/types': 7.28.4 '@babel/helper-plugin-utils@7.27.1': {} @@ -7051,7 +7458,7 @@ snapshots: '@babel/helper-skip-transparent-expression-wrappers@7.27.1': dependencies: '@babel/traverse': 7.28.3 - '@babel/types': 7.28.2 + '@babel/types': 7.28.4 transitivePeerDependencies: - supports-color @@ -7065,18 +7472,14 @@ snapshots: dependencies: '@babel/template': 7.27.2 '@babel/traverse': 7.28.3 - '@babel/types': 7.28.2 + '@babel/types': 7.28.4 transitivePeerDependencies: - supports-color '@babel/helpers@7.27.1': dependencies: '@babel/template': 7.27.2 - '@babel/types': 7.28.2 - - '@babel/parser@7.28.3': - dependencies: - '@babel/types': 7.28.2 + '@babel/types': 7.28.4 '@babel/parser@7.28.4': dependencies: @@ -7602,7 +8005,7 @@ snapshots: dependencies: '@babel/core': 7.27.1 '@babel/helper-plugin-utils': 7.27.1 - '@babel/types': 7.28.2 + '@babel/types': 7.28.4 esutils: 2.0.3 '@babel/preset-typescript@7.27.1(@babel/core@7.27.1)': @@ -7621,26 +8024,21 @@ snapshots: '@babel/template@7.27.2': dependencies: '@babel/code-frame': 7.27.1 - '@babel/parser': 7.28.3 - '@babel/types': 7.28.2 + '@babel/parser': 7.28.4 + '@babel/types': 7.28.4 '@babel/traverse@7.28.3': dependencies: '@babel/code-frame': 7.27.1 '@babel/generator': 7.28.3 '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.28.3 + '@babel/parser': 7.28.4 '@babel/template': 7.27.2 - '@babel/types': 7.28.2 - debug: 4.4.1 + '@babel/types': 7.28.4 + debug: 4.4.3 transitivePeerDependencies: - supports-color - '@babel/types@7.28.2': - dependencies: - '@babel/helper-string-parser': 7.27.1 - '@babel/helper-validator-identifier': 7.27.1 - '@babel/types@7.28.4': dependencies: '@babel/helper-string-parser': 7.27.1 @@ -7648,6 +8046,20 @@ snapshots: '@bcoe/v8-coverage@1.0.2': {} + '@cacheable/memoize@2.0.3': + dependencies: + '@cacheable/utils': 2.0.3 + + '@cacheable/memory@2.0.3': + dependencies: + '@cacheable/memoize': 2.0.3 + '@cacheable/utils': 2.0.3 + '@keyv/bigmap': 1.0.2 + hookified: 1.12.1 + keyv: 5.5.3 + + '@cacheable/utils@2.0.3': {} + '@comfyorg/comfyui-electron-types@0.4.73-0': {} '@csstools/color-helpers@5.1.0': {} @@ -7670,6 +8082,17 @@ snapshots: '@csstools/css-tokenizer@3.0.4': {} + '@csstools/media-query-list-parser@4.0.3(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)': + dependencies: + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-tokenizer': 3.0.4 + + '@csstools/selector-specificity@5.0.0(postcss-selector-parser@7.1.0)': + dependencies: + postcss-selector-parser: 7.1.0 + + '@dual-bundle/import-meta-resolve@4.2.1': {} + '@emnapi/core@1.4.5': dependencies: '@emnapi/wasi-threads': 1.0.4 @@ -7837,7 +8260,7 @@ snapshots: '@eslint/config-array@0.21.0': dependencies: '@eslint/object-schema': 2.1.6 - debug: 4.4.1 + debug: 4.4.3 minimatch: 3.1.2 transitivePeerDependencies: - supports-color @@ -7851,7 +8274,7 @@ snapshots: '@eslint/eslintrc@3.3.1': dependencies: ajv: 6.12.6 - debug: 4.4.1 + debug: 4.4.3 espree: 10.4.0 globals: 14.0.0 ignore: 5.3.1 @@ -8252,11 +8675,11 @@ snapshots: '@antfu/install-pkg': 1.1.0 '@antfu/utils': 8.1.1 '@iconify/types': 2.0.0 - debug: 4.4.1 + debug: 4.4.3 globals: 15.15.0 kolorist: 1.8.0 local-pkg: 1.1.2 - mlly: 1.7.4 + mlly: 1.8.0 transitivePeerDependencies: - supports-color @@ -8283,7 +8706,7 @@ snapshots: '@eslint/eslintrc': 3.3.1 '@intlify/core-base': 11.1.12 '@intlify/message-compiler': 11.1.12 - debug: 4.4.1 + debug: 4.4.3 eslint: 9.35.0(jiti@2.4.2) eslint-compat-utils: 0.6.5(eslint@9.35.0(jiti@2.4.2)) glob: 10.4.5 @@ -8370,6 +8793,12 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 + '@keyv/bigmap@1.0.2': + dependencies: + hookified: 1.12.1 + + '@keyv/serialize@1.1.1': {} + '@kurkle/color@0.3.4': {} '@lobehub/cli-ui@1.13.0(@types/react@19.1.9)': @@ -8868,14 +9297,6 @@ snapshots: estree-walker: 2.0.2 picomatch: 2.3.1 - '@rollup/pluginutils@5.1.4(rollup@4.22.4)': - dependencies: - '@types/estree': 1.0.8 - estree-walker: 2.0.2 - picomatch: 4.0.3 - optionalDependencies: - rollup: 4.22.4 - '@rollup/pluginutils@5.3.0(rollup@4.22.4)': dependencies: '@types/estree': 1.0.8 @@ -9051,7 +9472,7 @@ snapshots: '@storybook/builder-vite': 9.1.1(storybook@9.1.6(@testing-library/dom@10.4.1)(prettier@3.3.2)(vite@5.4.19(@types/node@20.14.10)(lightningcss@1.30.1)(terser@5.39.2)))(vite@5.4.19(@types/node@20.14.10)(lightningcss@1.30.1)(terser@5.39.2)) '@storybook/vue3': 9.1.1(storybook@9.1.6(@testing-library/dom@10.4.1)(prettier@3.3.2)(vite@5.4.19(@types/node@20.14.10)(lightningcss@1.30.1)(terser@5.39.2)))(vue@3.5.13(typescript@5.9.2)) find-package-json: 1.2.0 - magic-string: 0.30.18 + magic-string: 0.30.19 storybook: 9.1.6(@testing-library/dom@10.4.1)(prettier@3.3.2)(vite@5.4.19(@types/node@20.14.10)(lightningcss@1.30.1)(terser@5.39.2)) typescript: 5.9.2 vite: 5.4.19(@types/node@20.14.10)(lightningcss@1.30.1)(terser@5.39.2) @@ -9066,7 +9487,7 @@ snapshots: storybook: 9.1.6(@testing-library/dom@10.4.1)(prettier@3.3.2)(vite@5.4.19(@types/node@20.14.10)(lightningcss@1.30.1)(terser@5.39.2)) type-fest: 2.19.0 vue: 3.5.13(typescript@5.9.2) - vue-component-type-helpers: 3.0.8 + vue-component-type-helpers: 3.1.1 '@swc/helpers@0.5.17': dependencies: @@ -9078,7 +9499,7 @@ snapshots: enhanced-resolve: 5.18.3 jiti: 2.5.1 lightningcss: 1.30.1 - magic-string: 0.30.18 + magic-string: 0.30.19 source-map-js: 1.2.1 tailwindcss: 4.1.12 @@ -9331,9 +9752,9 @@ snapshots: '@trivago/prettier-plugin-sort-imports@5.2.2(@vue/compiler-sfc@3.5.13)(prettier@3.3.2)': dependencies: '@babel/generator': 7.28.3 - '@babel/parser': 7.28.3 + '@babel/parser': 7.28.4 '@babel/traverse': 7.28.3 - '@babel/types': 7.28.2 + '@babel/types': 7.28.4 javascript-natural-sort: 0.7.1 lodash: 4.17.21 prettier: 3.3.2 @@ -9484,7 +9905,7 @@ snapshots: '@typescript-eslint/types': 8.44.0 '@typescript-eslint/typescript-estree': 8.44.0(typescript@5.9.2) '@typescript-eslint/visitor-keys': 8.44.0 - debug: 4.4.1 + debug: 4.4.3 eslint: 9.35.0(jiti@2.4.2) typescript: 5.9.2 transitivePeerDependencies: @@ -9494,7 +9915,7 @@ snapshots: dependencies: '@typescript-eslint/tsconfig-utils': 8.44.0(typescript@5.9.2) '@typescript-eslint/types': 8.44.0 - debug: 4.4.1 + debug: 4.4.3 typescript: 5.9.2 transitivePeerDependencies: - supports-color @@ -9513,7 +9934,7 @@ snapshots: '@typescript-eslint/types': 8.44.0 '@typescript-eslint/typescript-estree': 8.44.0(typescript@5.9.2) '@typescript-eslint/utils': 8.44.0(eslint@9.35.0(jiti@2.4.2))(typescript@5.9.2) - debug: 4.4.1 + debug: 4.4.3 eslint: 9.35.0(jiti@2.4.2) ts-api-utils: 2.1.0(typescript@5.9.2) typescript: 5.9.2 @@ -9528,7 +9949,7 @@ snapshots: '@typescript-eslint/tsconfig-utils': 8.44.0(typescript@5.9.2) '@typescript-eslint/types': 8.44.0 '@typescript-eslint/visitor-keys': 8.44.0 - debug: 4.4.1 + debug: 4.4.3 fast-glob: 3.3.3 is-glob: 4.0.3 minimatch: 9.0.5 @@ -9564,12 +9985,12 @@ snapshots: '@ampproject/remapping': 2.3.0 '@bcoe/v8-coverage': 1.0.2 ast-v8-to-istanbul: 0.3.5 - debug: 4.4.1 + debug: 4.4.3 istanbul-lib-coverage: 3.2.2 istanbul-lib-report: 3.0.1 istanbul-lib-source-maps: 5.0.6 istanbul-reports: 3.2.0 - magic-string: 0.30.18 + magic-string: 0.30.19 magicast: 0.3.5 std-env: 3.9.0 test-exclude: 7.0.1 @@ -9590,7 +10011,7 @@ snapshots: dependencies: '@vitest/spy': 3.2.4 estree-walker: 3.0.3 - magic-string: 0.30.18 + magic-string: 0.30.19 optionalDependencies: vite: 5.4.19(@types/node@20.14.10)(lightningcss@1.30.1)(terser@5.39.2) @@ -9607,7 +10028,7 @@ snapshots: '@vitest/snapshot@3.2.4': dependencies: '@vitest/pretty-format': 3.2.4 - magic-string: 0.30.18 + magic-string: 0.30.19 pathe: 2.0.3 '@vitest/spy@3.2.4': @@ -9664,10 +10085,10 @@ snapshots: '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.27.1) '@babel/template': 7.27.2 '@babel/traverse': 7.28.3 - '@babel/types': 7.28.2 + '@babel/types': 7.28.4 '@vue/babel-helper-vue-transform-on': 1.4.0 '@vue/babel-plugin-resolve-type': 1.4.0(@babel/core@7.27.1) - '@vue/shared': 3.5.13 + '@vue/shared': 3.5.21 optionalDependencies: '@babel/core': 7.27.1 transitivePeerDependencies: @@ -9679,14 +10100,14 @@ snapshots: '@babel/core': 7.27.1 '@babel/helper-module-imports': 7.27.1 '@babel/helper-plugin-utils': 7.27.1 - '@babel/parser': 7.28.3 + '@babel/parser': 7.28.4 '@vue/compiler-sfc': 3.5.13 transitivePeerDependencies: - supports-color '@vue/compiler-core@3.5.13': dependencies: - '@babel/parser': 7.28.3 + '@babel/parser': 7.28.4 '@vue/shared': 3.5.13 entities: 4.5.0 estree-walker: 2.0.2 @@ -9712,13 +10133,13 @@ snapshots: '@vue/compiler-sfc@3.5.13': dependencies: - '@babel/parser': 7.28.3 + '@babel/parser': 7.28.4 '@vue/compiler-core': 3.5.13 '@vue/compiler-dom': 3.5.13 '@vue/compiler-ssr': 3.5.13 '@vue/shared': 3.5.13 estree-walker: 2.0.2 - magic-string: 0.30.18 + magic-string: 0.30.19 postcss: 8.5.1 source-map-js: 1.2.1 @@ -9776,9 +10197,9 @@ snapshots: '@vue/language-core@2.2.12(typescript@5.9.2)': dependencies: '@volar/language-core': 2.4.15 - '@vue/compiler-dom': 3.5.13 + '@vue/compiler-dom': 3.5.21 '@vue/compiler-vue2': 2.7.16 - '@vue/shared': 3.5.13 + '@vue/shared': 3.5.21 alien-signals: 1.0.13 minimatch: 9.0.5 muggle-string: 0.4.1 @@ -9789,9 +10210,9 @@ snapshots: '@vue/language-core@3.0.7(typescript@5.9.2)': dependencies: '@volar/language-core': 2.4.23 - '@vue/compiler-dom': 3.5.13 + '@vue/compiler-dom': 3.5.21 '@vue/compiler-vue2': 2.7.16 - '@vue/shared': 3.5.13 + '@vue/shared': 3.5.21 alien-signals: 2.0.7 muggle-string: 0.4.1 path-browserify: 1.0.1 @@ -10021,15 +10442,11 @@ snapshots: ansi-styles@6.2.1: {} - any-promise@1.3.0: {} - anymatch@3.1.3: dependencies: normalize-path: 3.0.0 picomatch: 2.3.1 - arg@5.0.2: {} - argparse@1.0.10: dependencies: sprintf-js: 1.0.3 @@ -10046,6 +10463,8 @@ snapshots: arr-rotate@1.0.0: {} + array-union@2.1.0: {} + asap@2.0.6: {} assert-never@1.4.0: {} @@ -10062,6 +10481,8 @@ snapshots: estree-walker: 3.0.3 js-tokens: 9.0.1 + astral-regex@2.0.0: {} + async@3.2.5: {} asynckit@0.4.0: {} @@ -10134,12 +10555,14 @@ snapshots: babel-walk@3.0.0-canary-5: dependencies: - '@babel/types': 7.28.2 + '@babel/types': 7.28.4 bail@2.0.2: {} balanced-match@1.0.2: {} + balanced-match@2.0.0: {} + base64-js@1.5.1: {} better-opn@3.0.2: @@ -10211,6 +10634,14 @@ snapshots: cac@6.7.14: {} + cacheable@2.0.3: + dependencies: + '@cacheable/memoize': 2.0.3 + '@cacheable/memory': 2.0.3 + '@cacheable/utils': 2.0.3 + hookified: 1.12.1 + keyv: 5.5.3 + call-bind-apply-helpers@1.0.2: dependencies: es-errors: 1.3.0 @@ -10235,8 +10666,6 @@ snapshots: pascal-case: 3.1.2 tslib: 2.8.1 - camelcase-css@2.0.1: {} - camelcase@8.0.0: {} caniuse-lite@1.0.30001737: {} @@ -10331,6 +10760,8 @@ snapshots: color-name@1.1.4: {} + colord@2.9.3: {} + colorette@2.0.20: {} columnify@1.6.0: @@ -10350,8 +10781,6 @@ snapshots: commander@2.20.3: {} - commander@4.1.1: {} - commander@8.3.0: {} compare-versions@6.1.1: {} @@ -10394,8 +10823,8 @@ snapshots: constantinople@4.0.1: dependencies: - '@babel/parser': 7.28.3 - '@babel/types': 7.28.2 + '@babel/parser': 7.28.4 + '@babel/types': 7.28.4 convert-source-map@2.0.0: {} @@ -10436,6 +10865,8 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 + css-functions-list@3.2.3: {} + css-select@4.3.0: dependencies: boolbase: 1.0.0 @@ -10444,6 +10875,11 @@ snapshots: domutils: 2.8.0 nth-check: 2.1.1 + css-tree@3.1.0: + dependencies: + mdn-data: 2.12.2 + source-map-js: 1.2.1 + css-what@6.1.0: {} css.escape@1.5.1: {} @@ -10472,10 +10908,6 @@ snapshots: dependencies: ms: 2.1.3 - debug@4.4.1: - dependencies: - ms: 2.1.3 - debug@4.4.3: dependencies: ms: 2.1.3 @@ -10526,7 +10958,7 @@ snapshots: detect-port@1.6.1: dependencies: address: 1.2.2 - debug: 4.4.1 + debug: 4.4.3 transitivePeerDependencies: - supports-color @@ -10534,18 +10966,18 @@ snapshots: dependencies: dequal: 2.0.3 - didyoumean@1.2.2: {} - diff-match-patch@1.0.5: {} + dir-glob@3.0.1: + dependencies: + path-type: 4.0.0 + dirty-json@0.9.2: dependencies: lex: 1.7.9 unescape-js: 1.1.4 utf8: 3.0.0 - dlv@1.1.3: {} - doctypes@1.1.0: {} dom-accessibility-api@0.5.16: {} @@ -10558,12 +10990,22 @@ snapshots: domhandler: 4.3.1 entities: 2.2.0 + dom-serializer@2.0.0: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + entities: 4.5.0 + domelementtype@2.3.0: {} domhandler@4.3.1: dependencies: domelementtype: 2.3.0 + domhandler@5.0.3: + dependencies: + domelementtype: 2.3.0 + dompurify@3.2.5: optionalDependencies: '@types/trusted-types': 2.0.7 @@ -10574,6 +11016,12 @@ snapshots: domelementtype: 2.3.0 domhandler: 4.3.1 + domutils@3.2.2: + dependencies: + dom-serializer: 2.0.0 + domelementtype: 2.3.0 + domhandler: 5.0.3 + dot-case@3.0.4: dependencies: no-case: 3.0.4 @@ -10672,7 +11120,7 @@ snapshots: esbuild-register@3.6.0(esbuild@0.25.5): dependencies: - debug: 4.4.1 + debug: 4.4.3 esbuild: 0.25.5 transitivePeerDependencies: - supports-color @@ -10816,7 +11264,7 @@ snapshots: ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.6 - debug: 4.4.1 + debug: 4.4.3 escape-string-regexp: 4.0.0 eslint-scope: 8.4.0 eslint-visitor-keys: 4.2.1 @@ -10968,6 +11416,8 @@ snapshots: fast-uri@3.0.3: {} + fastest-levenshtein@1.0.16: {} + fastq@1.17.1: dependencies: reusify: 1.0.4 @@ -10998,6 +11448,10 @@ snapshots: dependencies: is-unicode-supported: 2.1.0 + file-entry-cache@10.1.4: + dependencies: + flat-cache: 6.1.17 + file-entry-cache@8.0.0: dependencies: flat-cache: 4.0.1 @@ -11055,6 +11509,12 @@ snapshots: flatted: 3.3.3 keyv: 4.5.4 + flat-cache@6.1.17: + dependencies: + cacheable: 2.0.3 + flatted: 3.3.3 + hookified: 1.12.1 + flat@5.0.2: {} flatted@3.3.3: {} @@ -11096,7 +11556,7 @@ snapshots: fs-extra@10.1.0: dependencies: graceful-fs: 4.2.11 - jsonfile: 6.1.0 + jsonfile: 6.2.0 universalify: 2.0.1 fs-extra@11.2.0: @@ -11186,12 +11646,33 @@ snapshots: dependencies: ini: 4.1.1 + global-modules@2.0.0: + dependencies: + global-prefix: 3.0.0 + + global-prefix@3.0.0: + dependencies: + ini: 1.3.8 + kind-of: 6.0.3 + which: 1.3.1 + globals@14.0.0: {} globals@15.15.0: {} globals@16.4.0: {} + globby@11.1.0: + dependencies: + array-union: 2.1.0 + dir-glob: 3.0.1 + fast-glob: 3.3.3 + ignore: 5.3.1 + merge2: 1.4.1 + slash: 3.0.0 + + globjoin@0.1.4: {} + gopd@1.2.0: {} gpt-tokenizer@2.9.0: {} @@ -11237,6 +11718,8 @@ snapshots: hookable@5.5.3: {} + hookified@1.12.1: {} + hosted-git-info@7.0.2: dependencies: lru-cache: 10.4.3 @@ -11257,19 +11740,28 @@ snapshots: relateurl: 0.2.7 terser: 5.39.2 + html-tags@3.3.1: {} + + htmlparser2@8.0.2: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.2.2 + entities: 4.5.0 + http-parser-js@0.5.10: {} http-proxy-agent@7.0.2: dependencies: agent-base: 7.1.4 - debug: 4.4.1 + debug: 4.4.3 transitivePeerDependencies: - supports-color https-proxy-agent@7.0.6: dependencies: agent-base: 7.1.4 - debug: 4.4.1 + debug: 4.4.3 transitivePeerDependencies: - supports-color @@ -11411,6 +11903,8 @@ snapshots: is-plain-obj@4.1.0: {} + is-plain-object@5.0.0: {} + is-potential-custom-element-name@1.0.1: {} is-promise@2.2.2: {} @@ -11459,7 +11953,7 @@ snapshots: istanbul-lib-source-maps@5.0.6: dependencies: '@jridgewell/trace-mapping': 0.3.30 - debug: 4.4.1 + debug: 4.4.3 istanbul-lib-coverage: 3.2.2 transitivePeerDependencies: - supports-color @@ -11495,8 +11989,6 @@ snapshots: chalk: 4.1.2 pretty-format: 30.0.5 - jiti@1.21.7: {} - jiti@2.4.2: {} jiti@2.5.1: {} @@ -11628,6 +12120,10 @@ snapshots: dependencies: json-buffer: 3.0.1 + keyv@5.5.3: + dependencies: + '@keyv/serialize': 1.1.1 + kind-of@6.0.3: {} knip@5.62.0(@types/node@20.14.10)(typescript@5.9.2): @@ -11636,7 +12132,7 @@ snapshots: '@types/node': 20.14.10 fast-glob: 3.3.3 formatly: 0.2.4 - jiti: 2.4.2 + jiti: 2.5.1 js-yaml: 4.1.0 minimist: 1.2.8 oxc-resolver: 11.6.1 @@ -11648,6 +12144,8 @@ snapshots: zod: 3.24.1 zod-validation-error: 3.3.0(zod@3.24.1) + known-css-properties@0.37.0: {} + kolorist@1.8.0: {} ky@1.9.0: {} @@ -11718,8 +12216,6 @@ snapshots: lilconfig@3.1.2: {} - lilconfig@3.1.3: {} - lines-and-columns@1.2.4: {} lines-and-columns@2.0.3: {} @@ -11756,7 +12252,7 @@ snapshots: local-pkg@0.5.1: dependencies: - mlly: 1.7.4 + mlly: 1.8.0 pkg-types: 1.3.1 local-pkg@1.1.2: @@ -11777,6 +12273,8 @@ snapshots: lodash.merge@4.6.2: {} + lodash.truncate@4.4.2: {} + lodash@4.17.21: {} log-symbols@4.1.0: @@ -11820,18 +12318,14 @@ snapshots: lz-string@1.5.0: {} - magic-string@0.30.18: - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - magic-string@0.30.19: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 magicast@0.3.5: dependencies: - '@babel/parser': 7.28.3 - '@babel/types': 7.28.2 + '@babel/parser': 7.28.4 + '@babel/types': 7.28.4 source-map-js: 1.2.1 make-dir@4.0.0: @@ -11855,6 +12349,8 @@ snapshots: math-intrinsics@1.1.0: {} + mathml-tag-names@2.1.3: {} + mdast-util-find-and-replace@3.0.2: dependencies: '@types/mdast': 4.0.4 @@ -11968,6 +12464,8 @@ snapshots: dependencies: '@types/mdast': 4.0.4 + mdn-data@2.12.2: {} + mdurl@2.0.0: {} media-encoder-host-broker@8.0.19: @@ -11992,6 +12490,8 @@ snapshots: media-encoder-host-worker: 10.0.19 tslib: 2.8.1 + meow@13.2.0: {} + merge-stream@2.0.0: {} merge2@1.4.1: {} @@ -12177,7 +12677,7 @@ snapshots: micromark@4.0.2: dependencies: '@types/debug': 4.1.12 - debug: 4.4.1 + debug: 4.4.3 decode-named-character-reference: 1.2.0 devlop: 1.1.0 micromark-core-commonmark: 2.0.3 @@ -12251,13 +12751,6 @@ snapshots: mkdirp@3.0.1: {} - mlly@1.7.4: - dependencies: - acorn: 8.15.0 - pathe: 2.0.3 - pkg-types: 1.3.1 - ufo: 1.5.4 - mlly@1.8.0: dependencies: acorn: 8.15.0 @@ -12276,11 +12769,7 @@ snapshots: '@babel/runtime': 7.28.4 tslib: 2.8.1 - mz@2.7.0: - dependencies: - any-promise: 1.3.0 - object-assign: 4.1.1 - thenify-all: 1.6.0 + nanoid@3.3.11: {} nanoid@3.3.8: {} @@ -12395,8 +12884,6 @@ snapshots: object-assign@4.1.1: {} - object-hash@3.0.0: {} - object-keys@1.1.1: {} ohash@2.0.11: {} @@ -12587,8 +13074,6 @@ snapshots: pidtree@0.6.0: {} - pify@2.3.0: {} - pinia@2.2.2(typescript@5.9.2)(vue@3.5.13(typescript@5.9.2)): dependencies: '@vue/devtools-api': 6.6.3 @@ -12597,12 +13082,10 @@ snapshots: optionalDependencies: typescript: 5.9.2 - pirates@4.0.7: {} - pkg-types@1.3.1: dependencies: confbox: 0.1.8 - mlly: 1.7.4 + mlly: 1.8.0 pathe: 2.0.3 pkg-types@2.3.0: @@ -12619,36 +13102,29 @@ snapshots: optionalDependencies: fsevents: 2.3.2 - postcss-import@15.1.0(postcss@8.5.1): + postcss-html@1.8.0: dependencies: + htmlparser2: 8.0.2 + js-tokens: 9.0.1 postcss: 8.5.1 - postcss-value-parser: 4.2.0 - read-cache: 1.0.0 - resolve: 1.22.10 + postcss-safe-parser: 6.0.0(postcss@8.5.1) - postcss-js@4.1.0(postcss@8.5.1): + postcss-resolve-nested-selector@0.1.6: {} + + postcss-safe-parser@6.0.0(postcss@8.5.1): dependencies: - camelcase-css: 2.0.1 postcss: 8.5.1 - postcss-load-config@4.0.2(postcss@8.5.1): + postcss-safe-parser@7.0.1(postcss@8.5.6): dependencies: - lilconfig: 3.1.3 - yaml: 2.8.1 - optionalDependencies: - postcss: 8.5.1 - - postcss-nested@6.2.0(postcss@8.5.1): - dependencies: - postcss: 8.5.1 - postcss-selector-parser: 6.1.2 + postcss: 8.5.6 postcss-selector-parser@6.1.0: dependencies: cssesc: 3.0.0 util-deprecate: 1.0.2 - postcss-selector-parser@6.1.2: + postcss-selector-parser@7.1.0: dependencies: cssesc: 3.0.0 util-deprecate: 1.0.2 @@ -12661,6 +13137,12 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 + postcss@8.5.6: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + prelude-ls@1.2.1: {} prettier-linter-helpers@1.0.0: @@ -12930,10 +13412,6 @@ snapshots: react@19.1.1: {} - read-cache@1.0.0: - dependencies: - pify: 2.3.0 - readable-stream@2.3.8: dependencies: core-util-is: 1.0.3 @@ -13072,6 +13550,8 @@ snapshots: resolve-from@4.0.0: {} + resolve-from@5.0.0: {} + resolve-pkg-maps@1.0.0: {} resolve.exports@2.0.3: {} @@ -13184,6 +13664,14 @@ snapshots: mrmime: 2.0.1 totalist: 3.0.1 + slash@3.0.0: {} + + slice-ansi@4.0.0: + dependencies: + ansi-styles: 4.3.0 + astral-regex: 2.0.0 + is-fullwidth-code-point: 3.0.0 + slice-ansi@5.0.0: dependencies: ansi-styles: 6.2.1 @@ -13310,22 +13798,56 @@ snapshots: stubborn-fs@1.2.5: {} + stylelint@16.24.0(typescript@5.9.2): + dependencies: + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-tokenizer': 3.0.4 + '@csstools/media-query-list-parser': 4.0.3(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + '@csstools/selector-specificity': 5.0.0(postcss-selector-parser@7.1.0) + '@dual-bundle/import-meta-resolve': 4.2.1 + balanced-match: 2.0.0 + colord: 2.9.3 + cosmiconfig: 9.0.0(typescript@5.9.2) + css-functions-list: 3.2.3 + css-tree: 3.1.0 + debug: 4.4.3 + fast-glob: 3.3.3 + fastest-levenshtein: 1.0.16 + file-entry-cache: 10.1.4 + global-modules: 2.0.0 + globby: 11.1.0 + globjoin: 0.1.4 + html-tags: 3.3.1 + ignore: 7.0.5 + imurmurhash: 0.1.4 + is-plain-object: 5.0.0 + known-css-properties: 0.37.0 + mathml-tag-names: 2.1.3 + meow: 13.2.0 + micromatch: 4.0.8 + normalize-path: 3.0.0 + picocolors: 1.1.1 + postcss: 8.5.6 + postcss-resolve-nested-selector: 0.1.6 + postcss-safe-parser: 7.0.1(postcss@8.5.6) + postcss-selector-parser: 7.1.0 + postcss-value-parser: 4.2.0 + resolve-from: 5.0.0 + string-width: 4.2.3 + supports-hyperlinks: 3.2.0 + svg-tags: 1.0.0 + table: 6.9.0 + write-file-atomic: 5.0.1 + transitivePeerDependencies: + - supports-color + - typescript + subscribable-things@2.1.53: dependencies: '@babel/runtime': 7.28.4 rxjs-interop: 2.0.0 tslib: 2.8.1 - sucrase@3.35.0: - dependencies: - '@jridgewell/gen-mapping': 0.3.13 - commander: 4.1.1 - glob: 10.4.5 - lines-and-columns: 1.2.4 - mz: 2.7.0 - pirates: 4.0.7 - ts-interface-checker: 0.1.13 - superjson@2.2.2: dependencies: copy-anything: 3.0.5 @@ -13338,8 +13860,15 @@ snapshots: dependencies: has-flag: 4.0.0 + supports-hyperlinks@3.2.0: + dependencies: + has-flag: 4.0.0 + supports-color: 7.2.0 + supports-preserve-symlinks-flag@1.0.0: {} + svg-tags@1.0.0: {} + swr@2.3.6(react@19.1.1): dependencies: dequal: 2.0.3 @@ -13357,39 +13886,20 @@ snapshots: dependencies: '@pkgr/core': 0.2.9 + table@6.9.0: + dependencies: + ajv: 8.17.1 + lodash.truncate: 4.4.2 + slice-ansi: 4.0.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + tailwind-merge@2.6.0: {} tailwindcss-primeui@0.6.1(tailwindcss@4.1.12): dependencies: tailwindcss: 4.1.12 - tailwindcss@3.4.17: - 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.3 - glob-parent: 6.0.2 - is-glob: 4.0.3 - jiti: 1.21.7 - lilconfig: 3.1.3 - micromatch: 4.0.8 - normalize-path: 3.0.0 - object-hash: 3.0.0 - picocolors: 1.1.1 - postcss: 8.5.1 - postcss-import: 15.1.0(postcss@8.5.1) - postcss-js: 4.1.0(postcss@8.5.1) - postcss-load-config: 4.0.2(postcss@8.5.1) - postcss-nested: 6.2.0(postcss@8.5.1) - postcss-selector-parser: 6.1.2 - resolve: 1.22.10 - sucrase: 3.35.0 - transitivePeerDependencies: - - ts-node - tailwindcss@4.1.12: {} tapable@2.2.3: {} @@ -13424,14 +13934,6 @@ snapshots: glob: 10.4.5 minimatch: 9.0.5 - thenify-all@1.6.0: - dependencies: - thenify: 3.3.1 - - thenify@3.3.1: - dependencies: - any-promise: 1.3.0 - three@0.170.0: {} tiny-invariant@1.3.3: {} @@ -13497,8 +13999,6 @@ snapshots: ts-dedent@2.2.0: {} - ts-interface-checker@0.1.13: {} - ts-map@1.0.3: {} tsconfig-paths@4.2.0: @@ -13545,8 +14045,6 @@ snapshots: uc.micro@2.1.0: {} - ufo@1.5.4: {} - ufo@1.6.1: {} uint8array-extras@1.5.0: {} @@ -13606,7 +14104,7 @@ snapshots: '@antfu/install-pkg': 0.5.0 '@antfu/utils': 0.7.10 '@iconify/utils': 2.3.0 - debug: 4.4.1 + debug: 4.4.3 kolorist: 1.8.0 local-pkg: 0.5.1 unplugin: 2.3.5 @@ -13618,14 +14116,14 @@ snapshots: unplugin-vue-components@0.28.0(@babel/parser@7.28.4)(rollup@4.22.4)(vue@3.5.13(typescript@5.9.2)): dependencies: '@antfu/utils': 0.7.10 - '@rollup/pluginutils': 5.1.4(rollup@4.22.4) + '@rollup/pluginutils': 5.3.0(rollup@4.22.4) chokidar: 3.6.0 - debug: 4.4.1 + debug: 4.4.3 fast-glob: 3.3.3 local-pkg: 0.5.1 - magic-string: 0.30.18 + magic-string: 0.30.19 minimatch: 9.0.5 - mlly: 1.7.4 + mlly: 1.8.0 unplugin: 2.3.5 vue: 3.5.13(typescript@5.9.2) optionalDependencies: @@ -13697,7 +14195,7 @@ snapshots: vite-node@3.2.4(@types/node@20.14.10)(lightningcss@1.30.1)(terser@5.39.2): dependencies: cac: 6.7.14 - debug: 4.4.1 + debug: 4.4.3 es-module-lexer: 1.7.0 pathe: 2.0.3 vite: 5.4.19(@types/node@20.14.10)(lightningcss@1.30.1)(terser@5.39.2) @@ -13750,10 +14248,10 @@ snapshots: vite-plugin-inspect@0.8.9(rollup@4.22.4)(vite@5.4.19(@types/node@20.14.10)(lightningcss@1.30.1)(terser@5.39.2)): dependencies: '@antfu/utils': 0.7.10 - '@rollup/pluginutils': 5.1.4(rollup@4.22.4) - debug: 4.4.1 + '@rollup/pluginutils': 5.3.0(rollup@4.22.4) + debug: 4.4.3 error-stack-parser-es: 0.1.5 - fs-extra: 11.2.0 + fs-extra: 11.3.2 open: 10.1.2 perfect-debounce: 1.0.0 picocolors: 1.1.1 @@ -13787,9 +14285,9 @@ snapshots: '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.27.1) '@babel/plugin-transform-typescript': 7.27.1(@babel/core@7.27.1) '@vue/babel-plugin-jsx': 1.4.0(@babel/core@7.27.1) - '@vue/compiler-dom': 3.5.13 + '@vue/compiler-dom': 3.5.21 kolorist: 1.8.0 - magic-string: 0.30.18 + magic-string: 0.30.19 vite: 5.4.19(@types/node@20.14.10)(lightningcss@1.30.1)(terser@5.39.2) transitivePeerDependencies: - supports-color @@ -13816,9 +14314,9 @@ snapshots: '@vitest/spy': 3.2.4 '@vitest/utils': 3.2.4 chai: 5.3.3 - debug: 4.4.1 + debug: 4.4.3 expect-type: 1.2.2 - magic-string: 0.30.18 + magic-string: 0.30.19 pathe: 2.0.3 picomatch: 4.0.3 std-env: 3.9.0 @@ -13862,9 +14360,9 @@ snapshots: vue-component-type-helpers@2.2.12: {} - vue-component-type-helpers@3.0.7: {} + vue-component-type-helpers@3.1.0: {} - vue-component-type-helpers@3.0.8: {} + vue-component-type-helpers@3.1.1: {} vue-demi@0.14.10(vue@3.5.13(typescript@5.9.2)): dependencies: @@ -13872,9 +14370,9 @@ snapshots: vue-docgen-api@4.79.2(vue@3.5.13(typescript@5.9.2)): dependencies: - '@babel/parser': 7.28.3 - '@babel/types': 7.28.2 - '@vue/compiler-dom': 3.5.13 + '@babel/parser': 7.28.4 + '@babel/types': 7.28.4 + '@vue/compiler-dom': 3.5.21 '@vue/compiler-sfc': 3.5.13 ast-types: 0.16.1 esm-resolve: 1.0.11 @@ -13888,7 +14386,7 @@ snapshots: vue-eslint-parser@10.2.0(eslint@9.35.0(jiti@2.4.2)): dependencies: - debug: 4.4.1 + debug: 4.4.3 eslint: 9.35.0(jiti@2.4.2) eslint-scope: 8.4.0 eslint-visitor-keys: 4.2.1 @@ -13988,6 +14486,10 @@ snapshots: when-exit@2.1.4: {} + which@1.3.1: + dependencies: + isexe: 2.0.0 + which@2.0.2: dependencies: isexe: 2.0.0 @@ -14003,8 +14505,8 @@ snapshots: with@7.0.2: dependencies: - '@babel/parser': 7.28.3 - '@babel/types': 7.28.2 + '@babel/parser': 7.28.4 + '@babel/types': 7.28.4 assert-never: 1.4.0 babel-walk: 3.0.0-canary-5 @@ -14036,6 +14538,11 @@ snapshots: wrappy@1.0.2: {} + write-file-atomic@5.0.1: + dependencies: + imurmurhash: 0.1.4 + signal-exit: 4.1.0 + ws@8.18.3: {} xdg-basedir@5.1.0: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 0b9e0d06b..647025a37 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -2,6 +2,117 @@ packages: - apps/** - packages/** +catalog: + # Core frameworks + typescript: ^5.9.2 + vue: ^3.5.13 + + # Build tools + '@nx/eslint': 21.4.1 + '@nx/playwright': 21.4.1 + '@nx/storybook': 21.4.1 + '@nx/vite': 21.4.1 + nx: 21.4.1 + tsx: ^4.15.6 + vite: ^5.4.19 + '@vitejs/plugin-vue': ^5.1.4 + 'vite-plugin-dts': ^4.5.4 + vue-tsc: ^3.0.7 + + # Testing + 'happy-dom': ^15.11.0 + jsdom: ^26.1.0 + '@pinia/testing': ^0.1.5 + '@playwright/test': ^1.52.0 + '@vitest/coverage-v8': ^3.2.4 + '@vitest/ui': ^3.0.0 + vitest: ^3.2.4 + '@vue/test-utils': ^2.4.6 + + # Linting & Formatting + '@eslint/js': ^9.35.0 + eslint: ^9.34.0 + 'eslint-config-prettier': ^10.1.8 + 'eslint-plugin-prettier': ^5.5.4 + 'eslint-plugin-storybook': ^9.1.6 + 'eslint-plugin-unused-imports': ^4.2.0 + 'eslint-plugin-vue': ^10.4.0 + globals: ^15.9.0 + '@intlify/eslint-plugin-vue-i18n': ^4.1.0 + postcss-html: ^1.8.0 + prettier: ^3.3.2 + stylelint: ^16.24.0 + 'typescript-eslint': ^8.44.0 + 'vue-eslint-parser': ^10.2.0 + + # Vue ecosystem + '@sentry/vue': ^8.48.0 + '@vueuse/core': ^11.0.0 + '@vueuse/integrations': ^13.9.0 + 'vite-plugin-html': ^3.2.2 + 'vite-plugin-vue-devtools': ^7.7.6 + pinia: ^2.1.7 + 'vue-i18n': ^9.14.3 + 'vue-router': ^4.4.3 + vuefire: ^3.2.1 + + # PrimeVue UI framework + '@primeuix/forms': 0.0.2 + '@primeuix/styled': 0.3.2 + '@primeuix/utils': ^0.3.2 + '@primevue/core': ^4.2.5 + '@primevue/forms': ^4.2.5 + '@primevue/icons': 4.2.5 + '@primevue/themes': ^4.2.5 + primeicons: ^7.0.0 + primevue: ^4.2.5 + + # Tailwind CSS and design + '@iconify/json': ^2.2.380 + '@iconify-json/lucide': ^1.1.178 + '@iconify/tailwind': ^1.1.3 + '@tailwindcss/vite': ^4.1.12 + tailwindcss: ^4.1.12 + 'tailwindcss-primeui': ^0.6.1 + 'tw-animate-css': ^1.3.8 + 'unplugin-icons': ^0.22.0 + 'unplugin-vue-components': ^0.28.0 + + # Storybook + '@storybook/addon-docs': ^9.1.1 + storybook: ^9.1.6 + '@storybook/vue3': ^9.1.1 + '@storybook/vue3-vite': ^9.1.1 + + # Data and validation + algoliasearch: ^5.21.0 + axios: ^1.11.0 + firebase: ^11.6.0 + yjs: ^13.6.27 + zod: ^3.23.8 + 'zod-validation-error': ^3.3.0 + + # Dev tools + dotenv: ^16.4.5 + husky: ^9.0.11 + jiti: 2.4.2 + knip: ^5.62.0 + 'lint-staged': ^15.2.7 + + # Type definitions + '@types/fs-extra': ^11.0.4 + '@types/jsdom': ^21.1.7 + '@types/node': ^20.14.8 + '@types/semver': ^7.7.0 + '@types/three': ^0.169.0 + 'vue-component-type-helpers': ^3.0.7 + 'zod-to-json-schema': ^3.24.1 + + # i18n + '@alloc/quick-lru': ^5.2.0 + '@lobehub/i18n-cli': ^1.25.1 + '@trivago/prettier-plugin-sort-imports': ^5.2.0 + ignoredBuiltDependencies: - '@firebase/util' - protobufjs diff --git a/scripts/cicd/check-json.sh b/scripts/cicd/check-json.sh new file mode 100755 index 000000000..89e6a5c8f --- /dev/null +++ b/scripts/cicd/check-json.sh @@ -0,0 +1,77 @@ +#!/bin/bash +set -euo pipefail + +usage() { + echo "Usage: $0 [--debug]" >&2 +} + +debug=0 + +while [ "$#" -gt 0 ]; do + case "$1" in + --debug) + debug=1 + ;; + -h|--help) + usage + exit 0 + ;; + *) + echo "Unknown option: $1" >&2 + usage + exit 2 + ;; + esac + shift +done + +# Validate JSON syntax in tracked files using jq +if ! command -v jq >/dev/null 2>&1; then + echo "Error: jq is required but not installed" >&2 + exit 127 +fi + +EXCLUDE_PATTERNS=( + '**/tsconfig*.json' +) + +if [ -n "${JSON_LINT_EXCLUDES:-}" ]; then + # shellcheck disable=SC2206 + EXCLUDE_PATTERNS+=( ${JSON_LINT_EXCLUDES} ) +fi + +pathspecs=(-- '*.json') +for pattern in "${EXCLUDE_PATTERNS[@]}"; do + if [[ ${pattern:0:1} == ':' ]]; then + pathspecs+=("$pattern") + else + pathspecs+=(":(glob,exclude)${pattern}") + fi +done + +mapfile -t json_files < <(git ls-files "${pathspecs[@]}") + +if [ "${#json_files[@]}" -eq 0 ]; then + echo 'No JSON files found.' + exit 0 +fi + +if [ "$debug" -eq 1 ]; then + echo 'JSON files to validate:' + printf ' %s\n' "${json_files[@]}" +fi + +failed=0 +for file in "${json_files[@]}"; do + if ! jq -e . "$file" >/dev/null; then + echo "Invalid JSON syntax: $file" >&2 + failed=1 + fi +done + +if [ "$failed" -ne 0 ]; then + echo 'JSON validation failed.' >&2 + exit 1 +fi + +echo 'All JSON files are valid.' diff --git a/scripts/cicd/pr-storybook-deploy-and-comment.sh b/scripts/cicd/pr-storybook-deploy-and-comment.sh new file mode 100755 index 000000000..a2a1d37e9 --- /dev/null +++ b/scripts/cicd/pr-storybook-deploy-and-comment.sh @@ -0,0 +1,247 @@ +#!/bin/bash +set -e + +# Deploy Storybook to Cloudflare Pages and comment on PR +# Usage: ./pr-storybook-deploy-and-comment.sh [start_time] + +# Input validation +# Validate PR number is numeric +case "$1" in + ''|*[!0-9]*) + echo "Error: PR_NUMBER must be numeric" >&2 + exit 1 + ;; +esac +PR_NUMBER="$1" + +# Sanitize and validate branch name (allow alphanumeric, dots, dashes, underscores, slashes) +BRANCH_NAME=$(echo "$2" | sed 's/[^a-zA-Z0-9._/-]//g') +if [ -z "$BRANCH_NAME" ]; then + echo "Error: Invalid or empty branch name" >&2 + exit 1 +fi + +# Validate status parameter +STATUS="${3:-completed}" +case "$STATUS" in + starting|completed) ;; + *) + echo "Error: STATUS must be 'starting' or 'completed'" >&2 + exit 1 + ;; +esac + +START_TIME="${4:-$(date -u '+%m/%d/%Y, %I:%M:%S %p')}" + +# Required environment variables +: "${GITHUB_TOKEN:?GITHUB_TOKEN is required}" +: "${GITHUB_REPOSITORY:?GITHUB_REPOSITORY is required}" + +# Cloudflare variables only required for deployment +if [ "$STATUS" = "completed" ]; then + : "${CLOUDFLARE_API_TOKEN:?CLOUDFLARE_API_TOKEN is required for deployment}" + : "${CLOUDFLARE_ACCOUNT_ID:?CLOUDFLARE_ACCOUNT_ID is required for deployment}" +fi + +# Configuration +COMMENT_MARKER="" + +# Install wrangler if not available (output to stderr for debugging) +if ! command -v wrangler > /dev/null 2>&1; then + echo "Installing wrangler v4..." >&2 + npm install -g wrangler@^4.0.0 >&2 || { + echo "Failed to install wrangler" >&2 + echo "failed" + return + } +fi + +# Deploy Storybook report, WARN: ensure inputs are sanitized before calling this function +deploy_storybook() { + dir="$1" + branch="$2" + + [ ! -d "$dir" ] && echo "failed" && return + + project="comfy-storybook" + + echo "Deploying Storybook to project $project on branch $branch..." >&2 + + # Try deployment up to 3 times + i=1 + while [ $i -le 3 ]; do + echo "Deployment attempt $i of 3..." >&2 + # Branch is already sanitized, use it directly + if output=$(wrangler pages deploy "$dir" \ + --project-name="$project" \ + --branch="$branch" 2>&1); then + + # Extract URL from output (improved regex for valid URL characters) + url=$(echo "$output" | grep -oE 'https://[a-zA-Z0-9.-]+\.pages\.dev\S*' | head -1) + result="${url:-https://${branch}.${project}.pages.dev}" + echo "Success! URL: $result" >&2 + echo "$result" # Only this goes to stdout for capture + return + else + echo "Deployment failed on attempt $i: $output" >&2 + fi + [ $i -lt 3 ] && sleep 10 + i=$((i + 1)) + done + + echo "failed" +} + +# Post or update GitHub comment +post_comment() { + body="$1" + temp_file=$(mktemp) + echo "$body" > "$temp_file" + + if command -v gh > /dev/null 2>&1; then + # Find existing comment ID + existing=$(gh api "repos/$GITHUB_REPOSITORY/issues/$PR_NUMBER/comments" \ + --jq ".[] | select(.body | contains(\"$COMMENT_MARKER\")) | .id" | head -1) + + if [ -n "$existing" ]; then + # Update specific comment by ID + gh api --method PATCH "repos/$GITHUB_REPOSITORY/issues/comments/$existing" \ + --field body="$(cat "$temp_file")" + else + gh pr comment "$PR_NUMBER" --body-file "$temp_file" + fi + else + echo "GitHub CLI not available, outputting comment:" + cat "$temp_file" + fi + + rm -f "$temp_file" +} + +# Main execution +if [ "$STATUS" = "starting" ]; then + # Check if this is a version-bump branch + IS_VERSION_BUMP="false" + if echo "$BRANCH_NAME" | grep -q "^version-bump-"; then + IS_VERSION_BUMP="true" + fi + + # Post starting comment with appropriate message + if [ "$IS_VERSION_BUMP" = "true" ]; then + comment=$(cat < **Build is starting...** + +⏰ Started at: $START_TIME UTC + +### 🚀 Building Storybook +- 📦 Installing dependencies... +- 🔧 Building Storybook components... +- 🎨 Running Chromatic visual tests... + +--- +⏱️ Please wait while the Storybook build is in progress... +EOF +) + else + comment=$(cat < **Build is starting...** + +⏰ Started at: $START_TIME UTC + +### 🚀 Building Storybook +- 📦 Installing dependencies... +- 🔧 Building Storybook components... +- 🌐 Preparing deployment to Cloudflare Pages... + +--- +⏱️ Please wait while the Storybook build is in progress... +EOF +) + fi + post_comment "$comment" + +elif [ "$STATUS" = "completed" ]; then + # Deploy and post completion comment + # Convert branch name to Cloudflare-compatible format (lowercase, only alphanumeric and dashes) + cloudflare_branch=$(echo "$BRANCH_NAME" | tr '[:upper:]' '[:lower:]' | \ + sed 's/[^a-z0-9-]/-/g' | sed 's/--*/-/g' | sed 's/^-\|-$//g') + + echo "Looking for Storybook build in: $(pwd)/storybook-static" + + # Deploy Storybook if build exists + deployment_url="Not deployed" + if [ -d "storybook-static" ]; then + echo "Found Storybook build, deploying..." + url=$(deploy_storybook "storybook-static" "$cloudflare_branch") + if [ "$url" != "failed" ] && [ -n "$url" ]; then + deployment_url="[View Storybook]($url)" + else + deployment_url="Deployment failed" + fi + else + echo "Storybook build not found at storybook-static" + fi + + # Get workflow conclusion from environment or default to success + WORKFLOW_CONCLUSION="${WORKFLOW_CONCLUSION:-success}" + WORKFLOW_URL="${WORKFLOW_URL:-}" + + # Generate completion comment based on conclusion + if [ "$WORKFLOW_CONCLUSION" = "success" ]; then + status_icon="✅" + status_text="Build completed successfully!" + footer_text="🎉 Your Storybook is ready for review!" + elif [ "$WORKFLOW_CONCLUSION" = "skipped" ]; then + status_icon="⏭️" + status_text="Build skipped." + footer_text="ℹ️ Chromatic was skipped for this PR." + elif [ "$WORKFLOW_CONCLUSION" = "cancelled" ]; then + status_icon="🚫" + status_text="Build cancelled." + footer_text="ℹ️ The Chromatic run was cancelled." + else + status_icon="❌" + status_text="Build failed!" + footer_text="⚠️ Please check the workflow logs for error details." + fi + + comment="$COMMENT_MARKER +## 🎨 Storybook Build Status + +$status_icon **$status_text** + +⏰ Completed at: $(date -u '+%m/%d/%Y, %I:%M:%S %p') UTC + +### 🔗 Links +- [📊 View Workflow Run]($WORKFLOW_URL)" + + # Add deployment status + if [ "$deployment_url" != "Not deployed" ]; then + if [ "$deployment_url" = "Deployment failed" ]; then + comment="$comment +- ❌ Storybook deployment failed" + elif [ "$WORKFLOW_CONCLUSION" = "success" ]; then + comment="$comment +- 🎨 $deployment_url" + else + comment="$comment +- ⚠️ Build failed - $deployment_url" + fi + elif [ "$WORKFLOW_CONCLUSION" != "success" ]; then + comment="$comment +- ⏭️ Storybook deployment skipped (build did not succeed)" + fi + + comment="$comment + +--- +$footer_text" + + post_comment "$comment" +fi \ No newline at end of file diff --git a/scripts/collect-i18n-general.ts b/scripts/collect-i18n-general.ts index 53c813fb7..1bbcb2060 100644 --- a/scripts/collect-i18n-general.ts +++ b/scripts/collect-i18n-general.ts @@ -1,12 +1,15 @@ import * as fs from 'fs' +import { DESKTOP_DIALOGS } from '../apps/desktop-ui/src/constants/desktopDialogs' import { comfyPageFixture as test } from '../browser_tests/fixtures/ComfyPage' +import { + formatCamelCase, + normalizeI18nKey +} from '../packages/shared-frontend-utils/src/formatUtil' import { CORE_MENU_COMMANDS } from '../src/constants/coreMenuCommands' -import { DESKTOP_DIALOGS } from '../src/constants/desktopDialogs' import { SERVER_CONFIG_ITEMS } from '../src/constants/serverConfig' import type { FormItem, SettingParams } from '../src/platform/settings/types' import type { ComfyCommandImpl } from '../src/stores/commandStore' -import { formatCamelCase, normalizeI18nKey } from '../src/utils/formatUtil' const localePath = './src/locales/en/main.json' const commandsPath = './src/locales/en/commands.json' diff --git a/scripts/collect-i18n-node-defs.ts b/scripts/collect-i18n-node-defs.ts index 99ab97a66..46d85ad73 100644 --- a/scripts/collect-i18n-node-defs.ts +++ b/scripts/collect-i18n-node-defs.ts @@ -3,8 +3,8 @@ import * as fs from 'fs' import type { ComfyNodeDef } from '@/schemas/nodeDefSchema' import { comfyPageFixture as test } from '../browser_tests/fixtures/ComfyPage' +import { normalizeI18nKey } from '../packages/shared-frontend-utils/src/formatUtil' import type { ComfyNodeDefImpl } from '../src/stores/nodeDefStore' -import { normalizeI18nKey } from '../src/utils/formatUtil' const localePath = './src/locales/en/main.json' const nodeDefsPath = './src/locales/en/nodeDefs.json' diff --git a/src/App.vue b/src/App.vue index 0a8ec51c3..6f6f10a1e 100644 --- a/src/App.vue +++ b/src/App.vue @@ -44,7 +44,6 @@ const showContextMenu = (event: MouseEvent) => { onMounted(() => { // @ts-expect-error fixme ts strict error window['__COMFYUI_FRONTEND_VERSION__'] = config.app_version - console.log('ComfyUI Front-end version:', config.app_version) if (isElectron()) { document.addEventListener('contextmenu', showContextMenu) diff --git a/src/base/pointerUtils.ts b/src/base/pointerUtils.ts new file mode 100644 index 000000000..6bb218780 --- /dev/null +++ b/src/base/pointerUtils.ts @@ -0,0 +1,22 @@ +/** + * Utilities for pointer event handling + */ + +/** + * Checks if a pointer or mouse event is a middle button input + * @param event - The pointer or mouse event to check + * @returns true if the event is from the middle button/wheel + */ +export function isMiddlePointerInput( + event: PointerEvent | MouseEvent +): boolean { + if ('button' in event && event.button === 1) { + return true + } + + if ('buttons' in event && typeof event.buttons === 'number') { + return event.buttons === 4 + } + + return false +} diff --git a/src/components/bottomPanel/tabs/terminal/LogsTerminal.vue b/src/components/bottomPanel/tabs/terminal/LogsTerminal.vue index 68f643218..19b2fd6cc 100644 --- a/src/components/bottomPanel/tabs/terminal/LogsTerminal.vue +++ b/src/components/bottomPanel/tabs/terminal/LogsTerminal.vue @@ -69,7 +69,7 @@ const terminalCreated = ( await loadLogEntries() } catch (err) { console.error('Error loading logs', err) - // On older backends the endpoints wont exist + // On older backends the endpoints won't exist errorMessage.value = 'Unable to load logs, please ensure you have updated your ComfyUI backend.' return diff --git a/src/components/custom/widget/WorkflowTemplateSelectorDialog.vue b/src/components/custom/widget/WorkflowTemplateSelectorDialog.vue index 5e8397880..f5a86e1f5 100644 --- a/src/components/custom/widget/WorkflowTemplateSelectorDialog.vue +++ b/src/components/custom/widget/WorkflowTemplateSelectorDialog.vue @@ -128,7 +128,7 @@ @@ -148,7 +148,7 @@ @@ -157,10 +157,10 @@
@@ -172,7 +172,6 @@ v-for="template in isLoading ? [] : displayTemplates" :key="template.name" ref="cardRefs" - v-memo="[template.name, hoveredTemplate === template.name]" ratio="smallSquare" type="workflow-template-card" :data-testid="`template-workflow-${template.name}`" @@ -324,7 +323,7 @@ @@ -333,10 +332,10 @@
diff --git a/src/components/dialog/content/SignInContent.vue b/src/components/dialog/content/SignInContent.vue index a04531667..d6e199412 100644 --- a/src/components/dialog/content/SignInContent.vue +++ b/src/components/dialog/content/SignInContent.vue @@ -49,37 +49,39 @@ {{ t('auth.login.orContinueWith') }} - +
- + +
+ + + +
+
+ + + +
- - -
- - - -
diff --git a/src/renderer/extensions/vueNodes/components/SlotConnectionDot.vue b/src/renderer/extensions/vueNodes/components/SlotConnectionDot.vue index 85c7ec17d..3ee885413 100644 --- a/src/renderer/extensions/vueNodes/components/SlotConnectionDot.vue +++ b/src/renderer/extensions/vueNodes/components/SlotConnectionDot.vue @@ -28,11 +28,11 @@ defineExpose({ :style="{ backgroundColor: color }" :class=" cn( - 'bg-[#5B5E7D] rounded-full', + 'bg-slate-300 rounded-full', 'transition-all duration-150', 'cursor-crosshair', - 'border border-solid border-black/5 dark-theme:border-white/10', - 'group-hover/slot:border-black/20 dark-theme:group-hover/slot:border-white/50 group-hover/slot:scale-125', + 'border border-solid border-node-component-slot-dot-outline', + 'group-hover/slot:[--node-component-slot-dot-outline-opacity-mult:5] group-hover/slot:scale-125', multi ? 'w-3 h-6' : 'size-3' ) " diff --git a/src/renderer/extensions/vueNodes/composables/slotLinkDragSession.ts b/src/renderer/extensions/vueNodes/composables/slotLinkDragSession.ts new file mode 100644 index 000000000..6e12a03a5 --- /dev/null +++ b/src/renderer/extensions/vueNodes/composables/slotLinkDragSession.ts @@ -0,0 +1,45 @@ +import type { SlotLayout } from '@/renderer/core/layout/types' + +interface PendingMoveData { + clientX: number + clientY: number + target: EventTarget | null +} + +interface SlotLinkDragSession { + compatCache: Map + nodePreferred: Map< + number, + { index: number; key: string; layout: SlotLayout } | null + > + lastHoverSlotKey: string | null + lastHoverNodeId: number | null + lastCandidateKey: string | null + pendingMove: PendingMoveData | null + reset: () => void + dispose: () => void +} + +export function createSlotLinkDragSession(): SlotLinkDragSession { + const state: SlotLinkDragSession = { + compatCache: new Map(), + nodePreferred: new Map(), + lastHoverSlotKey: null, + lastHoverNodeId: null, + lastCandidateKey: null, + pendingMove: null, + reset: () => { + state.compatCache = new Map() + state.nodePreferred = new Map() + state.lastHoverSlotKey = null + state.lastHoverNodeId = null + state.lastCandidateKey = null + state.pendingMove = null + }, + dispose: () => { + state.reset() + } + } + + return state +} diff --git a/src/renderer/extensions/vueNodes/composables/useNodePointerInteractions.test.ts b/src/renderer/extensions/vueNodes/composables/useNodePointerInteractions.test.ts index f0c046ca0..7010d253c 100644 --- a/src/renderer/extensions/vueNodes/composables/useNodePointerInteractions.test.ts +++ b/src/renderer/extensions/vueNodes/composables/useNodePointerInteractions.test.ts @@ -4,10 +4,12 @@ import { nextTick, ref } from 'vue' import type { VueNodeData } from '@/composables/graph/useGraphNodeManager' import { useNodePointerInteractions } from '@/renderer/extensions/vueNodes/composables/useNodePointerInteractions' +const forwardEventToCanvasMock = vi.fn() + // Mock the dependencies vi.mock('@/renderer/core/canvas/useCanvasInteractions', () => ({ useCanvasInteractions: () => ({ - forwardEventToCanvas: vi.fn(), + forwardEventToCanvas: forwardEventToCanvasMock, shouldHandleNodePointerEvents: ref(true) }) })) @@ -69,6 +71,7 @@ const createMouseEvent = ( describe('useNodePointerInteractions', () => { beforeEach(() => { vi.clearAllMocks() + forwardEventToCanvasMock.mockClear() }) it('should only start drag on left-click', async () => { @@ -100,6 +103,34 @@ describe('useNodePointerInteractions', () => { ) }) + it('forwards middle mouse interactions to the canvas', () => { + const mockNodeData = createMockVueNodeData() + const mockOnPointerUp = vi.fn() + + const { pointerHandlers } = useNodePointerInteractions( + ref(mockNodeData), + mockOnPointerUp + ) + + const middlePointerDown = createPointerEvent('pointerdown', { button: 1 }) + pointerHandlers.onPointerdown(middlePointerDown) + expect(forwardEventToCanvasMock).toHaveBeenCalledWith(middlePointerDown) + + forwardEventToCanvasMock.mockClear() + + const middlePointerMove = createPointerEvent('pointermove', { buttons: 4 }) + pointerHandlers.onPointermove(middlePointerMove) + expect(forwardEventToCanvasMock).toHaveBeenCalledWith(middlePointerMove) + + forwardEventToCanvasMock.mockClear() + + const middlePointerUp = createPointerEvent('pointerup', { button: 1 }) + pointerHandlers.onPointerup(middlePointerUp) + expect(forwardEventToCanvasMock).toHaveBeenCalledWith(middlePointerUp) + + expect(mockOnPointerUp).not.toHaveBeenCalled() + }) + it('should distinguish drag from click based on distance threshold', async () => { const mockNodeData = createMockVueNodeData() const mockOnPointerUp = vi.fn() diff --git a/src/renderer/extensions/vueNodes/composables/useNodePointerInteractions.ts b/src/renderer/extensions/vueNodes/composables/useNodePointerInteractions.ts index e00e77c24..ccbf845cb 100644 --- a/src/renderer/extensions/vueNodes/composables/useNodePointerInteractions.ts +++ b/src/renderer/extensions/vueNodes/composables/useNodePointerInteractions.ts @@ -1,5 +1,6 @@ import { type MaybeRefOrGetter, computed, onUnmounted, ref, toValue } from 'vue' +import { isMiddlePointerInput } from '@/base/pointerUtils' import type { VueNodeData } from '@/composables/graph/useGraphNodeManager' import { useCanvasInteractions } from '@/renderer/core/canvas/useCanvasInteractions' import { layoutStore } from '@/renderer/core/layout/store/layoutStore' @@ -34,6 +35,12 @@ export function useNodePointerInteractions( const { forwardEventToCanvas, shouldHandleNodePointerEvents } = useCanvasInteractions() + const forwardMiddlePointerIfNeeded = (event: PointerEvent) => { + if (!isMiddlePointerInput(event)) return false + forwardEventToCanvas(event) + return true + } + // Drag state for styling const isDragging = ref(false) const dragStyle = computed(() => { @@ -52,6 +59,19 @@ export function useNodePointerInteractions( return } + if (forwardMiddlePointerIfNeeded(event)) return + + const stopNodeDragTarget = + event.target instanceof HTMLElement + ? event.target.closest('[data-capture-node="true"]') + : null + if (stopNodeDragTarget) { + if (!shouldHandleNodePointerEvents.value) { + forwardEventToCanvas(event) + } + return + } + // Only start drag on left-click (button 0) if (event.button !== 0) { return @@ -79,6 +99,8 @@ export function useNodePointerInteractions( } const handlePointerMove = (event: PointerEvent) => { + if (forwardMiddlePointerIfNeeded(event)) return + if (isDragging.value) { void handleDrag(event) } @@ -118,6 +140,8 @@ export function useNodePointerInteractions( } const handlePointerUp = (event: PointerEvent) => { + if (forwardMiddlePointerIfNeeded(event)) return + if (isDragging.value) { handleDragTermination(event, 'drag end') } diff --git a/src/renderer/extensions/vueNodes/composables/useNodeTooltips.ts b/src/renderer/extensions/vueNodes/composables/useNodeTooltips.ts index e69d21f56..05fc2fb5e 100644 --- a/src/renderer/extensions/vueNodes/composables/useNodeTooltips.ts +++ b/src/renderer/extensions/vueNodes/composables/useNodeTooltips.ts @@ -1,23 +1,92 @@ -import type { TooltipDirectivePassThroughOptions } from 'primevue' -import { type MaybeRef, type Ref, computed, unref } from 'vue' +import type { + TooltipDirectivePassThroughOptions, + TooltipPassThroughMethodOptions +} from 'primevue/tooltip' +import { type MaybeRef, computed, ref, unref } from 'vue' import type { SafeWidgetData } from '@/composables/graph/useGraphNodeManager' import { st } from '@/i18n' import { useSettingStore } from '@/platform/settings/settingStore' import { useNodeDefStore } from '@/stores/nodeDefStore' import { normalizeI18nKey } from '@/utils/formatUtil' +import { cn } from '@/utils/tailwindUtil' + +/** + * Hide all visible tooltips by dispatching mouseleave events + * + * + * IMPORTANT: this escape is needed for many reason due to primevue's directive tooltip system. + * We cannot use PT to conditionally render the tooltips because the entire PT object only run + * once during the initialization of the directive not every mount/unmount. + * Once the directive is constructed its no longer reactive in the traditional sense. + * We have to use something non destructive like mouseevents to dismiss the tooltip. + * + * TODO: use a better tooltip component like RekaUI for vue nodes specifically. + */ + +const tooltipsTemporarilyDisabled = ref(false) + +const hideTooltipsGlobally = () => { + // Get all visible tooltip elements + const tooltips = document.querySelectorAll('.p-tooltip') + + // Early return if no tooltips are visible + if (tooltips.length === 0) return + + tooltips.forEach((tooltipEl) => { + const tooltipId = tooltipEl.id + if (!tooltipId) return + + // Find the target element that owns this tooltip + const targetElements = document.querySelectorAll('[data-pd-tooltip="true"]') + for (const targetEl of targetElements) { + if ((targetEl as any).$_ptooltipId === tooltipId) { + ;(targetEl as HTMLElement).dispatchEvent( + new MouseEvent('mouseleave', { bubbles: true }) + ) + break + } + } + }) + + // Disable tooltips temporarily after hiding (for drag operations) + tooltipsTemporarilyDisabled.value = true +} + +/** + * Re-enable tooltips after pointer interaction ends + */ +const handlePointerUp = () => { + tooltipsTemporarilyDisabled.value = false +} + +// Global tooltip hiding system +const globalTooltipState = { listenersSetup: false } + +function setupGlobalTooltipHiding() { + if (globalTooltipState.listenersSetup) return + + document.addEventListener('pointerdown', hideTooltipsGlobally) + document.addEventListener('pointerup', handlePointerUp) + window.addEventListener('wheel', hideTooltipsGlobally, { + capture: true, //Need this to bypass the event layer from Litegraph + passive: true + }) + + globalTooltipState.listenersSetup = true +} /** * Composable for managing Vue node tooltips * Provides tooltip text for node headers, slots, and widgets */ -export function useNodeTooltips( - nodeType: MaybeRef, - containerRef?: Ref -) { +export function useNodeTooltips(nodeType: MaybeRef) { const nodeDefStore = useNodeDefStore() const settingsStore = useSettingStore() + // Setup global pointerdown listener once + setupGlobalTooltipHiding() + // Check if tooltips are globally enabled const tooltipsEnabled = computed(() => settingsStore.get('Comfy.EnableTooltips') @@ -76,38 +145,36 @@ export function useNodeTooltips( /** * Create tooltip configuration object for v-tooltip directive + * Components wrap this in computed() for reactivity */ const createTooltipConfig = (text: string) => { const tooltipDelay = settingsStore.get('LiteGraph.Node.TooltipDelay') const tooltipText = text || '' - const config: { - value: string - showDelay: number - disabled: boolean - appendTo?: HTMLElement - pt?: TooltipDirectivePassThroughOptions - } = { + return { value: tooltipText, showDelay: tooltipDelay as number, - disabled: !tooltipsEnabled.value || !tooltipText, + hideDelay: 0, // Immediate hiding + disabled: + !tooltipsEnabled.value || + !tooltipText || + tooltipsTemporarilyDisabled.value, // this reactive value works but only on next mount, + // so if the tooltip is already visible changing this will not hide it pt: { text: { class: - 'bg-pure-white dark-theme:bg-charcoal-800 border dark-theme:border-slate-300 rounded-md px-4 py-2 text-charcoal-700 dark-theme:text-pure-white text-sm font-normal leading-tight max-w-75 shadow-none' + 'border-node-component-tooltip-border bg-node-component-tooltip-surface border rounded-md px-4 py-2 text-node-component-tooltip text-sm font-normal leading-tight max-w-75 shadow-none' }, - arrow: { - class: 'before:border-slate-300' - } - } + arrow: ({ context }: TooltipPassThroughMethodOptions) => ({ + class: cn( + context.top && 'border-t-node-component-tooltip-border', + context.bottom && 'border-b-node-component-tooltip-border', + context.left && 'border-l-node-component-tooltip-border ', + context.right && 'border-r-node-component-tooltip-border' + ) + }) + } as TooltipDirectivePassThroughOptions } - - // If we have a container reference, append tooltips to it - if (containerRef?.value) { - config.appendTo = containerRef.value - } - - return config } return { diff --git a/src/renderer/extensions/vueNodes/composables/useSlotElementTracking.ts b/src/renderer/extensions/vueNodes/composables/useSlotElementTracking.ts index 4b6cbf811..3b859cee2 100644 --- a/src/renderer/extensions/vueNodes/composables/useSlotElementTracking.ts +++ b/src/renderer/extensions/vueNodes/composables/useSlotElementTracking.ts @@ -17,19 +17,17 @@ import { isSizeEqual } from '@/renderer/core/layout/utils/geometry' import { useNodeSlotRegistryStore } from '@/renderer/extensions/vueNodes/stores/nodeSlotRegistryStore' +import { createRafBatch } from '@/utils/rafBatch' // RAF batching const pendingNodes = new Set() -let rafId: number | null = null +const raf = createRafBatch(() => { + flushScheduledSlotLayoutSync() +}) function scheduleSlotLayoutSync(nodeId: string) { pendingNodes.add(nodeId) - if (rafId == null) { - rafId = requestAnimationFrame(() => { - rafId = null - flushScheduledSlotLayoutSync() - }) - } + raf.schedule() } function flushScheduledSlotLayoutSync() { diff --git a/src/renderer/extensions/vueNodes/composables/useSlotLinkInteraction.ts b/src/renderer/extensions/vueNodes/composables/useSlotLinkInteraction.ts index f82deab7d..12f94f5c4 100644 --- a/src/renderer/extensions/vueNodes/composables/useSlotLinkInteraction.ts +++ b/src/renderer/extensions/vueNodes/composables/useSlotLinkInteraction.ts @@ -2,22 +2,34 @@ import { type Fn, useEventListener } from '@vueuse/core' import { onBeforeUnmount } from 'vue' import { useSharedCanvasPositionConversion } from '@/composables/element/useCanvasPositionConversion' +import type { LGraph } from '@/lib/litegraph/src/LGraph' +import type { LGraphNode } from '@/lib/litegraph/src/LGraphNode' +import { LLink } from '@/lib/litegraph/src/LLink' +import type { Reroute } from '@/lib/litegraph/src/Reroute' +import type { RenderLink } from '@/lib/litegraph/src/canvas/RenderLink' +import type { + INodeInputSlot, + INodeOutputSlot +} from '@/lib/litegraph/src/interfaces' import { LinkDirection } from '@/lib/litegraph/src/types/globalEnums' -import { evaluateCompatibility } from '@/renderer/core/canvas/links/slotLinkCompatibility' +import { createLinkConnectorAdapter } from '@/renderer/core/canvas/links/linkConnectorAdapter' +import type { LinkConnectorAdapter } from '@/renderer/core/canvas/links/linkConnectorAdapter' import { type SlotDropCandidate, useSlotLinkDragState } from '@/renderer/core/canvas/links/slotLinkDragState' import { getSlotKey } from '@/renderer/core/layout/slots/slotIdentifier' import { layoutStore } from '@/renderer/core/layout/store/layoutStore' -import type { SlotLayout } from '@/renderer/core/layout/types' +import type { Point } from '@/renderer/core/layout/types' +import { toPoint } from '@/renderer/core/layout/utils/geometry' +import { createSlotLinkDragSession } from '@/renderer/extensions/vueNodes/composables/slotLinkDragSession' import { app } from '@/scripts/app' +import { createRafBatch } from '@/utils/rafBatch' interface SlotInteractionOptions { nodeId: string index: number type: 'input' | 'output' - readonly?: boolean } interface SlotInteractionHandlers { @@ -67,23 +79,23 @@ function createPointerSession(): PointerSession { export function useSlotLinkInteraction({ nodeId, index, - type, - readonly + type }: SlotInteractionOptions): SlotInteractionHandlers { - if (readonly) { - return { - onPointerDown: () => {} - } - } - - const { state, beginDrag, endDrag, updatePointerPosition } = + const { state, beginDrag, endDrag, updatePointerPosition, setCandidate } = useSlotLinkDragState() + const conversion = useSharedCanvasPositionConversion() + const pointerSession = createPointerSession() + let activeAdapter: LinkConnectorAdapter | null = null + + // Per-drag drag-state cache + const dragSession = createSlotLinkDragSession() function candidateFromTarget( target: EventTarget | null ): SlotDropCandidate | null { if (!(target instanceof HTMLElement)) return null - const key = target.dataset['slotKey'] + const elWithKey = target.closest('[data-slot-key]') + const key = elWithKey?.dataset['slotKey'] if (!key) return null const layout = layoutStore.getSlotLayout(key) @@ -91,23 +103,218 @@ export function useSlotLinkInteraction({ const candidate: SlotDropCandidate = { layout, compatible: false } - if (state.source) { - candidate.compatible = evaluateCompatibility( - state.source, - candidate - ).allowable + const graph = app.canvas?.graph + const adapter = ensureActiveAdapter() + if (graph && adapter) { + const cached = dragSession.compatCache.get(key) + if (cached != null) { + candidate.compatible = cached + } else { + const compatible = + layout.type === 'input' + ? adapter.isInputValidDrop(layout.nodeId, layout.index) + : adapter.isOutputValidDrop(layout.nodeId, layout.index) + dragSession.compatCache.set(key, compatible) + candidate.compatible = compatible + } } return candidate } - const conversion = useSharedCanvasPositionConversion() + function candidateFromNodeTarget( + target: EventTarget | null + ): SlotDropCandidate | null { + if (!(target instanceof HTMLElement)) return null + const elWithNode = target.closest('[data-node-id]') + const nodeIdStr = elWithNode?.dataset['nodeId'] + if (!nodeIdStr) return null - const pointerSession = createPointerSession() + const adapter = ensureActiveAdapter() + const graph = app.canvas?.graph + if (!adapter || !graph) return null + + const nodeId = Number(nodeIdStr) + + // Cached preferred slot for this node within this drag + const cachedPreferred = dragSession.nodePreferred.get(nodeId) + if (cachedPreferred !== undefined) { + return cachedPreferred + ? { layout: cachedPreferred.layout, compatible: true } + : null + } + + const node = graph.getNodeById(nodeId) + if (!node) return null + + const firstLink = adapter.renderLinks[0] + if (!firstLink) return null + const connectingTo = adapter.linkConnector.state.connectingTo + + if (connectingTo !== 'input' && connectingTo !== 'output') return null + + const isInput = connectingTo === 'input' + const slotType = firstLink.fromSlot.type + + const res = isInput + ? node.findInputByType(slotType) + : node.findOutputByType(slotType) + + const index = res?.index + if (index == null) return null + + const key = getSlotKey(String(nodeId), index, isInput) + const layout = layoutStore.getSlotLayout(key) + if (!layout) return null + + const compatible = isInput + ? adapter.isInputValidDrop(nodeId, index) + : adapter.isOutputValidDrop(nodeId, index) + + if (compatible) { + dragSession.compatCache.set(key, true) + const preferred = { index, key, layout } + dragSession.nodePreferred.set(nodeId, preferred) + return { layout, compatible: true } + } else { + dragSession.compatCache.set(key, false) + dragSession.nodePreferred.set(nodeId, null) + return null + } + } + + const ensureActiveAdapter = (): LinkConnectorAdapter | null => { + if (!activeAdapter) activeAdapter = createLinkConnectorAdapter() + return activeAdapter + } + + function hasCanConnectToReroute( + link: RenderLink + ): link is RenderLink & { canConnectToReroute: (r: Reroute) => boolean } { + return 'canConnectToReroute' in link + } + + type ToInputLink = RenderLink & { toType: 'input' } + type ToOutputLink = RenderLink & { toType: 'output' } + const isToInputLink = (link: RenderLink): link is ToInputLink => + link.toType === 'input' + const isToOutputLink = (link: RenderLink): link is ToOutputLink => + link.toType === 'output' + + function connectLinksToInput( + links: ReadonlyArray, + node: LGraphNode, + inputSlot: INodeInputSlot + ): boolean { + const validCandidates = links + .filter(isToInputLink) + .filter((link) => link.canConnectToInput(node, inputSlot)) + + for (const link of validCandidates) { + link.connectToInput(node, inputSlot, activeAdapter?.linkConnector.events) + } + + return validCandidates.length > 0 + } + + function connectLinksToOutput( + links: ReadonlyArray, + node: LGraphNode, + outputSlot: INodeOutputSlot + ): boolean { + const validCandidates = links + .filter(isToOutputLink) + .filter((link) => link.canConnectToOutput(node, outputSlot)) + + for (const link of validCandidates) { + link.connectToOutput( + node, + outputSlot, + activeAdapter?.linkConnector.events + ) + } + + return validCandidates.length > 0 + } + + const resolveLinkOrigin = ( + link: LLink | undefined + ): { position: Point; direction: LinkDirection } | null => { + if (!link) return null + + const slotKey = getSlotKey(String(link.origin_id), link.origin_slot, false) + const layout = layoutStore.getSlotLayout(slotKey) + if (!layout) return null + + return { position: { ...layout.position }, direction: LinkDirection.NONE } + } + + const resolveExistingInputLinkAnchor = ( + graph: LGraph, + inputSlot: INodeInputSlot | undefined + ): { position: Point; direction: LinkDirection } | null => { + if (!inputSlot) return null + + const directLink = graph.getLink(inputSlot.link) + if (directLink) { + const reroutes = LLink.getReroutes(graph, directLink) + const lastReroute = reroutes.at(-1) + if (lastReroute) { + const rerouteLayout = layoutStore.getRerouteLayout(lastReroute.id) + if (rerouteLayout) { + return { + position: { ...rerouteLayout.position }, + direction: LinkDirection.NONE + } + } + + const pos = lastReroute.pos + if (pos) { + return { + position: toPoint(pos[0], pos[1]), + direction: LinkDirection.NONE + } + } + } + + const directAnchor = resolveLinkOrigin(directLink) + if (directAnchor) return directAnchor + } + + const floatingLinkIterator = inputSlot._floatingLinks?.values() + const floatingLink = floatingLinkIterator + ? floatingLinkIterator.next().value + : undefined + if (!floatingLink) return null + + if (floatingLink.parentId != null) { + const rerouteLayout = layoutStore.getRerouteLayout(floatingLink.parentId) + if (rerouteLayout) { + return { + position: { ...rerouteLayout.position }, + direction: LinkDirection.NONE + } + } + + const reroute = graph.getReroute(floatingLink.parentId) + if (reroute) { + return { + position: toPoint(reroute.pos[0], reroute.pos[1]), + direction: LinkDirection.NONE + } + } + } + + return null + } const cleanupInteraction = () => { + activeAdapter?.reset() pointerSession.clear() endDrag() + activeAdapter = null + raf.cancel() + dragSession.dispose() } const updatePointerState = (event: PointerEvent) => { @@ -121,50 +328,195 @@ export function useSlotLinkInteraction({ updatePointerPosition(clientX, clientY, canvasX, canvasY) } - const handlePointerMove = (event: PointerEvent) => { - if (!pointerSession.matches(event)) return - updatePointerState(event) + const processPointerMoveFrame = () => { + const data = dragSession.pendingMove + if (!data) return + dragSession.pendingMove = null + + const [canvasX, canvasY] = conversion.clientPosToCanvasPos([ + data.clientX, + data.clientY + ]) + updatePointerPosition(data.clientX, data.clientY, canvasX, canvasY) + + let hoveredSlotKey: string | null = null + let hoveredNodeId: number | null = null + const target = data.target + if (target instanceof HTMLElement) { + hoveredSlotKey = + target.closest('[data-slot-key]')?.dataset['slotKey'] ?? + null + if (!hoveredSlotKey) { + const nodeIdStr = + target.closest('[data-node-id]')?.dataset['nodeId'] + hoveredNodeId = nodeIdStr != null ? Number(nodeIdStr) : null + } + } + + const hoverChanged = + hoveredSlotKey !== dragSession.lastHoverSlotKey || + hoveredNodeId !== dragSession.lastHoverNodeId + + let candidate: SlotDropCandidate | null = state.candidate + + if (hoverChanged) { + const slotCandidate = candidateFromTarget(target) + const nodeCandidate = slotCandidate + ? null + : candidateFromNodeTarget(target) + candidate = slotCandidate ?? nodeCandidate + dragSession.lastHoverSlotKey = hoveredSlotKey + dragSession.lastHoverNodeId = hoveredNodeId + } + + const newCandidate = candidate?.compatible ? candidate : null + const newCandidateKey = newCandidate + ? getSlotKey( + newCandidate.layout.nodeId, + newCandidate.layout.index, + newCandidate.layout.type === 'input' + ) + : null + + if (newCandidateKey !== dragSession.lastCandidateKey) { + setCandidate(newCandidate) + dragSession.lastCandidateKey = newCandidateKey + } + app.canvas?.setDirty(true) } + const raf = createRafBatch(processPointerMoveFrame) - const connectSlots = (slotLayout: SlotLayout) => { - const canvas = app.canvas - const graph = canvas?.graph - const source = state.source - if (!canvas || !graph || !source) return + const handlePointerMove = (event: PointerEvent) => { + if (!pointerSession.matches(event)) return + dragSession.pendingMove = { + clientX: event.clientX, + clientY: event.clientY, + target: event.target + } + raf.schedule() + } - const sourceNode = graph.getNodeById(Number(source.nodeId)) - const targetNode = graph.getNodeById(Number(slotLayout.nodeId)) - if (!sourceNode || !targetNode) return + // Attempt to finalize by connecting to a DOM slot candidate + const tryConnectToCandidate = ( + candidate: SlotDropCandidate | null + ): boolean => { + if (!candidate?.compatible) return false + const graph = app.canvas?.graph + const adapter = ensureActiveAdapter() + if (!graph || !adapter) return false - if (source.type === 'output' && slotLayout.type === 'input') { - const outputSlot = sourceNode.outputs?.[source.slotIndex] - const inputSlot = targetNode.inputs?.[slotLayout.index] - if (!outputSlot || !inputSlot) return - graph.beforeChange() - sourceNode.connectSlots(outputSlot, targetNode, inputSlot, undefined) - return + const nodeId = Number(candidate.layout.nodeId) + const targetNode = graph.getNodeById(nodeId) + if (!targetNode) return false + + if (candidate.layout.type === 'input') { + const inputSlot = targetNode.inputs?.[candidate.layout.index] + return ( + !!inputSlot && + connectLinksToInput(adapter.renderLinks, targetNode, inputSlot) + ) } - if (source.type === 'input' && slotLayout.type === 'output') { - const inputSlot = sourceNode.inputs?.[source.slotIndex] - const outputSlot = targetNode.outputs?.[slotLayout.index] - if (!inputSlot || !outputSlot) return - graph.beforeChange() - sourceNode.disconnectInput(source.slotIndex, true) - targetNode.connectSlots(outputSlot, sourceNode, inputSlot, undefined) + if (candidate.layout.type === 'output') { + const outputSlot = targetNode.outputs?.[candidate.layout.index] + return ( + !!outputSlot && + connectLinksToOutput(adapter.renderLinks, targetNode, outputSlot) + ) } + + return false + } + + // Attempt to finalize by dropping on a reroute under the pointer + const tryConnectViaRerouteAtPointer = (): boolean => { + const rerouteLayout = layoutStore.queryRerouteAtPoint({ + x: state.pointer.canvas.x, + y: state.pointer.canvas.y + }) + const graph = app.canvas?.graph + const adapter = ensureActiveAdapter() + if (!rerouteLayout || !graph || !adapter) return false + + const reroute = graph.getReroute(rerouteLayout.id) + if (!reroute || !adapter.isRerouteValidDrop(reroute.id)) return false + + let didConnect = false + + const results = reroute.findTargetInputs() ?? [] + const maybeReroutes = reroute.getReroutes() + if (results.length && maybeReroutes !== null) { + const originalReroutes = maybeReroutes.slice(0, -1).reverse() + for (const link of adapter.renderLinks) { + if (!isToInputLink(link)) continue + for (const result of results) { + link.connectToRerouteInput( + reroute, + result, + adapter.linkConnector.events, + originalReroutes + ) + didConnect = true + } + } + } + + const sourceOutput = reroute.findSourceOutput() + if (sourceOutput) { + const { node, output } = sourceOutput + for (const link of adapter.renderLinks) { + if (!isToOutputLink(link)) continue + if (hasCanConnectToReroute(link) && !link.canConnectToReroute(reroute)) + continue + link.connectToRerouteOutput( + reroute, + node, + output, + adapter.linkConnector.events + ) + didConnect = true + } + } + + return didConnect } const finishInteraction = (event: PointerEvent) => { if (!pointerSession.matches(event)) return event.preventDefault() - if (state.source) { - const candidate = candidateFromTarget(event.target) - if (candidate?.compatible) { - connectSlots(candidate.layout) - } + raf.flush() + + if (!state.source) { + cleanupInteraction() + app.canvas?.setDirty(true) + return + } + + // Prefer using the snapped candidate captured during hover for perf + consistency + const snappedCandidate = state.candidate?.compatible + ? state.candidate + : null + + let connected = tryConnectToCandidate(snappedCandidate) + + // Fallback to DOM slot under pointer (if any), then node fallback, then reroute + if (!connected) { + const domCandidate = candidateFromTarget(event.target) + connected = tryConnectToCandidate(domCandidate) + } + + if (!connected) { + const nodeCandidate = candidateFromNodeTarget(event.target) + connected = tryConnectToCandidate(nodeCandidate) + } + + if (!connected) connected = tryConnectViaRerouteAtPointer() || connected + + // Drop on canvas: disconnect moving input link(s) + if (!connected && !snappedCandidate && state.source.type === 'input') { + ensureActiveAdapter()?.disconnectMovingLinks() } cleanupInteraction() @@ -177,6 +529,8 @@ export function useSlotLinkInteraction({ const handlePointerCancel = (event: PointerEvent) => { if (!pointerSession.matches(event)) return + + raf.flush() cleanupInteraction() app.canvas?.setDirty(true) } @@ -190,19 +544,82 @@ export function useSlotLinkInteraction({ const graph = canvas?.graph if (!canvas || !graph) return + ensureActiveAdapter() + raf.cancel() + dragSession.reset() + const layout = layoutStore.getSlotLayout( getSlotKey(nodeId, index, type === 'input') ) if (!layout) return - const resolvedNode = graph.getNodeById(Number(nodeId)) - const slot = - type === 'input' - ? resolvedNode?.inputs?.[index] - : resolvedNode?.outputs?.[index] + const numericNodeId = Number(nodeId) + const isInputSlot = type === 'input' + const isOutputSlot = type === 'output' - const direction = - slot?.dir ?? (type === 'input' ? LinkDirection.LEFT : LinkDirection.RIGHT) + const resolvedNode = graph.getNodeById(numericNodeId) + const inputSlot = isInputSlot ? resolvedNode?.inputs?.[index] : undefined + const outputSlot = isOutputSlot ? resolvedNode?.outputs?.[index] : undefined + + const ctrlOrMeta = event.ctrlKey || event.metaKey + + const inputLinkId = inputSlot?.link ?? null + const inputFloatingCount = inputSlot?._floatingLinks?.size ?? 0 + const hasExistingInputLink = inputLinkId != null || inputFloatingCount > 0 + + const outputLinkCount = outputSlot?.links?.length ?? 0 + const outputFloatingCount = outputSlot?._floatingLinks?.size ?? 0 + const hasExistingOutputLink = outputLinkCount > 0 || outputFloatingCount > 0 + + const shouldBreakExistingInputLink = + isInputSlot && + hasExistingInputLink && + ctrlOrMeta && + event.altKey && + !event.shiftKey + + const existingInputLink = + isInputSlot && inputLinkId != null + ? graph.getLink(inputLinkId) + : undefined + + if (shouldBreakExistingInputLink && resolvedNode) { + resolvedNode.disconnectInput(index, true) + } + + const baseDirection = isInputSlot + ? inputSlot?.dir ?? LinkDirection.LEFT + : outputSlot?.dir ?? LinkDirection.RIGHT + + const existingAnchor = + isInputSlot && !shouldBreakExistingInputLink + ? resolveExistingInputLinkAnchor(graph, inputSlot) + : null + + const shouldMoveExistingOutput = + isOutputSlot && event.shiftKey && hasExistingOutputLink + + const shouldMoveExistingInput = + isInputSlot && !shouldBreakExistingInputLink && hasExistingInputLink + + const adapter = ensureActiveAdapter() + if (adapter) { + if (isOutputSlot) { + adapter.beginFromOutput(numericNodeId, index, { + moveExisting: shouldMoveExistingOutput + }) + } else { + adapter.beginFromInput(numericNodeId, index, { + moveExisting: shouldMoveExistingInput + }) + } + } + + const direction = existingAnchor?.direction ?? baseDirection + const startPosition = existingAnchor?.position ?? { + x: layout.position.x, + y: layout.position.y + } beginDrag( { @@ -210,7 +627,11 @@ export function useSlotLinkInteraction({ slotIndex: index, type, direction, - position: layout.position + position: startPosition, + linkId: !shouldBreakExistingInputLink + ? existingInputLink?.id + : undefined, + movingExistingOutput: shouldMoveExistingOutput }, event.pointerId ) diff --git a/src/renderer/extensions/vueNodes/execution/useNodeExecutionState.ts b/src/renderer/extensions/vueNodes/execution/useNodeExecutionState.ts index aa4867db9..8debe0666 100644 --- a/src/renderer/extensions/vueNodes/execution/useNodeExecutionState.ts +++ b/src/renderer/extensions/vueNodes/execution/useNodeExecutionState.ts @@ -9,27 +9,27 @@ import { useExecutionStore } from '@/stores/executionStore' * Provides reactive access to execution state and progress for a specific node * by injecting execution data from the parent GraphCanvas provider. * - * @param nodeIdMaybe - The ID of the node to track execution state for + * @param nodeLocatorIdMaybe - Locator ID (root or subgraph scoped) of the node to track * @returns Object containing reactive execution state and progress */ export const useNodeExecutionState = ( - nodeIdMaybe: MaybeRefOrGetter + nodeLocatorIdMaybe: MaybeRefOrGetter ) => { - const nodeId = toValue(nodeIdMaybe) - const { uniqueExecutingNodeIdStrings, nodeProgressStates } = - storeToRefs(useExecutionStore()) + const locatorId = computed(() => toValue(nodeLocatorIdMaybe) ?? '') + const { nodeLocationProgressStates } = storeToRefs(useExecutionStore()) - const executing = computed(() => { - return uniqueExecutingNodeIdStrings.value.has(nodeId) + const progressState = computed(() => { + const id = locatorId.value + return id ? nodeLocationProgressStates.value[id] : undefined }) + const executing = computed(() => progressState.value?.state === 'running') + const progress = computed(() => { - const state = nodeProgressStates.value[nodeId] - return state?.max > 0 ? state.value / state.max : undefined + const state = progressState.value + return state && state.max > 0 ? state.value / state.max : undefined }) - const progressState = computed(() => nodeProgressStates.value[nodeId]) - const progressPercentage = computed(() => { const prog = progress.value return prog !== undefined ? Math.round(prog * 100) : undefined diff --git a/src/renderer/extensions/vueNodes/widgets/components/WidgetButton.test.ts b/src/renderer/extensions/vueNodes/widgets/components/WidgetButton.test.ts index 72d6726a5..2ca7a4340 100644 --- a/src/renderer/extensions/vueNodes/widgets/components/WidgetButton.test.ts +++ b/src/renderer/extensions/vueNodes/widgets/components/WidgetButton.test.ts @@ -50,16 +50,6 @@ describe('WidgetButton Interactions', () => { expect(mockCallback).toHaveBeenCalledTimes(1) }) - it('does not call callback when button is readonly', async () => { - const mockCallback = vi.fn() - const widget = createMockWidget({}, mockCallback) - const wrapper = mountComponent(widget, true) - - await clickButton(wrapper) - - expect(mockCallback).not.toHaveBeenCalled() - }) - it('handles missing callback gracefully', async () => { const widget = createMockWidget({}, undefined) const wrapper = mountComponent(widget) @@ -75,7 +65,6 @@ describe('WidgetButton Interactions', () => { const numClicks = 8 - await clickButton(wrapper) for (let i = 0; i < numClicks; i++) { await clickButton(wrapper) } @@ -134,26 +123,6 @@ describe('WidgetButton Interactions', () => { }) }) - describe('Readonly Mode', () => { - it('disables button when readonly', () => { - const widget = createMockWidget() - const wrapper = mountComponent(widget, true) - - // Test the actual DOM button element instead of the Vue component props - const buttonElement = wrapper.find('button') - expect(buttonElement.element.disabled).toBe(true) - }) - - it('enables button when not readonly', () => { - const widget = createMockWidget() - const wrapper = mountComponent(widget, false) - - // Test the actual DOM button element instead of the Vue component props - const buttonElement = wrapper.find('button') - expect(buttonElement.element.disabled).toBe(false) - }) - }) - describe('Widget Options', () => { it('handles button with text only', () => { const widget = createMockWidget({ label: 'Click Me' }) diff --git a/src/renderer/extensions/vueNodes/widgets/components/WidgetButton.vue b/src/renderer/extensions/vueNodes/widgets/components/WidgetButton.vue index ae8fb7567..7a0ce4ff5 100644 --- a/src/renderer/extensions/vueNodes/widgets/components/WidgetButton.vue +++ b/src/renderer/extensions/vueNodes/widgets/components/WidgetButton.vue @@ -3,12 +3,7 @@ -