From 97613870d3560390c66ff488a20cc233a3960afb Mon Sep 17 00:00:00 2001 From: Youssef Adel Date: Mon, 2 Feb 2026 00:57:12 +0200 Subject: [PATCH 01/16] feat: Enhance OpenAI integration with new Responses API and improved token management - Added support for OpenAI Responses API, allowing for structured input and output handling. - Implemented token persistence using file storage for GitHub and Copilot tokens. - Updated authentication flow to handle token refresh and verification more robustly. - Enhanced model mapping for Copilot API to support new models and formats. - Improved error handling and logging throughout the API interactions. - Increased request body size limits for JSON and URL-encoded data. - Refactored middleware and service functions for better maintainability and clarity. --- .commitlintrc.json | 7 - .github/workflows/ci.yml | 56 - .gitignore | 3 + .husky/commit-msg | 4 - .husky/pre-commit | 4 - package-lock.json | 7260 +++++++++++++++++++++++++++++++ package.json | 14 +- src/config/index.ts | 3 +- src/middleware/rate-limiter.ts | 2 +- src/routes/openai.ts | 707 ++- src/server.ts | 3 +- src/services/auth-service.ts | 160 +- src/services/copilot-service.ts | 192 +- src/types/openai.ts | 54 + 14 files changed, 8254 insertions(+), 215 deletions(-) delete mode 100644 .commitlintrc.json delete mode 100644 .github/workflows/ci.yml delete mode 100755 .husky/commit-msg delete mode 100755 .husky/pre-commit create mode 100644 package-lock.json diff --git a/.commitlintrc.json b/.commitlintrc.json deleted file mode 100644 index 13dd0ab..0000000 --- a/.commitlintrc.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "extends": ["@commitlint/config-conventional"], - "rules": { - "subject-case": [0], - "header-max-length": [2, "always", 100] - } -} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index 581b0b3..0000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,56 +0,0 @@ -name: CI - -on: - push: - branches: [ main, dev ] - pull_request: - branches: [ main, dev ] - -jobs: - build: - runs-on: ubuntu-latest - - strategy: - matrix: - node-version: [18.x, 20.x] - - steps: - - uses: actions/checkout@v3 - - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 - with: - node-version: ${{ matrix.node-version }} - cache: 'npm' - - - name: Install dependencies - run: npm ci - - - name: Lint - run: npm run lint - - - name: Build - run: npm run build - - - name: Test - run: npm test - - docker: - runs-on: ubuntu-latest - needs: build - if: github.event_name != 'pull_request' - - steps: - - uses: actions/checkout@v3 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 - - - name: Build Docker image - uses: docker/build-push-action@v4 - with: - context: . - push: false - tags: github-copilot-proxy:latest - cache-from: type=gha - cache-to: type=gha,mode=max diff --git a/.gitignore b/.gitignore index 59f90e6..8831576 100644 --- a/.gitignore +++ b/.gitignore @@ -27,6 +27,9 @@ jspm_packages/ .env.production.local .env.local +# Token storage (sensitive!) +.tokens.json + # Build output dist/ build/ diff --git a/.husky/commit-msg b/.husky/commit-msg deleted file mode 100755 index e810522..0000000 --- a/.husky/commit-msg +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env sh -. "$(dirname -- "$0")/_/husky.sh" - -npx --no -- commitlint --edit $1 diff --git a/.husky/pre-commit b/.husky/pre-commit deleted file mode 100755 index 75fac8e..0000000 --- a/.husky/pre-commit +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env sh -. "$(dirname -- "$0")/_/husky.sh" - -npm run lint diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..1a3b0f0 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,7260 @@ +{ + "name": "github-copilot-proxy", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "github-copilot-proxy", + "version": "0.1.0", + "license": "MIT", + "dependencies": { + "@microsoft/fetch-event-source": "^2.0.1", + "@octokit/auth-oauth-device": "^6.0.1", + "cors": "^2.8.5", + "dotenv": "^16.4.1", + "eventsource-parser": "^3.0.6", + "express": "^4.18.2", + "node-fetch": "^3.3.2", + "uuid": "^9.0.1", + "winston": "^3.11.0", + "zod": "^3.22.4" + }, + "devDependencies": { + "@types/cors": "^2.8.17", + "@types/express": "^4.17.21", + "@types/jest": "^29.5.11", + "@types/node": "^20.11.6", + "@types/supertest": "^6.0.2", + "@types/uuid": "^9.0.8", + "@typescript-eslint/eslint-plugin": "^6.19.1", + "@typescript-eslint/parser": "^6.19.1", + "concurrently": "^8.2.2", + "cross-env": "^7.0.3", + "eslint": "^8.56.0", + "jest": "^29.7.0", + "supertest": "^6.3.4", + "ts-jest": "^29.1.2", + "ts-node": "^10.9.2", + "typescript": "^5.3.3" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.28.5", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", + "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", + "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.0.tgz", + "integrity": "sha512-vSH118/wwM/pLR38g/Sgk05sNtro6TlTJKuiMXDaZqPUfjTFcudpCOt00IhOfj+1BFAX+UFAlzCU+6WXr3GLFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", + "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.28.6", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", + "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz", + "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", + "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.28.6.tgz", + "integrity": "sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.28.6.tgz", + "integrity": "sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.28.6.tgz", + "integrity": "sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.6.tgz", + "integrity": "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@colors/colors": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", + "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==", + "license": "MIT", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@dabh/diagnostics": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.8.tgz", + "integrity": "sha512-R4MSXTVnuMzGD7bzHdW2ZhhdPC/igELENcq5IjEverBvq5hn1SXCWcsi6eSsdWP0/Ur+SItRRjAktmdoX/8R/Q==", + "license": "MIT", + "dependencies": { + "@so-ric/colorspace": "^1.1.6", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/js": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", + "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", + "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", + "deprecated": "Use @eslint/config-array instead", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.3", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "deprecated": "Use @eslint/object-schema instead", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", + "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", + "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/reporters": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^29.7.0", + "jest-config": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-resolve-dependencies": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "jest-watcher": "^29.7.0", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/environment": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", + "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "expect": "^29.7.0", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", + "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-get-type": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", + "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", + "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/types": "^29.6.3", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", + "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^6.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", + "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.18", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", + "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", + "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@microsoft/fetch-event-source": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@microsoft/fetch-event-source/-/fetch-event-source-2.0.1.tgz", + "integrity": "sha512-W6CLUJ2eBMw3Rec70qrsEW0jOm/3twwJv21mrmj2yORiaVmVYGS4sSS5yUwvQc1ZlDLYGPnClVWmUUMagKNsfA==", + "license": "MIT" + }, + "node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@octokit/auth-oauth-device": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@octokit/auth-oauth-device/-/auth-oauth-device-6.1.0.tgz", + "integrity": "sha512-FNQ7cb8kASufd6Ej4gnJ3f1QB5vJitkoV1O0/g6e6lUsQ7+VsSNRHRmFScN2tV4IgKA12frrr/cegUs0t+0/Lw==", + "license": "MIT", + "dependencies": { + "@octokit/oauth-methods": "^4.1.0", + "@octokit/request": "^8.3.1", + "@octokit/types": "^13.0.0", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/endpoint": { + "version": "9.0.6", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-9.0.6.tgz", + "integrity": "sha512-H1fNTMA57HbkFESSt3Y9+FBICv+0jFceJFPWDePYlR/iMGrwM5ph+Dd4XRQs+8X+PUFURLQgX9ChPfhJ/1uNQw==", + "license": "MIT", + "dependencies": { + "@octokit/types": "^13.1.0", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/oauth-authorization-url": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@octokit/oauth-authorization-url/-/oauth-authorization-url-6.0.2.tgz", + "integrity": "sha512-CdoJukjXXxqLNK4y/VOiVzQVjibqoj/xHgInekviUJV73y/BSIcwvJ/4aNHPBPKcPWFnd4/lO9uqRV65jXhcLA==", + "license": "MIT", + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/oauth-methods": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@octokit/oauth-methods/-/oauth-methods-4.1.0.tgz", + "integrity": "sha512-4tuKnCRecJ6CG6gr0XcEXdZtkTDbfbnD5oaHBmLERTjTMZNi2CbfEHZxPU41xXLDG4DfKf+sonu00zvKI9NSbw==", + "license": "MIT", + "dependencies": { + "@octokit/oauth-authorization-url": "^6.0.2", + "@octokit/request": "^8.3.1", + "@octokit/request-error": "^5.1.0", + "@octokit/types": "^13.0.0", + "btoa-lite": "^1.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/openapi-types": { + "version": "24.2.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz", + "integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==", + "license": "MIT" + }, + "node_modules/@octokit/request": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-8.4.1.tgz", + "integrity": "sha512-qnB2+SY3hkCmBxZsR/MPCybNmbJe4KAlfWErXq+rBKkQJlbjdJeS85VI9r8UqeLYLvnAenU8Q1okM/0MBsAGXw==", + "license": "MIT", + "dependencies": { + "@octokit/endpoint": "^9.0.6", + "@octokit/request-error": "^5.1.1", + "@octokit/types": "^13.1.0", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/request-error": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-5.1.1.tgz", + "integrity": "sha512-v9iyEQJH6ZntoENr9/yXxjuezh4My67CBSu9r6Ve/05Iu5gNgnisNWOsoJHTP6k0Rr0+HQIpnH+kyammu90q/g==", + "license": "MIT", + "dependencies": { + "@octokit/types": "^13.1.0", + "deprecation": "^2.0.0", + "once": "^1.4.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/types": { + "version": "13.10.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz", + "integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==", + "license": "MIT", + "dependencies": { + "@octokit/openapi-types": "^24.2.0" + } + }, + "node_modules/@paralleldrive/cuid2": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@paralleldrive/cuid2/-/cuid2-2.3.1.tgz", + "integrity": "sha512-XO7cAxhnTZl0Yggq6jOgjiOHhbgcO4NqFqwSmQpjK3b6TEE6Uj/jfSk6wzYyemh3+I0sHirKSetjQwn5cZktFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "^1.1.5" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, + "node_modules/@so-ric/colorspace": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@so-ric/colorspace/-/colorspace-1.1.6.tgz", + "integrity": "sha512-/KiKkpHNOBgkFJwu9sh48LkHSMYGyuTcSFK/qMBdnOAlrRJzRSXAOFB5qwzaVQuDl8wAvHVMkaASQDReTahxuw==", + "license": "MIT", + "dependencies": { + "color": "^5.0.2", + "text-hex": "1.0.x" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz", + "integrity": "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.6", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", + "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/cookiejar": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@types/cookiejar/-/cookiejar-2.1.5.tgz", + "integrity": "sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/cors": { + "version": "2.8.19", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz", + "integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/express": { + "version": "4.17.25", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.25.tgz", + "integrity": "sha512-dVd04UKsfpINUnK0yBoYHDF3xu7xVH4BuDotC/xGuycx4CgbP48X/KF/586bcObxT0HENHXEU8Nqtu6NR+eKhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "^1" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.19.8", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.8.tgz", + "integrity": "sha512-02S5fmqeoKzVZCHPZid4b8JH2eM5HzQLZWN2FohQEy/0eXTq8VXZfSN6Pcr3F6N9R/vNrj7cpgbhjie6m/1tCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", + "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/http-errors": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", + "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jest": { + "version": "29.5.14", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.14.tgz", + "integrity": "sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "expect": "^29.0.0", + "pretty-format": "^29.0.0" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/methods": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@types/methods/-/methods-1.1.4.tgz", + "integrity": "sha512-ymXWVrDiCxTBE3+RIrrP533E70eA+9qu7zdWoHuOmGujkYtzf4HQF96b8nwHLqhuf4ykX61IGRIB38CC6/sImQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "20.19.30", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.30.tgz", + "integrity": "sha512-WJtwWJu7UdlvzEAUm484QNg5eAoq5QR08KDNx7g45Usrs2NtOPiX8ugDqmKdXkyL03rBqU5dYNYVQetEpBHq2g==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/qs": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/send": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz", + "integrity": "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.10", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.10.tgz", + "integrity": "sha512-tRs1dB+g8Itk72rlSI2ZrW6vZg0YrLI81iQSTkMmOqnqCaNr/8Ek4VwWcN5vZgCYWbg/JJSGBlUaYGAOP73qBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "<1" + } + }, + "node_modules/@types/serve-static/node_modules/@types/send": { + "version": "0.17.6", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.6.tgz", + "integrity": "sha512-Uqt8rPBE8SY0RK8JB1EzVOIZ32uqy8HwdxCnoCOsYrvnswqmFZ/k+9Ikidlk/ImhsdvBsloHbAlewb2IEBV/Og==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/superagent": { + "version": "8.1.9", + "resolved": "https://registry.npmjs.org/@types/superagent/-/superagent-8.1.9.tgz", + "integrity": "sha512-pTVjI73witn+9ILmoJdajHGW2jkSaOzhiFYF1Rd3EQ94kymLqB9PjD9ISg7WaALC7+dCHT0FGe9T2LktLq/3GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/cookiejar": "^2.1.5", + "@types/methods": "^1.1.4", + "@types/node": "*", + "form-data": "^4.0.0" + } + }, + "node_modules/@types/supertest": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@types/supertest/-/supertest-6.0.3.tgz", + "integrity": "sha512-8WzXq62EXFhJ7QsH3Ocb/iKQ/Ty9ZVWnVzoTKc9tyyFRRF3a74Tk2+TLFgaFFw364Ere+npzHKEJ6ga2LzIL7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/methods": "^1.1.4", + "@types/superagent": "^8.1.0" + } + }, + "node_modules/@types/triple-beam": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", + "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==", + "license": "MIT" + }, + "node_modules/@types/uuid": { + "version": "9.0.8", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.8.tgz", + "integrity": "sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/yargs": { + "version": "17.0.35", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz", + "integrity": "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz", + "integrity": "sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/type-utils": "6.21.0", + "@typescript-eslint/utils": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz", + "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", + "dev": true, + "license": "BSD-2-Clause", + "peer": true, + "dependencies": { + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz", + "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz", + "integrity": "sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/utils": "6.21.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz", + "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz", + "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "9.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz", + "integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "semver": "^7.5.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz", + "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "dev": true, + "license": "ISC" + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "license": "MIT", + "peer": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true, + "license": "MIT" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "license": "MIT" + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "dev": true, + "license": "MIT" + }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "license": "MIT" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/babel-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", + "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/transform": "^29.7.0", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.6.3", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-istanbul/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", + "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz", + "integrity": "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-import-attributes": "^7.24.7", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5" + }, + "peerDependencies": { + "@babel/core": "^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/babel-preset-jest": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", + "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", + "dev": true, + "license": "MIT", + "dependencies": { + "babel-plugin-jest-hoist": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.9.19", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.19.tgz", + "integrity": "sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + }, + "node_modules/body-parser": { + "version": "1.20.4", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.4.tgz", + "integrity": "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "~1.2.0", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "on-finished": "~2.4.1", + "qs": "~6.14.0", + "raw-body": "~2.5.3", + "type-is": "~1.6.18", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-json-stable-stringify": "2.x" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/btoa-lite": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/btoa-lite/-/btoa-lite-1.0.0.tgz", + "integrity": "sha512-gvW7InbIyF8AicrqWoptdW08pUxuhq8BEgowNajy9RhiE86fmGAGl+bLKo6oB8QP0CkqHLowfN0oJdKC/J6LbA==", + "license": "MIT" + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001766", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001766.tgz", + "integrity": "sha512-4C0lfJ0/YPjJQHagaE9x2Elb69CIqEPZeG0anQt9SIvIoOH4a4uaRl73IavyO+0qZh6MDLH//DrXThEYKHkmYA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cjs-module-lexer": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz", + "integrity": "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.3.tgz", + "integrity": "sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==", + "dev": true, + "license": "MIT" + }, + "node_modules/color": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/color/-/color-5.0.3.tgz", + "integrity": "sha512-ezmVcLR3xAVp8kYOm4GS45ZLLgIE6SPAFoduLr6hTDajwb3KZ2F46gulK3XpcwRFb5KKGCSezCBAY4Dw4HsyXA==", + "license": "MIT", + "dependencies": { + "color-convert": "^3.1.3", + "color-string": "^2.1.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/color-string": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-2.1.4.tgz", + "integrity": "sha512-Bb6Cq8oq0IjDOe8wJmi4JeNn763Xs9cfrBcaylK1tPypWzyoy2G3l90v9k64kjphl/ZJjPIShFztenRomi8WTg==", + "license": "MIT", + "dependencies": { + "color-name": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/color-string/node_modules/color-name": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-2.1.0.tgz", + "integrity": "sha512-1bPaDNFm0axzE4MEAzKPuqKWeRaT43U/hyxKPBdqTfmPF+d6n7FSoTFxLVULUJOmiLp01KjhIPPH+HrXZJN4Rg==", + "license": "MIT", + "engines": { + "node": ">=12.20" + } + }, + "node_modules/color/node_modules/color-convert": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-3.1.3.tgz", + "integrity": "sha512-fasDH2ont2GqF5HpyO4w0+BcewlhHEZOFn9c1ckZdHpJ56Qb7MHhH/IcJZbBGgvdtwdwNbLvxiBEdg336iA9Sg==", + "license": "MIT", + "dependencies": { + "color-name": "^2.0.0" + }, + "engines": { + "node": ">=14.6" + } + }, + "node_modules/color/node_modules/color-name": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-2.1.0.tgz", + "integrity": "sha512-1bPaDNFm0axzE4MEAzKPuqKWeRaT43U/hyxKPBdqTfmPF+d6n7FSoTFxLVULUJOmiLp01KjhIPPH+HrXZJN4Rg==", + "license": "MIT", + "engines": { + "node": ">=12.20" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/component-emitter": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", + "integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/concurrently": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-8.2.2.tgz", + "integrity": "sha512-1dP4gpXFhei8IOtlXRE/T/4H88ElHgTiUzh71YUmtjTEHMSRS2Z/fgOxHSxxusGHogsRfxNq1vyAwxSC+EVyDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.2", + "date-fns": "^2.30.0", + "lodash": "^4.17.21", + "rxjs": "^7.8.1", + "shell-quote": "^1.8.1", + "spawn-command": "0.0.2", + "supports-color": "^8.1.1", + "tree-kill": "^1.2.2", + "yargs": "^17.7.2" + }, + "bin": { + "conc": "dist/bin/concurrently.js", + "concurrently": "dist/bin/concurrently.js" + }, + "engines": { + "node": "^14.13.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" + } + }, + "node_modules/concurrently/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", + "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==", + "license": "MIT" + }, + "node_modules/cookiejar": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz", + "integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==", + "dev": true, + "license": "MIT" + }, + "node_modules/cors": { + "version": "2.8.6", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz", + "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/create-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", + "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "prompts": "^2.0.1" + }, + "bin": { + "create-jest": "bin/create-jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-env": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", + "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.1" + }, + "bin": { + "cross-env": "src/bin/cross-env.js", + "cross-env-shell": "src/bin/cross-env-shell.js" + }, + "engines": { + "node": ">=10.14", + "npm": ">=6", + "yarn": ">=1" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/date-fns": { + "version": "2.30.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", + "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.21.0" + }, + "engines": { + "node": ">=0.11" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/date-fns" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/dedent": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.1.tgz", + "integrity": "sha512-9JmrhGZpOlEgOLdQgSm0zxFaYoQon408V1v49aqTWuXENVlnCuY9JBZcXZiCsZQWDjTm5Qf/nIvAy77mXDAjEg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/deprecation": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", + "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==", + "license": "ISC" + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/dezalgo": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", + "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", + "dev": true, + "license": "ISC", + "dependencies": { + "asap": "^2.0.0", + "wrappy": "1" + } + }, + "node_modules/diff": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.4.tgz", + "integrity": "sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dotenv": { + "version": "16.6.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", + "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.283", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.283.tgz", + "integrity": "sha512-3vifjt1HgrGW/h76UEeny+adYApveS9dH2h3p57JYzBSXJIKUJAvtmIytDKjcSCt9xHfrNCFJ7gts6vkhuq++w==", + "dev": true, + "license": "ISC" + }, + "node_modules/emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==", + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", + "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.1", + "@humanwhocodes/config-array": "^0.13.0", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventsource-parser": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.6.tgz", + "integrity": "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==", + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/expect-utils": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/express": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz", + "integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "~1.20.3", + "content-disposition": "~0.5.4", + "content-type": "~1.0.4", + "cookie": "~0.7.1", + "cookie-signature": "~1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.3.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "~2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "~0.1.12", + "proxy-addr": "~2.0.7", + "qs": "~6.14.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "~0.19.0", + "serve-static": "~1.16.2", + "setprototypeof": "1.2.0", + "statuses": "~2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/fecha": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", + "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==", + "license": "MIT" + }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz", + "integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "~2.4.1", + "parseurl": "~1.3.3", + "statuses": "~2.0.2", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, + "node_modules/fn.name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==", + "license": "MIT" + }, + "node_modules/form-data": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "license": "MIT", + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/formidable": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-2.1.5.tgz", + "integrity": "sha512-Oz5Hwvwak/DCaXVVUtPn4oLMLLy1CdclLKO1LFgU7XzDpVMUU5UjlSLpGMocyQNNk8F6IJW9M/YdooSn2MRI+Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@paralleldrive/cuid2": "^2.2.2", + "dezalgo": "^1.0.4", + "once": "^1.4.0", + "qs": "^6.11.0" + }, + "funding": { + "url": "https://ko-fi.com/tunnckoCore/commissions" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, + "node_modules/handlebars": { + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, + "node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/import-local": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", + "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/types": "^29.6.3", + "import-local": "^3.0.2", + "jest-cli": "^29.7.0" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-changed-files": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", + "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "execa": "^5.0.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", + "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^1.0.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^29.7.0", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0", + "pretty-format": "^29.7.0", + "pure-rand": "^6.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-cli": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", + "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "create-jest": "^29.7.0", + "exit": "^0.1.2", + "import-local": "^3.0.2", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "yargs": "^17.3.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-config": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", + "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-jest": "^29.7.0", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-docblock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", + "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", + "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "jest-util": "^29.7.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-environment-node": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", + "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", + "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-leak-detector": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", + "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-mock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", + "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "resolve": "^1.20.0", + "resolve.exports": "^2.0.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", + "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-regex-util": "^29.6.3", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", + "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/environment": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-leak-detector": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-resolve": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-util": "^29.7.0", + "jest-watcher": "^29.7.0", + "jest-worker": "^29.7.0", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", + "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/globals": "^29.7.0", + "@jest/source-map": "^29.6.3", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", + "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "natural-compare": "^1.4.0", + "pretty-format": "^29.7.0", + "semver": "^7.5.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "leven": "^3.1.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-watcher": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", + "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "jest-util": "^29.7.0", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==", + "license": "MIT" + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", + "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/logform": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.7.0.tgz", + "integrity": "sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==", + "license": "MIT", + "dependencies": { + "@colors/colors": "1.6.0", + "@types/triple-beam": "^1.3.2", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "safe-stable-stringify": "^2.3.1", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "license": "ISC" + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "deprecated": "Use your platform's native DOMException instead", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "license": "MIT", + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.27", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", + "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "license": "MIT", + "dependencies": { + "fn.name": "1.x.x" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-to-regexp": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", + "license": "MIT" + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/pure-rand": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT" + }, + "node_modules/qs": { + "version": "6.14.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz", + "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", + "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve.exports": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.3.tgz", + "integrity": "sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, + "node_modules/send": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz", + "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.1", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "~2.4.1", + "range-parser": "~1.2.1", + "statuses": "~2.0.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/serve-static": { + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz", + "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==", + "license": "MIT", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "~0.19.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", + "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true, + "license": "MIT" + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/spawn-command": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2.tgz", + "integrity": "sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ==", + "dev": true + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/superagent": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-8.1.2.tgz", + "integrity": "sha512-6WTxW1EB6yCxV5VFOIPQruWGHqc3yI7hEmZK6h+pyk69Lk/Ut7rLUY6W/ONF2MjBuGjvmMiIpsrVJ2vjrHlslA==", + "deprecated": "Please upgrade to superagent v10.2.2+, see release notes at https://github.com/forwardemail/superagent/releases/tag/v10.2.2 - maintenance is supported by Forward Email @ https://forwardemail.net", + "dev": true, + "license": "MIT", + "dependencies": { + "component-emitter": "^1.3.0", + "cookiejar": "^2.1.4", + "debug": "^4.3.4", + "fast-safe-stringify": "^2.1.1", + "form-data": "^4.0.0", + "formidable": "^2.1.2", + "methods": "^1.1.2", + "mime": "2.6.0", + "qs": "^6.11.0", + "semver": "^7.3.8" + }, + "engines": { + "node": ">=6.4.0 <13 || >=14" + } + }, + "node_modules/superagent/node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true, + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/supertest": { + "version": "6.3.4", + "resolved": "https://registry.npmjs.org/supertest/-/supertest-6.3.4.tgz", + "integrity": "sha512-erY3HFDG0dPnhw4U+udPfrzXa4xhSG+n4rxfRuZWCUvjFWwKl+OxWf/7zk50s84/fAAs7vf5QAb9uRa0cCykxw==", + "deprecated": "Please upgrade to supertest v7.1.3+, see release notes at https://github.com/forwardemail/supertest/releases/tag/v7.1.3 - maintenance is supported by Forward Email @ https://forwardemail.net", + "dev": true, + "license": "MIT", + "dependencies": { + "methods": "^1.1.2", + "superagent": "^8.1.2" + }, + "engines": { + "node": ">=6.4.0" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/test-exclude/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/test-exclude/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==", + "license": "MIT" + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true, + "license": "MIT" + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "license": "MIT", + "bin": { + "tree-kill": "cli.js" + } + }, + "node_modules/triple-beam": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", + "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==", + "license": "MIT", + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/ts-api-utils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz", + "integrity": "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/ts-jest": { + "version": "29.4.6", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.6.tgz", + "integrity": "sha512-fSpWtOO/1AjSNQguk43hb/JCo16oJDnMJf3CdEGNkqsEX3t0KX96xvyX1D7PfLCpVoKu4MfVrqUkFyblYoY4lA==", + "dev": true, + "license": "MIT", + "dependencies": { + "bs-logger": "^0.2.6", + "fast-json-stable-stringify": "^2.1.0", + "handlebars": "^4.7.8", + "json5": "^2.2.3", + "lodash.memoize": "^4.1.2", + "make-error": "^1.3.6", + "semver": "^7.7.3", + "type-fest": "^4.41.0", + "yargs-parser": "^21.1.1" + }, + "bin": { + "ts-jest": "cli.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "@babel/core": ">=7.0.0-beta.0 <8", + "@jest/transform": "^29.0.0 || ^30.0.0", + "@jest/types": "^29.0.0 || ^30.0.0", + "babel-jest": "^29.0.0 || ^30.0.0", + "jest": "^29.0.0 || ^30.0.0", + "jest-util": "^29.0.0 || ^30.0.0", + "typescript": ">=4.3 <6" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@jest/transform": { + "optional": true + }, + "@jest/types": { + "optional": true + }, + "babel-jest": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jest-util": { + "optional": true + } + } + }, + "node_modules/ts-jest/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ts-jest/node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/uglify-js": { + "version": "3.19.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", + "dev": true, + "license": "BSD-2-Clause", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/universal-user-agent": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.1.tgz", + "integrity": "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==", + "license": "ISC" + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true, + "license": "MIT" + }, + "node_modules/v8-to-istanbul": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/winston": { + "version": "3.19.0", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.19.0.tgz", + "integrity": "sha512-LZNJgPzfKR+/J3cHkxcpHKpKKvGfDZVPS4hfJCc4cCG0CgYzvlD6yE/S3CIL/Yt91ak327YCpiF/0MyeZHEHKA==", + "license": "MIT", + "dependencies": { + "@colors/colors": "^1.6.0", + "@dabh/diagnostics": "^2.0.8", + "async": "^3.2.3", + "is-stream": "^2.0.0", + "logform": "^2.7.0", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "safe-stable-stringify": "^2.3.1", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.9.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/winston-transport": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.9.0.tgz", + "integrity": "sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A==", + "license": "MIT", + "dependencies": { + "logform": "^2.7.0", + "readable-stream": "^3.6.2", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + } + } +} diff --git a/package.json b/package.json index a5d47f4..69e697e 100644 --- a/package.json +++ b/package.json @@ -4,12 +4,14 @@ "description": "Proxy server that lets Cursor IDE use GitHub Copilot APIs", "main": "dist/index.js", "scripts": { - "build": "tsc", + "build": "tsc && npm run copy-public", + "copy-public": "node -e \"require('fs').cpSync('src/public', 'dist/public', {recursive: true})\"", "start": "node dist/index.js", + "start:verbose": "cross-env LOG_LEVEL=debug node dist/index.js", + "start:all": "npm run build && concurrently --names \"proxy,gateway\" --prefix-colors \"cyan,magenta\" \"npm run start:verbose\" \"openclaw gateway --port 18789 --verbose\"", "dev": "ts-node src/index.ts", "lint": "eslint src/**/*.ts", - "test": "jest", - "prepare": "husky" + "test": "jest" }, "repository": { "type": "git", @@ -36,6 +38,7 @@ "@octokit/auth-oauth-device": "^6.0.1", "cors": "^2.8.5", "dotenv": "^16.4.1", + "eventsource-parser": "^3.0.6", "express": "^4.18.2", "node-fetch": "^3.3.2", "uuid": "^9.0.1", @@ -43,8 +46,6 @@ "zod": "^3.22.4" }, "devDependencies": { - "@commitlint/cli": "^18.6.0", - "@commitlint/config-conventional": "^18.6.0", "@types/cors": "^2.8.17", "@types/express": "^4.17.21", "@types/jest": "^29.5.11", @@ -53,8 +54,9 @@ "@types/uuid": "^9.0.8", "@typescript-eslint/eslint-plugin": "^6.19.1", "@typescript-eslint/parser": "^6.19.1", + "concurrently": "^8.2.2", + "cross-env": "^7.0.3", "eslint": "^8.56.0", - "husky": "^9.0.6", "jest": "^29.7.0", "supertest": "^6.3.4", "ts-jest": "^29.1.2", diff --git a/src/config/index.ts b/src/config/index.ts index 300efd3..ae85e7f 100644 --- a/src/config/index.ts +++ b/src/config/index.ts @@ -1,6 +1,6 @@ import dotenv from 'dotenv'; import { z } from 'zod'; -import pkg from '../../package.json' assert { type: 'json' }; +import pkg from '../../package.json' with { type: 'json' }; // Load environment variables dotenv.config(); @@ -32,6 +32,7 @@ const env = envSchema.parse({ const API_ENDPOINTS = { GITHUB_COPILOT_TOKEN: 'https://api.github.com/copilot_internal/v2/token', GITHUB_COPILOT_COMPLETIONS: 'https://copilot-proxy.githubusercontent.com/v1/engines/copilot-codex/completions', + GITHUB_COPILOT_CHAT: 'https://api.individual.githubcopilot.com/chat/completions', }; // Configuration object diff --git a/src/middleware/rate-limiter.ts b/src/middleware/rate-limiter.ts index b250241..0904e57 100644 --- a/src/middleware/rate-limiter.ts +++ b/src/middleware/rate-limiter.ts @@ -1,5 +1,5 @@ import { Request, Response, NextFunction } from 'express'; -import { checkRateLimit, getUsage } from '../services/usage-service.js'; +import { checkRateLimit, getUsage, getTokenUsageInWindow } from '../services/usage-service.js'; import { logger } from '../utils/logger.js'; import { config } from '../config/index.js'; import crypto from 'crypto'; diff --git a/src/routes/openai.ts b/src/routes/openai.ts index cc98f82..ce2cbf5 100644 --- a/src/routes/openai.ts +++ b/src/routes/openai.ts @@ -1,17 +1,28 @@ import express from 'express'; -import { fetchEventSource } from '@microsoft/fetch-event-source'; +import fetch from 'node-fetch'; +import { createParser, type EventSourceMessage } from 'eventsource-parser'; import { v4 as uuidv4 } from 'uuid'; import { isTokenValid, getCopilotToken, - refreshCopilotToken + refreshCopilotToken, + hasGithubToken } from '../services/auth-service.js'; import { convertMessagesToCopilotPrompt, detectLanguageFromMessages, - makeCompletionRequest + makeCompletionRequest, + convertResponsesInputToMessages, + mapToCopilotModel } from '../services/copilot-service.js'; -import { OpenAICompletionRequest, OpenAICompletion } from '../types/openai.js'; +import { + OpenAICompletionRequest, + OpenAICompletion, + ResponsesRequest, + ResponsesResponse, + ResponsesOutput, + OpenAIMessage +} from '../types/openai.js'; import { AppError } from '../middleware/error-handler.js'; import { config } from '../config/index.js'; import { getMachineId } from '../utils/machine-id.js'; @@ -22,21 +33,32 @@ export const openaiRoutes = express.Router(); // Authentication middleware const requireAuth = async (req: express.Request, res: express.Response, next: express.NextFunction) => { - if (!isTokenValid()) { + try { + // If token is valid, proceed + if (isTokenValid()) { + return next(); + } + + // Try to refresh token if we have a GitHub token + if (hasGithubToken()) { + logger.debug('Token expired, attempting refresh...'); + try { + await refreshCopilotToken(); + logger.info('Token refreshed successfully'); + return next(); + } catch (refreshError) { + logger.error('Token refresh failed:', refreshError); + // Fall through to return 401 + } + } + + // No valid token and couldn't refresh const error = new Error('Authentication required') as AppError; error.status = 401; error.code = 'authentication_required'; return next(error); - } - - try { - // Check if token needs refreshing - if (getCopilotToken() && !isTokenValid()) { - await refreshCopilotToken(); - } - next(); } catch (error) { - logger.error('Token refresh failed in middleware:', error); + logger.error('Auth middleware error:', error); const authError = new Error('Authentication failed') as AppError; authError.status = 401; authError.code = 'authentication_failed'; @@ -46,27 +68,116 @@ const requireAuth = async (req: express.Request, res: express.Response, next: ex // GET /v1/models - List available models openaiRoutes.get('/models', requireAuth, (req, res) => { - // Return a simple model list that includes models compatible with GitHub Copilot + // Return models available from GitHub Copilot API + const timestamp = Math.floor(Date.now() / 1000); res.json({ object: 'list', data: [ + // Claude Models (Anthropic) { - id: 'gpt-4', + id: 'claude-opus-4.5', object: 'model', - created: Date.now(), - owned_by: 'github-copilot', + created: timestamp, + owned_by: 'anthropic', }, + { + id: 'claude-sonnet-4.5', + object: 'model', + created: timestamp, + owned_by: 'anthropic', + }, + { + id: 'claude-sonnet-4', + object: 'model', + created: timestamp, + owned_by: 'anthropic', + }, + { + id: 'claude-haiku-4.5', + object: 'model', + created: timestamp, + owned_by: 'anthropic', + }, + // GPT Models (OpenAI/Azure) { id: 'gpt-4o', object: 'model', - created: Date.now(), - owned_by: 'github-copilot', + created: timestamp, + owned_by: 'azure-openai', + }, + { + id: 'gpt-4o-mini', + object: 'model', + created: timestamp, + owned_by: 'azure-openai', + }, + { + id: 'gpt-4.1', + object: 'model', + created: timestamp, + owned_by: 'azure-openai', + }, + { + id: 'gpt-4', + object: 'model', + created: timestamp, + owned_by: 'azure-openai', }, { id: 'gpt-3.5-turbo', object: 'model', - created: Date.now(), - owned_by: 'github-copilot', + created: timestamp, + owned_by: 'azure-openai', + }, + { + id: 'gpt-5.2', + object: 'model', + created: timestamp, + owned_by: 'openai', + }, + { + id: 'gpt-5-codex', + object: 'model', + created: timestamp, + owned_by: 'openai', + }, + // Gemini Models (Google) + { + id: 'gemini-2.5-pro', + object: 'model', + created: timestamp, + owned_by: 'google', + }, + { + id: 'gemini-3-pro-preview', + object: 'model', + created: timestamp, + owned_by: 'google', + }, + { + id: 'gemini-3-flash-preview', + object: 'model', + created: timestamp, + owned_by: 'google', + }, + // o1/o3 Reasoning Models + { + id: 'o1-preview', + object: 'model', + created: timestamp, + owned_by: 'openai', + }, + { + id: 'o1-mini', + object: 'model', + created: timestamp, + owned_by: 'openai', + }, + { + id: 'o3-mini', + object: 'model', + created: timestamp, + owned_by: 'openai', } ] }); @@ -99,7 +210,7 @@ openaiRoutes.post('/chat/completions', requireAuth, async (req, res, next) => { // Handle streaming response if (stream) { - handleStreamingCompletion(req, res, next); + handleStreamingCompletion(req, res, next, sessionId); } else { // Handle non-streaming response try { @@ -141,7 +252,8 @@ openaiRoutes.post('/chat/completions', requireAuth, async (req, res, next) => { async function handleStreamingCompletion( req: express.Request, res: express.Response, - next: express.NextFunction + next: express.NextFunction, + sessionId: string ) { try { const request = req.body as OpenAICompletionRequest; @@ -155,10 +267,6 @@ async function handleStreamingCompletion( return next(error); } - // Convert OpenAI messages to Copilot format - const prompt = convertMessagesToCopilotPrompt(messages); - const suffix = ""; // Empty for chat completions - // Get machine ID for request const machineId = getMachineId(); @@ -166,96 +274,114 @@ async function handleStreamingCompletion( res.setHeader('Content-Type', 'text/event-stream'); res.setHeader('Cache-Control', 'no-cache'); res.setHeader('Connection', 'keep-alive'); + res.setHeader('X-Accel-Buffering', 'no'); // Disable nginx buffering + res.flushHeaders(); // Ensure headers are sent immediately - const completionsUrl = config.github.copilot.apiEndpoints.GITHUB_COPILOT_COMPLETIONS; + const chatUrl = config.github.copilot.apiEndpoints.GITHUB_COPILOT_CHAT; - // Set up event source for streaming - await fetchEventSource(completionsUrl, { + // Make streaming request using node-fetch with chat completions format + const response = await fetch(chatUrl, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${copilotToken.token}`, 'X-Request-Id': uuidv4(), - 'Machine-Id': machineId, - 'User-Agent': 'GitHubCopilotChat/0.12.0', - 'Editor-Version': 'Cursor-IDE/1.0.0', - 'Editor-Plugin-Version': 'copilot-cursor/1.0.0', - 'Openai-Organization': 'github-copilot', - 'Openai-Intent': 'copilot-ghost' + 'Vscode-Machineid': machineId, + 'Vscode-Sessionid': sessionId, + 'User-Agent': 'GitHubCopilotChat/0.22.2', + 'Editor-Version': 'vscode/1.96.0', + 'Editor-Plugin-Version': 'copilot-chat/0.22.2', + 'Copilot-Integration-Id': 'vscode-chat', + 'Openai-Intent': 'conversation-agent' }, body: JSON.stringify({ - prompt, - suffix, - max_tokens: max_tokens || 500, + model: mapToCopilotModel(model || 'gpt-4o'), + messages, + max_tokens: max_tokens || 4096, temperature: temperature || 0.7, top_p: top_p || 1, n: n || 1, - stream: true, - stop: ["\n\n"], - extra: { - language: detectLanguageFromMessages(messages), - next_indent: 0, - trim_by_indentation: true, - } + stream: true }), - async onopen(response) { - if (!response.ok) { - logger.error('Stream connection error', { - status: response.status, - statusText: response.statusText - }); - throw new Error(`Stream connection error: ${response.status} ${response.statusText}`); - } - }, - onmessage(msg) { - if (msg.data === '[DONE]') { + }); + + if (!response.ok) { + logger.error('Stream connection error', { + status: response.status, + statusText: response.statusText + }); + throw new Error(`Stream connection error: ${response.status} ${response.statusText}`); + } + + if (!response.body) { + throw new Error('No response body'); + } + + // Create SSE parser (v3.x API) + const parser = createParser({ + onEvent(event: EventSourceMessage) { + const data = event.data; + + if (data === '[DONE]') { res.write('data: [DONE]\n\n'); return; } try { - // Parse the data - const data = JSON.parse(msg.data); + // Parse the data - chat completions format + const parsed = JSON.parse(data); + + // Chat completions uses delta.content, not text + const content = parsed.choices?.[0]?.delta?.content || ''; // Convert to ChatCompletions format const openAiFormatted = { - id: `chatcmpl-${uuidv4()}`, + id: parsed.id || `chatcmpl-${uuidv4()}`, object: 'chat.completion.chunk', - created: Math.floor(Date.now() / 1000), - model, + created: parsed.created || Math.floor(Date.now() / 1000), + model: parsed.model || model, choices: [ { index: 0, delta: { - content: data.choices[0].text + content: content }, - finish_reason: data.choices[0].finish_reason || null + finish_reason: parsed.choices?.[0]?.finish_reason || null } ] }; res.write(`data: ${JSON.stringify(openAiFormatted)}\n\n`); - // Note: For streaming, we don't have accurate token counts - // We'll estimate based on response length - if (data.choices[0].text) { - const estimatedTokens = Math.ceil(data.choices[0].text.length / 4); - trackRequest(sessionId, estimatedTokens); - } + // Note: For streaming, we don't have accurate token counts + // We'll estimate based on response length + if (content) { + const estimatedTokens = Math.ceil(content.length / 4); + trackRequest(sessionId, estimatedTokens); + } } catch (error) { logger.error('Error parsing stream message:', error); res.write(`data: ${JSON.stringify({ error: String(error) })}\n\n`); } - }, - onerror(err) { - logger.error('SSE stream error:', err); - res.write(`data: ${JSON.stringify({ error: String(err) })}\n\n`); - res.end(); - }, - onclose() { - res.end(); } }); + + // Process the stream + const reader = response.body; + reader.on('data', (chunk: Buffer) => { + parser.feed(chunk.toString()); + }); + + reader.on('end', () => { + res.end(); + }); + + reader.on('error', (err: Error) => { + logger.error('SSE stream error:', err); + res.write(`data: ${JSON.stringify({ error: String(err) })}\n\n`); + res.end(); + }); + } catch (error) { logger.error('Error in streaming completion:', error); @@ -273,3 +399,426 @@ async function handleStreamingCompletion( } } } + +// POST /v1/responses - OpenAI Responses API (newer format) +openaiRoutes.post('/responses', requireAuth, async (req, res, next) => { + const sessionId = res.locals.sessionId || 'default'; + trackRequest(sessionId, 0); + + try { + const request = req.body as ResponsesRequest; + const { input, instructions, stream = false, model = 'gpt-4' } = request; + + logger.debug('Responses API request', { + stream, + model, + hasInput: !!input, + inputType: typeof input + }); + + // Validate request + if (!input) { + const error = new Error('Input is required') as AppError; + error.status = 400; + error.code = 'invalid_request'; + return next(error); + } + + const copilotToken = getCopilotToken(); + if (!copilotToken) { + const error = new Error('Authentication required') as AppError; + error.status = 401; + error.code = 'authentication_required'; + return next(error); + } + + // Convert Responses API input to OpenAI messages format + const messages = convertResponsesInputToMessages(input, instructions); + + // Handle streaming response + if (stream) { + handleStreamingResponses(req, res, next, sessionId, messages, model); + } else { + // Handle non-streaming response + try { + const completionRequest: OpenAICompletionRequest = { + model, + messages, + temperature: request.temperature, + max_tokens: request.max_output_tokens, + top_p: request.top_p, + }; + + const completionData = await makeCompletionRequest(completionRequest, copilotToken.token); + + // Convert to Responses API format + const responseId = `resp_${uuidv4()}`; + const outputId = `msg_${uuidv4()}`; + + const responseOutput: ResponsesOutput = { + type: 'message', + id: outputId, + status: 'completed', + role: 'assistant', + content: completionData.choices.map(choice => ({ + type: 'output_text' as const, + text: choice.text + })) + }; + + const response: ResponsesResponse = { + id: responseId, + object: 'response', + created_at: Math.floor(Date.now() / 1000), + model, + status: 'completed', + output: [responseOutput], + usage: completionData.usage ? { + input_tokens: completionData.usage.prompt_tokens, + output_tokens: completionData.usage.completion_tokens, + total_tokens: completionData.usage.total_tokens + } : undefined, + metadata: request.metadata + }; + + // Track token usage + const totalTokens = response.usage?.total_tokens || 0; + trackRequest(sessionId, totalTokens); + + res.json(response); + } catch (error) { + logger.error('Error in non-streaming responses:', error); + next(error); + } + } + } catch (error) { + next(error); + } +}); + +// Handle streaming for Responses API +async function handleStreamingResponses( + req: express.Request, + res: express.Response, + next: express.NextFunction, + sessionId: string, + messages: OpenAIMessage[], + model: string +) { + try { + const request = req.body as ResponsesRequest; + + const copilotToken = getCopilotToken(); + if (!copilotToken || !copilotToken.token) { + const error = new Error('Authentication required') as AppError; + error.status = 401; + error.code = 'authentication_required'; + return next(error); + } + + const machineId = getMachineId(); + + // Set appropriate headers for SSE + res.setHeader('Content-Type', 'text/event-stream'); + res.setHeader('Cache-Control', 'no-cache'); + res.setHeader('Connection', 'keep-alive'); + res.setHeader('X-Accel-Buffering', 'no'); // Disable nginx buffering + res.flushHeaders(); // Ensure headers are sent immediately + + const chatUrl = config.github.copilot.apiEndpoints.GITHUB_COPILOT_CHAT; + const responseId = `resp_${uuidv4()}`; + const outputId = `msg_${uuidv4()}`; + const contentPartId = `cp_${uuidv4()}`; + let accumulatedText = ''; + let firstChunk = true; + let completionSent = false; + + // Send initial response.created event + res.write(`event: response.created\ndata: ${JSON.stringify({ + type: 'response.created', + response: { + id: responseId, + object: 'response', + created_at: Math.floor(Date.now() / 1000), + model, + status: 'in_progress', + output: [] + } + })}\n\n`); + + // Make streaming request using node-fetch with chat completions format + const response = await fetch(chatUrl, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${copilotToken.token}`, + 'X-Request-Id': uuidv4(), + 'Vscode-Machineid': machineId, + 'Vscode-Sessionid': sessionId, + 'User-Agent': 'GitHubCopilotChat/0.22.2', + 'Editor-Version': 'vscode/1.96.0', + 'Editor-Plugin-Version': 'copilot-chat/0.22.2', + 'Copilot-Integration-Id': 'vscode-chat', + 'Openai-Intent': 'conversation-agent' + }, + body: JSON.stringify({ + model: mapToCopilotModel(model || 'gpt-4o'), + messages, + max_tokens: request.max_output_tokens || 4096, + temperature: request.temperature || 0.7, + top_p: request.top_p || 1, + n: 1, + stream: true + }), + }); + + if (!response.ok) { + logger.error('Stream connection error', { + status: response.status, + statusText: response.statusText + }); + throw new Error(`Stream connection error: ${response.status} ${response.statusText}`); + } + + if (!response.body) { + throw new Error('No response body'); + } + + // Create SSE parser (v3.x API) + const parser = createParser({ + onEvent(event: EventSourceMessage) { + const data = event.data; + + if (data === '[DONE]') { + if (completionSent) return; + completionSent = true; + + // Send response.output_text.done + res.write(`event: response.output_text.done\ndata: ${JSON.stringify({ + type: 'response.output_text.done', + item_id: outputId, + output_index: 0, + content_index: 0, + text: accumulatedText + })}\n\n`); + + // Send response.output_item.done + res.write(`event: response.output_item.done\ndata: ${JSON.stringify({ + type: 'response.output_item.done', + item: { + type: 'message', + id: outputId, + status: 'completed', + role: 'assistant', + content: [{ type: 'output_text', text: accumulatedText }] + }, + output_index: 0 + })}\n\n`); + + // Send response.completed event + res.write(`event: response.completed\ndata: ${JSON.stringify({ + type: 'response.completed', + response: { + id: responseId, + object: 'response', + created_at: Math.floor(Date.now() / 1000), + model, + status: 'completed', + output: [{ + type: 'message', + id: outputId, + status: 'completed', + role: 'assistant', + content: [{ type: 'output_text', text: accumulatedText }] + }] + } + })}\n\n`); + + // Send response.done (final event) + res.write(`event: response.done\ndata: ${JSON.stringify({ + type: 'response.done', + response: { + id: responseId, + object: 'response', + created_at: Math.floor(Date.now() / 1000), + model, + status: 'completed', + output: [{ + type: 'message', + id: outputId, + status: 'completed', + role: 'assistant', + content: [{ type: 'output_text', text: accumulatedText }] + }] + } + })}\n\n`); + return; + } + + try { + const parsed = JSON.parse(data); + // Chat completions uses delta.content, not text + const text = parsed.choices?.[0]?.delta?.content || ''; + + if (text) { + // On first chunk, send output_item.added and content_part.added + if (firstChunk) { + firstChunk = false; + + // Send response.output_item.added + res.write(`event: response.output_item.added\ndata: ${JSON.stringify({ + type: 'response.output_item.added', + item: { + type: 'message', + id: outputId, + status: 'in_progress', + role: 'assistant', + content: [] + }, + output_index: 0 + })}\n\n`); + + // Send response.content_part.added + res.write(`event: response.content_part.added\ndata: ${JSON.stringify({ + type: 'response.content_part.added', + item_id: outputId, + output_index: 0, + content_index: 0, + part: { + type: 'output_text', + text: '' + } + })}\n\n`); + } + + accumulatedText += text; + + // Send response.output_text.delta event + const deltaEvent = { + type: 'response.output_text.delta', + item_id: outputId, + output_index: 0, + content_index: 0, + delta: text + }; + res.write(`event: response.output_text.delta\ndata: ${JSON.stringify(deltaEvent)}\n\n`); + logger.debug('Sent delta event', { text: text.substring(0, 50) }); + + // Track tokens + const estimatedTokens = Math.ceil(text.length / 4); + trackRequest(sessionId, estimatedTokens); + } + } catch (error) { + logger.error('Error parsing stream message:', error); + res.write(`event: error\ndata: ${JSON.stringify({ + type: 'error', + error: { message: String(error) } + })}\n\n`); + } + } + }); + + // Process the stream for Responses API + const reader = response.body; + reader.on('data', (chunk: Buffer) => { + logger.debug('Responses: Received chunk from Copilot', { length: chunk.length }); + parser.feed(chunk.toString()); + }); + + reader.on('end', () => { + logger.debug('Responses: Stream ended', { totalTextLength: accumulatedText.length }); + + // Send completion events when stream ends (Copilot doesn't send [DONE]) + if (accumulatedText.length > 0 && !completionSent) { + completionSent = true; + // Send response.output_text.done + res.write(`event: response.output_text.done\ndata: ${JSON.stringify({ + type: 'response.output_text.done', + item_id: outputId, + output_index: 0, + content_index: 0, + text: accumulatedText + })}\n\n`); + + // Send response.output_item.done + res.write(`event: response.output_item.done\ndata: ${JSON.stringify({ + type: 'response.output_item.done', + item: { + type: 'message', + id: outputId, + status: 'completed', + role: 'assistant', + content: [{ type: 'output_text', text: accumulatedText }] + }, + output_index: 0 + })}\n\n`); + + // Send response.completed event + res.write(`event: response.completed\ndata: ${JSON.stringify({ + type: 'response.completed', + response: { + id: responseId, + object: 'response', + created_at: Math.floor(Date.now() / 1000), + model, + status: 'completed', + output: [{ + type: 'message', + id: outputId, + status: 'completed', + role: 'assistant', + content: [{ type: 'output_text', text: accumulatedText }] + }] + } + })}\n\n`); + + // Send response.done (final event) + res.write(`event: response.done\ndata: ${JSON.stringify({ + type: 'response.done', + response: { + id: responseId, + object: 'response', + created_at: Math.floor(Date.now() / 1000), + model, + status: 'completed', + output: [{ + type: 'message', + id: outputId, + status: 'completed', + role: 'assistant', + content: [{ type: 'output_text', text: accumulatedText }] + }] + } + })}\n\n`); + } + + res.end(); + }); + + reader.on('error', (err: Error) => { + logger.error('SSE stream error:', err); + res.write(`event: error\ndata: ${JSON.stringify({ + type: 'error', + error: { message: String(err) } + })}\n\n`); + res.end(); + }); + + } catch (error) { + logger.error('Error in streaming responses:', error); + + if (!res.headersSent) { + return next(error); + } + + try { + res.write(`event: error\ndata: ${JSON.stringify({ + type: 'error', + error: { message: String(error) } + })}\n\n`); + res.end(); + } catch (streamError) { + logger.error('Error sending error response to stream:', streamError); + } + } +} diff --git a/src/server.ts b/src/server.ts index 20f4169..272d0c4 100644 --- a/src/server.ts +++ b/src/server.ts @@ -19,7 +19,8 @@ export const app = express(); // Apply middleware app.use(cors()); -app.use(express.json()); +app.use(express.json({ limit: '50mb' })); +app.use(express.urlencoded({ limit: '50mb', extended: true })); app.use(requestLogger); // Serve static files diff --git a/src/services/auth-service.ts b/src/services/auth-service.ts index e51a79c..7fcd6b2 100644 --- a/src/services/auth-service.ts +++ b/src/services/auth-service.ts @@ -1,49 +1,137 @@ import { createOAuthDeviceAuth } from '@octokit/auth-oauth-device'; import fetch from 'node-fetch'; +import fs from 'fs'; +import path from 'path'; +import { fileURLToPath } from 'url'; import { config } from '../config/index.js'; import { CopilotToken, VerificationResponse } from '../types/github.js'; import { logger } from '../utils/logger.js'; +// Get directory for token storage +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const TOKEN_FILE_PATH = path.join(__dirname, '..', '..', '.tokens.json'); + +// Token storage interface +interface StoredTokens { + githubToken: string | null; + copilotToken: CopilotToken | null; + savedAt: number; +} + // In-memory token storage -// Note: In a production environment with multiple instances, -// you might want to use Redis or another shared cache let githubToken: string | null = null; let copilotToken: CopilotToken | null = null; +// Store verification info for later retrieval +let pendingVerification: VerificationResponse | null = null; + /** - * Initialize the OAuth device flow for GitHub authentication - * @returns Promise Device verification info + * Load tokens from file on startup */ -export async function initiateDeviceFlow(): Promise { - const auth = createOAuthDeviceAuth({ - clientType: "oauth-app", - clientId: config.github.copilot.clientId, - scopes: ["read:user"], - onVerification(verification) { - logger.info('Device verification initiated', { - verification_uri: verification.verification_uri, - user_code: verification.user_code +function loadTokensFromFile(): void { + try { + if (fs.existsSync(TOKEN_FILE_PATH)) { + const data = fs.readFileSync(TOKEN_FILE_PATH, 'utf-8'); + const stored: StoredTokens = JSON.parse(data); + + githubToken = stored.githubToken; + copilotToken = stored.copilotToken; + + logger.info('Tokens loaded from file', { + hasGithubToken: !!githubToken, + hasCopilotToken: !!copilotToken, + savedAt: new Date(stored.savedAt).toISOString() }); - }, - }); + } + } catch (error) { + logger.error('Error loading tokens from file:', error); + } +} +/** + * Save tokens to file for persistence + */ +function saveTokensToFile(): void { try { - // Start the device authorization flow - const verification = await auth({ type: "oauth" }); - - return { - verification_uri: verification.verification_uri, - user_code: verification.user_code, - expires_in: verification.expires_in, - interval: verification.interval, - status: 'pending_verification' + const data: StoredTokens = { + githubToken, + copilotToken, + savedAt: Date.now() }; + fs.writeFileSync(TOKEN_FILE_PATH, JSON.stringify(data, null, 2), 'utf-8'); + logger.debug('Tokens saved to file'); + } catch (error) { + logger.error('Error saving tokens to file:', error); + } +} + +/** + * Delete token file + */ +function deleteTokenFile(): void { + try { + if (fs.existsSync(TOKEN_FILE_PATH)) { + fs.unlinkSync(TOKEN_FILE_PATH); + logger.debug('Token file deleted'); + } } catch (error) { - logger.error('Failed to initiate device flow:', error); - throw new Error('Failed to initiate GitHub authentication'); + logger.error('Error deleting token file:', error); } } +// Load tokens on module initialization +loadTokensFromFile(); + +/** + * Initialize the OAuth device flow for GitHub authentication + * @returns Promise Device verification info + */ +export async function initiateDeviceFlow(): Promise { + return new Promise((resolve, reject) => { + const auth = createOAuthDeviceAuth({ + clientType: "oauth-app", + clientId: config.github.copilot.clientId, + scopes: ["read:user"], + onVerification(verification) { + logger.info('Device verification initiated', { + verification_uri: verification.verification_uri, + user_code: verification.user_code + }); + + // Store and return the verification info + pendingVerification = { + verification_uri: verification.verification_uri, + user_code: verification.user_code, + expires_in: verification.expires_in, + interval: verification.interval, + status: 'pending_verification' + }; + + resolve(pendingVerification); + }, + }); + + // Start the device authorization flow - this will trigger onVerification + auth({ type: "oauth" }).then((tokenAuth) => { + // Token received means user completed authorization + if (tokenAuth.token) { + githubToken = tokenAuth.token; + saveTokensToFile(); + refreshCopilotToken().catch(err => { + logger.error('Error refreshing copilot token after auth:', err); + }); + } + }).catch((error) => { + // If we already resolved with verification info, ignore pending errors + if (!pendingVerification) { + logger.error('Failed to initiate device flow:', error); + reject(new Error('Failed to initiate GitHub authentication')); + } + }); + }); +} + /** * Check if the user has completed the device flow authorization * @returns Promise Whether authentication was successful @@ -58,6 +146,10 @@ export async function checkDeviceFlowAuth(): Promise { clientType: "oauth-app", clientId: config.github.copilot.clientId, scopes: ["read:user"], + onVerification(verification) { + // This is called when verification is needed + logger.debug('Verification check', { user_code: verification.user_code }); + }, }); try { @@ -67,6 +159,7 @@ export async function checkDeviceFlowAuth(): Promise { if (tokenAuth.token) { // Successfully authenticated githubToken = tokenAuth.token; + saveTokensToFile(); // Get Copilot token using GitHub token await refreshCopilotToken(); @@ -101,8 +194,9 @@ export async function refreshCopilotToken(): Promise { method: 'GET', headers: { 'Authorization': `token ${githubToken}`, - 'Editor-Version': 'Cursor-IDE/1.0.0', - 'Editor-Plugin-Version': 'copilot-cursor/1.0.0' + 'Editor-Version': 'vscode/1.96.0', + 'Editor-Plugin-Version': 'copilot-chat/0.22.2', + 'User-Agent': 'GitHubCopilotChat/0.22.2' } }); @@ -111,6 +205,7 @@ export async function refreshCopilotToken(): Promise { } copilotToken = await response.json() as CopilotToken; + saveTokensToFile(); logger.info('Copilot token refreshed', { expires_at: new Date(copilotToken.expires_at * 1000).toISOString() }); @@ -130,6 +225,14 @@ export function getCopilotToken(): CopilotToken | null { return copilotToken; } +/** + * Check if we have a GitHub token for refreshing + * @returns boolean Whether a GitHub token exists + */ +export function hasGithubToken(): boolean { + return !!githubToken; +} + /** * Check if the current token is valid and not expired * @returns boolean Whether the token is valid @@ -150,5 +253,6 @@ export function isTokenValid(): boolean { export function clearTokens(): void { githubToken = null; copilotToken = null; + deleteTokenFile(); logger.info('Authentication tokens cleared'); } diff --git a/src/services/copilot-service.ts b/src/services/copilot-service.ts index 91693dd..e6efbe7 100644 --- a/src/services/copilot-service.ts +++ b/src/services/copilot-service.ts @@ -3,12 +3,81 @@ import { v4 as uuidv4 } from 'uuid'; import { config } from '../config/index.js'; import { OpenAIMessage, - OpenAICompletionRequest + OpenAICompletionRequest, + ResponsesInput, + ResponsesContentPart } from '../types/openai.js'; import { CopilotCompletionResponse } from '../types/github.js'; import { getMachineId } from '../utils/machine-id.js'; import { logger } from '../utils/logger.js'; +/** + * Model name mapping from client-requested names to Copilot API model names + * Based on actual Copilot API /models endpoint response + * Copilot uses "claude-{tier}-{version}" format (e.g., claude-opus-4.5) + */ +const MODEL_MAPPING: Record = { + // Claude models - Copilot uses "claude-{tier}-{version}" format + 'claude-4.5-opus': 'claude-opus-4.5', + 'claude-opus-4.5': 'claude-opus-4.5', + 'claude-4-opus': 'claude-opus-4.5', + 'claude-opus-4': 'claude-opus-4.5', + 'claude-4.5-sonnet': 'claude-sonnet-4.5', + 'claude-sonnet-4.5': 'claude-sonnet-4.5', + 'claude-4-sonnet': 'claude-sonnet-4', + 'claude-sonnet-4': 'claude-sonnet-4', + 'claude-4.5-haiku': 'claude-haiku-4.5', + 'claude-haiku-4.5': 'claude-haiku-4.5', + 'claude-3.5-sonnet': 'claude-sonnet-4', + 'claude-3-opus': 'claude-opus-4.5', + 'claude-3-sonnet': 'claude-sonnet-4', + + // GPT models + 'gpt-4o': 'gpt-4o', + 'gpt-4o-mini': 'gpt-4o-mini', + 'gpt-4.1': 'gpt-4.1', + 'gpt-4-turbo': 'gpt-4-0125-preview', + 'gpt-4': 'gpt-4', + 'gpt-3.5-turbo': 'gpt-3.5-turbo', + 'gpt-5.2': 'gpt-5.2', + 'gpt-5-codex': 'gpt-5-codex', + 'gpt-5.1-codex-max': 'gpt-5.1-codex-max', + + // Gemini models + 'gemini-2.5-pro': 'gemini-2.5-pro', + 'gemini-3-pro': 'gemini-3-pro-preview', + 'gemini-3-pro-preview': 'gemini-3-pro-preview', + 'gemini-3-flash': 'gemini-3-flash-preview', + 'gemini-3-flash-preview': 'gemini-3-flash-preview', + + // o1/o3 reasoning models + 'o1': 'o1-preview', + 'o1-preview': 'o1-preview', + 'o1-mini': 'o1-mini', + 'o3-mini': 'o3-mini', + + // Default fallback + 'default': 'gpt-4o' +}; + +/** + * Maps a client-requested model name to a valid Copilot API model name + * + * @param requestedModel The model name requested by the client + * @returns A valid Copilot API model name + */ +export function mapToCopilotModel(requestedModel: string): string { + const mapped = MODEL_MAPPING[requestedModel.toLowerCase()]; + if (mapped) { + logger.debug('Model mapped', { from: requestedModel, to: mapped }); + return mapped; + } + + // If no mapping found, try to use the model as-is or default to gpt-4o + logger.warn('Unknown model requested, using default', { requestedModel, default: 'gpt-4o' }); + return 'gpt-4o'; +} + /** * Converts OpenAI messages format to GitHub Copilot prompt format * @@ -99,7 +168,7 @@ export function detectLanguageFromMessages(messages: OpenAIMessage[]): string { } /** - * Makes a non-streaming request to GitHub Copilot API + * Makes a non-streaming request to GitHub Copilot Chat API * * @param request OpenAI-format completion request * @param copilotToken Copilot authentication token @@ -109,58 +178,55 @@ export async function makeCompletionRequest( request: OpenAICompletionRequest, copilotToken: string ): Promise { - const { messages, temperature, max_tokens, top_p, n } = request; - - // Convert OpenAI format to Copilot format - const prompt = convertMessagesToCopilotPrompt(messages); - const suffix = ""; // Empty for chat completions + const { model, messages, temperature, max_tokens, top_p, n } = request; // Get machine ID for request const machineId = getMachineId(); - // Prepare request parameters - const completionsUrl = config.github.copilot.apiEndpoints.GITHUB_COPILOT_COMPLETIONS; + // Use chat completions endpoint for chat requests + const chatUrl = config.github.copilot.apiEndpoints.GITHUB_COPILOT_CHAT; const headers = { 'Content-Type': 'application/json', 'Authorization': `Bearer ${copilotToken}`, 'X-Request-Id': uuidv4(), - 'Machine-Id': machineId, - 'User-Agent': 'GitHubCopilotChat/0.12.0', - 'Editor-Version': 'Cursor-IDE/1.0.0', - 'Editor-Plugin-Version': 'copilot-cursor/1.0.0', - 'Openai-Organization': 'github-copilot', - 'Openai-Intent': 'copilot-ghost' + 'Vscode-Machineid': machineId, + 'Vscode-Sessionid': uuidv4(), + 'User-Agent': 'GitHubCopilotChat/0.22.2', + 'Editor-Version': 'vscode/1.96.0', + 'Editor-Plugin-Version': 'copilot-chat/0.22.2', + 'Copilot-Integration-Id': 'vscode-chat', + 'Openai-Intent': 'conversation-agent' }; + // Map the requested model to a valid Copilot model + const copilotModel = mapToCopilotModel(model || 'gpt-4o'); + + // Use OpenAI chat completions format const body = { - prompt, - suffix, - max_tokens: max_tokens || 500, + model: copilotModel, + messages, + max_tokens: max_tokens || 4096, temperature: temperature || 0.7, top_p: top_p || 1, n: n || 1, - stream: false, - stop: ["\n\n"], - extra: { - language: detectLanguageFromMessages(messages), - next_indent: 0, - trim_by_indentation: true, - } + stream: false }; try { - logger.debug('Making completion request to Copilot', { completionsUrl }); + logger.debug('Making chat completion request to Copilot', { chatUrl, model: copilotModel, requestedModel: model }); - const response = await fetch(completionsUrl, { + const response = await fetch(chatUrl, { method: 'POST', headers, body: JSON.stringify(body) }); if (!response.ok) { + const errorText = await response.text(); logger.error('Copilot API error', { status: response.status, - statusText: response.statusText + statusText: response.statusText, + error: errorText }); throw new Error(`Copilot API error: ${response.status} ${response.statusText}`); } @@ -172,3 +238,73 @@ export async function makeCompletionRequest( throw error; } } + +/** + * Converts OpenAI Responses API input to standard OpenAI messages format + * + * @param input Responses API input (string or array of ResponsesInput) + * @param instructions Optional system instructions + * @returns Array of OpenAI messages + */ +export function convertResponsesInputToMessages( + input: string | ResponsesInput[], + instructions?: string +): OpenAIMessage[] { + const messages: OpenAIMessage[] = []; + + // Add system instructions if provided + if (instructions) { + messages.push({ + role: 'system', + content: instructions + }); + } + + // Handle simple string input + if (typeof input === 'string') { + messages.push({ + role: 'user', + content: input + }); + return messages; + } + + // Handle array of ResponsesInput or OpenAI-style messages + if (Array.isArray(input)) { + for (const item of input) { + let content: string; + let itemRole: string; + + // Check if this is Responses API format (has type: 'message') or OpenAI-style (has role directly) + if (item.type === 'message' || (item.role && !item.type)) { + // Handle content - can be string or array of content parts + if (typeof item.content === 'string') { + content = item.content; + } else if (Array.isArray(item.content)) { + // Extract text from content parts + content = item.content + .filter((part): part is ResponsesContentPart => + part.type === 'input_text' || part.type === 'output_text' || part.type === 'text' + ) + .map(part => part.text) + .join(''); + } else { + content = ''; + } + + // Map Responses API roles to OpenAI message roles + itemRole = item.role === 'user' ? 'user' : + item.role === 'assistant' ? 'assistant' : + item.role === 'system' ? 'system' : + item.role === 'developer' ? 'system' : 'user'; + + messages.push({ + role: itemRole as 'system' | 'user' | 'assistant' | 'function', + content + }); + } + } + } + + return messages; +} diff --git a/src/types/openai.ts b/src/types/openai.ts index ecec276..915a1fd 100644 --- a/src/types/openai.ts +++ b/src/types/openai.ts @@ -56,3 +56,57 @@ export interface OpenAIModelList { object: string; data: OpenAIModel[]; } + +// OpenAI Responses API Types +export interface ResponsesInput { + type?: 'message'; // Optional - OpenAI-style messages may not have this + role: 'user' | 'assistant' | 'system' | 'developer'; + content: string | ResponsesContentPart[]; +} + +export interface ResponsesContentPart { + type: 'input_text' | 'output_text' | 'text'; + text: string; +} + +export interface ResponsesRequest { + model: string; + input: string | ResponsesInput[]; + instructions?: string; + temperature?: number; + max_output_tokens?: number; + top_p?: number; + stream?: boolean; + tools?: any[]; + tool_choice?: string | { type: string; name: string }; + metadata?: Record; + store?: boolean; + previous_response_id?: string; +} + +export interface ResponsesOutput { + type: 'message'; + id: string; + status: 'completed' | 'in_progress' | 'incomplete'; + role: 'assistant'; + content: ResponsesContentPart[]; +} + +export interface ResponsesResponse { + id: string; + object: 'response'; + created_at: number; + model: string; + status: 'completed' | 'in_progress' | 'incomplete' | 'failed'; + output: ResponsesOutput[]; + usage?: { + input_tokens: number; + output_tokens: number; + total_tokens: number; + }; + metadata?: Record; + error?: { + code: string; + message: string; + }; +} From 72325a6a2b3f538ab98c7b56a1a8f57fa8fb3b3f Mon Sep 17 00:00:00 2001 From: Youssef Adel Date: Mon, 2 Feb 2026 02:01:20 +0200 Subject: [PATCH 02/16] fix: update default server port in .env.example to 18790 and README --- .env.example | 2 +- README.md | 359 ++++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 331 insertions(+), 30 deletions(-) diff --git a/.env.example b/.env.example index 91d681b..4900a32 100644 --- a/.env.example +++ b/.env.example @@ -1,5 +1,5 @@ # Server Configuration -PORT=3000 +PORT=18790 HOST=localhost NODE_ENV=development diff --git a/README.md b/README.md index 2246067..ce1767c 100644 --- a/README.md +++ b/README.md @@ -1,26 +1,56 @@ -# GitHub Copilot Proxy for Cursor IDE +# GitHub Copilot Proxy - Universal OpenAI-Compatible Gateway [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT) [![TypeScript](https://img.shields.io/badge/TypeScript-5.0+-blue.svg)](https://www.typescriptlang.org/) [![Node.js](https://img.shields.io/badge/Node.js-18.0+-green.svg)](https://nodejs.org/) [![Conventional Commits](https://img.shields.io/badge/Conventional%20Commits-1.0.0-yellow.svg)](https://conventionalcommits.org) +[![OpenClaw](https://img.shields.io/badge/OpenClaw-Supported-orange.svg)](https://github.com/openclaw/openclaw) +[![OpenAI Compatible](https://img.shields.io/badge/OpenAI-Compatible-green.svg)](https://platform.openai.com/docs/api-reference) -A proxy server that enables Cursor IDE to use GitHub Copilot's API instead of Cursor's default AI services. This allows you to use your GitHub Copilot subscription with Cursor IDE, maximizing your resources by switching between services as needed. +A powerful proxy server that exposes GitHub Copilot's AI capabilities through a fully OpenAI-compatible API. Use your GitHub Copilot subscription with **any** application that supports the OpenAI API format - including Cursor IDE, OpenClaw, Continue, Aider, LangChain, and more. ## 🚀 Features -- **OpenAI API Compatibility**: Implements the OpenAI API format that Cursor IDE can use -- **GitHub Copilot Integration**: Connects to GitHub Copilot's backend services -- **Seamless Authentication**: Handles GitHub OAuth device flow authentication -- **Token Management**: Automatically refreshes Copilot tokens -- **Streaming Support**: Supports both streaming and non-streaming completions -- **Easy Configuration**: Simple setup with Cursor IDE +### Core API Support +- **OpenAI Chat Completions API**: Full `/v1/chat/completions` endpoint with streaming +- **OpenAI Responses API**: Support for the newer `/v1/responses` endpoint format +- **OpenAI Models API**: `/v1/models` endpoint for model discovery +- **SSE Streaming**: Real-time Server-Sent Events streaming for all completions + +### GitHub Copilot Integration +- **Multi-Model Access**: Access Claude, GPT, Gemini, and reasoning models through your Copilot subscription +- **OAuth Device Flow**: Secure browser-based GitHub authentication +- **Token Persistence**: Tokens stored in `.tokens.json` survive server restarts +- **Auto Token Refresh**: Automatically refreshes expired Copilot tokens + +### Supported AI Models + +| Provider | Models | +|----------|--------| +| **Anthropic Claude** | `claude-opus-4.5`, `claude-sonnet-4.5`, `claude-sonnet-4`, `claude-haiku-4.5` | +| **OpenAI GPT** | `gpt-5.2`, `gpt-5-codex`, `gpt-5.1-codex-max`, `gpt-4o`, `gpt-4o-mini`, `gpt-4.1`, `gpt-4`, `gpt-3.5-turbo` | +| **Google Gemini** | `gemini-2.5-pro`, `gemini-3-pro-preview`, `gemini-3-flash-preview` | +| **Reasoning** | `o1-preview`, `o1-mini`, `o3-mini` | + +### Smart Model Mapping +Automatically translates common model name variations: +- `claude-4.5-opus` → `claude-opus-4.5` +- `claude-4.5-sonnet` → `claude-sonnet-4.5` +- `gpt-4-turbo` → `gpt-4-0125-preview` +- `gemini-3-pro` → `gemini-3-pro-preview` + +### Framework & Tool Integration +- **OpenClaw**: Full integration with multi-agent AI workflows +- **Cursor IDE**: Drop-in replacement for Cursor's AI backend +- **Continue**: VS Code AI assistant extension +- **Aider**: AI pair programming in your terminal +- **LangChain/LlamaIndex**: LLM orchestration frameworks +- **Any OpenAI SDK**: Works with official SDKs in Python, Node.js, Go, etc. ## 📋 Prerequisites - Node.js 18.0 or higher -- GitHub Copilot subscription -- Cursor IDE +- GitHub Copilot subscription (Individual, Business, or Enterprise) ## 🔧 Installation @@ -50,50 +80,307 @@ A proxy server that enables Cursor IDE to use GitHub Copilot's API instead of Cu npm start ``` + Or run with verbose logging: + ```bash + npm run start:verbose + ``` + ## 🔌 Configuration with Cursor IDE 1. Open Cursor IDE 2. Go to Settings > API Keys 3. In the "Override OpenAI Base URL" section, enter: ``` - http://localhost:3000 + http://localhost:18790/v1 ``` -4. Go to http://localhost:3000 in your browser +4. Go to http://localhost:18790/auth.html in your browser 5. Follow the authentication steps to connect to GitHub -## 💡 Usage +## 🐾 OpenClaw Integration + +This proxy fully supports [OpenClaw](https://github.com/openclaw/openclaw), an AI agent framework that enables building sophisticated multi-agent workflows. + +### Quick Start with OpenClaw + +1. Start the proxy with OpenClaw gateway: + ```bash + npm run start:all + ``` + +2. Configure OpenClaw to use the proxy: + ```yaml + # openclaw.config.yaml + provider: + type: openai + baseUrl: http://localhost:18790/v1 + ``` + +3. Authenticate at `http://localhost:18790/auth.html` + +### OpenClaw Agent Categories + +| Category | Description | Recommended Models | +|----------|-------------|-------------------| +| **Workflow** | Orchestration and task management | GPT-4o, Claude Sonnet 4.5 | +| **Processing** | Data transformation and analysis | GPT-4o-mini, Claude Haiku 4.5 | +| **Integration** | External service connections | GPT-4, Gemini 2.5 Pro | +| **Worker** | Background task execution | GPT-3.5-turbo, o3-mini | +| **Sub-agent** | Specialized nested agents | Any supported model | + +## 🔧 Other Compatible Applications + +### Continue (VS Code Extension) +```json +// ~/.continue/config.json +{ + "models": [{ + "title": "GitHub Copilot via Proxy", + "provider": "openai", + "model": "gpt-4o", + "apiBase": "http://localhost:18790/v1", + "apiKey": "dummy" + }] +} +``` + +### Aider (AI Pair Programming) +```bash +# Set environment variables +export OPENAI_API_BASE=http://localhost:18790/v1 +export OPENAI_API_KEY=dummy + +# Run Aider with any supported model +aider --model gpt-4o +aider --model claude-sonnet-4.5 +``` + +### LangChain (Python) +```python +from langchain_openai import ChatOpenAI + +llm = ChatOpenAI( + model="gpt-4o", + base_url="http://localhost:18790/v1", + api_key="dummy" # Not validated, but required +) + +response = llm.invoke("Hello, how are you?") +``` + +### LlamaIndex (Python) +```python +from llama_index.llms.openai import OpenAI + +llm = OpenAI( + model="claude-sonnet-4.5", + api_base="http://localhost:18790/v1", + api_key="dummy" +) +``` + +### OpenAI Python SDK +```python +from openai import OpenAI + +client = OpenAI( + base_url="http://localhost:18790/v1", + api_key="dummy" +) + +response = client.chat.completions.create( + model="gpt-4o", + messages=[{"role": "user", "content": "Hello!"}], + stream=True +) + +for chunk in response: + print(chunk.choices[0].delta.content, end="") +``` -Once configured, you can use Cursor IDE as normal. All AI-powered features will now use your GitHub Copilot subscription instead of Cursor's API. +### OpenAI Node.js SDK +```javascript +import OpenAI from 'openai'; -To switch back to Cursor's API: -1. Go to Settings > API Keys -2. Remove the Override OpenAI Base URL +const openai = new OpenAI({ + baseURL: 'http://localhost:18790/v1', + apiKey: 'dummy' +}); + +const stream = await openai.chat.completions.create({ + model: 'claude-opus-4.5', + messages: [{ role: 'user', content: 'Hello!' }], + stream: true +}); + +for await (const chunk of stream) { + process.stdout.write(chunk.choices[0]?.delta?.content || ''); +} +``` + +### cURL / REST API +```bash +# List available models +curl http://localhost:18790/v1/models + +# Chat completion +curl http://localhost:18790/v1/chat/completions \ + -H "Content-Type: application/json" \ + -d '{ + "model": "gpt-4o", + "messages": [{"role": "user", "content": "Hello!"}], + "stream": false + }' + +# Responses API (newer format) +curl http://localhost:18790/v1/responses \ + -H "Content-Type: application/json" \ + -d '{ + "model": "claude-sonnet-4.5", + "input": "Explain quantum computing", + "stream": false + }' +``` + +## 🌐 API Endpoints + +| Endpoint | Method | Description | +|----------|--------|-------------| +| `/v1/models` | GET | List all available models | +| `/v1/chat/completions` | POST | Chat completions (OpenAI format, streaming supported) | +| `/v1/responses` | POST | Responses API (newer OpenAI format, streaming supported) | +| `/auth/status` | GET | Check authentication status | +| `/auth/login` | POST | Initiate GitHub device flow | +| `/auth/logout` | POST | Clear authentication tokens | +| `/auth.html` | GET | Browser-based authentication UI | +| `/usage.html` | GET | Token usage tracking dashboard | + +## 💡 Usage Examples + +### Basic Chat Completion +```bash +curl -X POST http://localhost:18790/v1/chat/completions \ + -H "Content-Type: application/json" \ + -d '{ + "model": "gpt-4o", + "messages": [ + {"role": "system", "content": "You are a helpful assistant."}, + {"role": "user", "content": "What is the capital of France?"} + ] + }' +``` + +### Streaming Response +```bash +curl -X POST http://localhost:18790/v1/chat/completions \ + -H "Content-Type: application/json" \ + -d '{ + "model": "claude-sonnet-4.5", + "messages": [{"role": "user", "content": "Write a haiku about coding"}], + "stream": true + }' +``` + +### Responses API Format +```bash +curl -X POST http://localhost:18790/v1/responses \ + -H "Content-Type: application/json" \ + -d '{ + "model": "gemini-2.5-pro", + "input": "Explain machine learning in simple terms", + "instructions": "Be concise and use analogies" + }' +``` ## 🤔 How It Works 1. The proxy authenticates with GitHub using the OAuth device flow 2. GitHub provides a token that the proxy uses to obtain a Copilot token -3. Cursor sends requests to the proxy in OpenAI format -4. The proxy converts these requests to GitHub Copilot's format -5. The proxy forwards responses back to Cursor in OpenAI format +3. Tokens are persisted to `.tokens.json` and auto-refresh when expired +4. Your application sends requests to the proxy in OpenAI format +5. The proxy maps model names and converts requests to GitHub Copilot Chat API format +6. The proxy forwards responses back in OpenAI format (with SSE streaming) + +## 🎯 Model Mapping + +The proxy automatically translates model names to Copilot's format: + +| You Request | Copilot Receives | +|-------------|------------------| +| `claude-4.5-opus` | `claude-opus-4.5` | +| `claude-4.5-sonnet` | `claude-sonnet-4.5` | +| `claude-3.5-sonnet` | `claude-sonnet-4` | +| `claude-3-opus` | `claude-opus-4.5` | +| `gpt-4-turbo` | `gpt-4-0125-preview` | +| `gemini-3-pro` | `gemini-3-pro-preview` | +| `gemini-3-flash` | `gemini-3-flash-preview` | +| `o1` | `o1-preview` | + +You can use either format - the proxy handles the translation automatically. ## 🛠️ Development -### Running in development mode: +### Available Scripts ```bash -npm run dev +npm run build # Build the TypeScript project +npm start # Start the server +npm run start:verbose # Start with debug logging +npm run start:all # Build and run with OpenClaw gateway +npm run dev # Run in development mode with ts-node +npm test # Run tests +npm run lint # Run linting ``` -### Testing: -```bash -npm test -``` +### Environment Variables +| Variable | Default | Description | +|----------|---------|-------------| +| `PORT` | `18790` | Server port | +| `HOST` | `localhost` | Server host | +| `LOG_LEVEL` | `info` | Logging level (`error`, `warn`, `info`, `debug`) | -### Linting: -```bash -npm run lint +## 🏗️ Architecture + +``` +┌─────────────────────────────────────────────────────────────┐ +│ Your Applications │ +│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────────────┐ │ +│ │ Cursor │ │OpenClaw │ │Continue │ │ LangChain/Aider │ │ +│ └────┬────┘ └────┬────┘ └────┬────┘ └────────┬────────┘ │ +└───────┼────────────┼────────────┼────────────────┼──────────┘ + │ │ │ │ + └────────────┴─────┬──────┴────────────────┘ + │ + OpenAI API Format + │ + ▼ + ┌────────────────────────────────┐ + │ GitHub Copilot Proxy │ + │ http://localhost:18790/v1 │ + │ │ + │ • /v1/chat/completions │ + │ • /v1/responses │ + │ • /v1/models │ + │ • Model name mapping │ + │ • Token management │ + │ • SSE streaming │ + └───────────────┬────────────────┘ + │ + GitHub Copilot API + │ + ▼ + ┌────────────────────────────────┐ + │ GitHub Copilot │ + │ │ + │ Claude • GPT • Gemini • o1/o3 │ + └────────────────────────────────┘ ``` +## 🔒 Security Notes + +- Tokens are stored locally in `.tokens.json` - **do not commit this file** +- The proxy requires a valid GitHub Copilot subscription +- API key parameter is ignored (authentication via GitHub OAuth) +- Recommended: Run on localhost only in production + ## 📄 License This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. @@ -107,3 +394,17 @@ Contributions are welcome! Please feel free to submit a Pull Request. 3. Commit your changes using conventional commits (`git commit -m 'feat: add amazing feature'`) 4. Push to the branch (`git push origin feature/amazing-feature`) 5. Open a Pull Request + +## ❓ FAQ + +**Q: Do I need to provide an API key?** +A: No. The proxy uses GitHub OAuth device flow for authentication. Any `apiKey` parameter is ignored. + +**Q: Which models are available?** +A: All models available through your GitHub Copilot subscription, including Claude, GPT, Gemini, and reasoning models. + +**Q: Does streaming work?** +A: Yes! Both `/v1/chat/completions` and `/v1/responses` support SSE streaming. + +**Q: Can I use this with other tools?** +A: Yes! Any tool that supports the OpenAI API format can use this proxy - Cursor, OpenClaw, Continue, Aider, LangChain, LlamaIndex, and more. From 326b14bf15ccabf216e5f540ed49db54c636ae7a Mon Sep 17 00:00:00 2001 From: Youssef Adel Date: Mon, 2 Feb 2026 02:18:04 +0200 Subject: [PATCH 03/16] feat: update TypeScript and Node.js versions in README and package.json; change target to ES2023 in tsconfig --- README.md | 19 ++++++++++++------- package.json | 12 ++++++------ tsconfig.json | 2 +- 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index ce1767c..75d8348 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # GitHub Copilot Proxy - Universal OpenAI-Compatible Gateway [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT) -[![TypeScript](https://img.shields.io/badge/TypeScript-5.0+-blue.svg)](https://www.typescriptlang.org/) -[![Node.js](https://img.shields.io/badge/Node.js-18.0+-green.svg)](https://nodejs.org/) +[![TypeScript](https://img.shields.io/badge/TypeScript-5.5+-blue.svg)](https://www.typescriptlang.org/) +[![Node.js](https://img.shields.io/badge/Node.js-22.0+-green.svg)](https://nodejs.org/) [![Conventional Commits](https://img.shields.io/badge/Conventional%20Commits-1.0.0-yellow.svg)](https://conventionalcommits.org) [![OpenClaw](https://img.shields.io/badge/OpenClaw-Supported-orange.svg)](https://github.com/openclaw/openclaw) [![OpenAI Compatible](https://img.shields.io/badge/OpenAI-Compatible-green.svg)](https://platform.openai.com/docs/api-reference) @@ -49,7 +49,7 @@ Automatically translates common model name variations: ## 📋 Prerequisites -- Node.js 18.0 or higher +- Node.js 22.0 or higher - GitHub Copilot subscription (Individual, Business, or Enterprise) ## 🔧 Installation @@ -102,12 +102,17 @@ This proxy fully supports [OpenClaw](https://github.com/openclaw/openclaw), an A ### Quick Start with OpenClaw -1. Start the proxy with OpenClaw gateway: +1. Install OpenClaw CLI globally: ```bash - npm run start:all + npm install -g openclaw ``` -2. Configure OpenClaw to use the proxy: +2. Start the proxy with OpenClaw gateway: + ```bash + npm run start:openclaw + ``` + +3. Configure OpenClaw to use the proxy: ```yaml # openclaw.config.yaml provider: @@ -324,7 +329,7 @@ You can use either format - the proxy handles the translation automatically. npm run build # Build the TypeScript project npm start # Start the server npm run start:verbose # Start with debug logging -npm run start:all # Build and run with OpenClaw gateway +npm run start:openclaw # Build and run with OpenClaw gateway (requires: npm i -g openclaw) npm run dev # Run in development mode with ts-node npm test # Run tests npm run lint # Run linting diff --git a/package.json b/package.json index 69e697e..4ff07da 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "copy-public": "node -e \"require('fs').cpSync('src/public', 'dist/public', {recursive: true})\"", "start": "node dist/index.js", "start:verbose": "cross-env LOG_LEVEL=debug node dist/index.js", - "start:all": "npm run build && concurrently --names \"proxy,gateway\" --prefix-colors \"cyan,magenta\" \"npm run start:verbose\" \"openclaw gateway --port 18789 --verbose\"", + "start:openclaw": "npm run build && concurrently --names \"proxy,gateway\" --prefix-colors \"cyan,magenta\" \"npm run start:verbose\" \"openclaw gateway --port 18789 --verbose\"", "dev": "ts-node src/index.ts", "lint": "eslint src/**/*.ts", "test": "jest" @@ -49,11 +49,11 @@ "@types/cors": "^2.8.17", "@types/express": "^4.17.21", "@types/jest": "^29.5.11", - "@types/node": "^20.11.6", + "@types/node": "^22.0.0", "@types/supertest": "^6.0.2", "@types/uuid": "^9.0.8", - "@typescript-eslint/eslint-plugin": "^6.19.1", - "@typescript-eslint/parser": "^6.19.1", + "@typescript-eslint/eslint-plugin": "^7.0.0", + "@typescript-eslint/parser": "^7.0.0", "concurrently": "^8.2.2", "cross-env": "^7.0.3", "eslint": "^8.56.0", @@ -61,10 +61,10 @@ "supertest": "^6.3.4", "ts-jest": "^29.1.2", "ts-node": "^10.9.2", - "typescript": "^5.3.3" + "typescript": "^5.5.0" }, "type": "module", "engines": { - "node": ">=18.0.0" + "node": ">=22.0.0" } } diff --git a/tsconfig.json b/tsconfig.json index f2daf97..aca4966 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "target": "ES2022", + "target": "ES2023", "module": "NodeNext", "moduleResolution": "NodeNext", "esModuleInterop": true, From 82dc445aa2028c63fb352c1ad1b2d0d596a36fdd Mon Sep 17 00:00:00 2001 From: Youssef Adel Date: Mon, 2 Feb 2026 03:16:23 +0200 Subject: [PATCH 04/16] feat: add legacy completions API endpoint and types; update README and Jest config for compatibility --- README.md | 1 + jest.config.js | 7 + package.json | 2 +- src/routes/openai.ts | 258 +++++++++++++++++++++++++++++++- src/services/copilot-service.ts | 20 ++- src/types/openai.ts | 40 +++++ 6 files changed, 315 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 75d8348..8717f24 100644 --- a/README.md +++ b/README.md @@ -251,6 +251,7 @@ curl http://localhost:18790/v1/responses \ | Endpoint | Method | Description | |----------|--------|-------------| | `/v1/models` | GET | List all available models | +| `/v1/completions` | POST | Legacy completions API (for Cursor tab autocomplete) | | `/v1/chat/completions` | POST | Chat completions (OpenAI format, streaming supported) | | `/v1/responses` | POST | Responses API (newer OpenAI format, streaming supported) | | `/auth/status` | GET | Check authentication status | diff --git a/jest.config.js b/jest.config.js index d60ed5c..1248400 100644 --- a/jest.config.js +++ b/jest.config.js @@ -11,7 +11,14 @@ export default { 'ts-jest', { useESM: true, + diagnostics: { + ignoreCodes: [151002], + }, }, ], }, + // Handle ESM modules in node_modules + transformIgnorePatterns: [ + 'node_modules/(?!(node-fetch|eventsource-parser)/)', + ], }; diff --git a/package.json b/package.json index 4ff07da..726a101 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "start:openclaw": "npm run build && concurrently --names \"proxy,gateway\" --prefix-colors \"cyan,magenta\" \"npm run start:verbose\" \"openclaw gateway --port 18789 --verbose\"", "dev": "ts-node src/index.ts", "lint": "eslint src/**/*.ts", - "test": "jest" + "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js" }, "repository": { "type": "git", diff --git a/src/routes/openai.ts b/src/routes/openai.ts index ce2cbf5..84fd78e 100644 --- a/src/routes/openai.ts +++ b/src/routes/openai.ts @@ -21,7 +21,9 @@ import { ResponsesRequest, ResponsesResponse, ResponsesOutput, - OpenAIMessage + OpenAIMessage, + LegacyCompletionRequest, + LegacyCompletion } from '../types/openai.js'; import { AppError } from '../middleware/error-handler.js'; import { config } from '../config/index.js'; @@ -183,6 +185,260 @@ openaiRoutes.get('/models', requireAuth, (req, res) => { }); }); +// POST /v1/completions - Legacy completions API (for Cursor tab completions) +openaiRoutes.post('/completions', requireAuth, async (req, res, next) => { + const sessionId = res.locals.sessionId || `session-${uuidv4()}`; + trackRequest(sessionId, 0); + + try { + const request = req.body as LegacyCompletionRequest; + const { prompt, stream = false, model = 'gpt-4o' } = request; + + // Validate request + if (!prompt) { + const error = new Error('Prompt is required') as AppError; + error.status = 400; + error.code = 'invalid_request'; + return next(error); + } + + const copilotToken = getCopilotToken(); + if (!copilotToken) { + const error = new Error('Authentication required') as AppError; + error.status = 401; + error.code = 'authentication_required'; + return next(error); + } + + // Handle streaming response + if (stream) { + handleStreamingLegacyCompletion(req, res, next, sessionId); + } else { + // Handle non-streaming response + try { + const machineId = getMachineId(); + const completionsUrl = config.github.copilot.apiEndpoints.GITHUB_COPILOT_COMPLETIONS; + + const promptText = Array.isArray(prompt) ? prompt.join('\n') : prompt; + + const response = await fetch(completionsUrl, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${copilotToken.token}`, + 'X-Request-Id': uuidv4(), + 'Vscode-Machineid': machineId, + 'Vscode-Sessionid': sessionId, + 'User-Agent': 'GitHubCopilotChat/0.22.2', + 'Editor-Version': 'vscode/1.96.0', + 'Editor-Plugin-Version': 'copilot-chat/0.22.2', + 'Copilot-Integration-Id': 'vscode-chat', + 'Openai-Intent': 'copilot-ghost' + }, + body: JSON.stringify({ + prompt: promptText, + suffix: request.suffix || '', + max_tokens: request.max_tokens || 500, + temperature: request.temperature || 0.1, + top_p: request.top_p || 1, + n: request.n || 1, + stream: false, + stop: request.stop || ['\n\n'], + extra: { + language: 'typescript', // Default, could be detected + next_indent: 0, + trim_by_indentation: true, + } + }), + }); + + if (!response.ok) { + const errorText = await response.text(); + logger.error('Completions API error', { status: response.status, error: errorText }); + throw new Error(`Completions API error: ${response.status}`); + } + + const data = await response.json() as any; + + // Convert to OpenAI format + const legacyResponse: LegacyCompletion = { + id: `cmpl-${uuidv4()}`, + object: 'text_completion', + created: Math.floor(Date.now() / 1000), + model, + choices: (data.choices || []).map((choice: any, index: number) => ({ + text: choice.text || '', + index, + logprobs: null, + finish_reason: choice.finish_reason || 'stop', + })), + usage: data.usage + }; + + // Track token usage + const totalTokens = legacyResponse.usage?.total_tokens || 0; + trackRequest(sessionId, totalTokens); + + res.json(legacyResponse); + } catch (error) { + logger.error('Error in non-streaming legacy completion:', error); + next(error); + } + } + } catch (error) { + next(error); + } +}); + +// Handle streaming legacy completions (for Cursor tab completions) +async function handleStreamingLegacyCompletion( + req: express.Request, + res: express.Response, + next: express.NextFunction, + sessionId: string +) { + try { + const request = req.body as LegacyCompletionRequest; + const { prompt, model = 'gpt-4o' } = request; + + const copilotToken = getCopilotToken(); + if (!copilotToken || !copilotToken.token) { + const error = new Error('Authentication required') as AppError; + error.status = 401; + error.code = 'authentication_required'; + return next(error); + } + + const machineId = getMachineId(); + + // Set appropriate headers for SSE + res.setHeader('Content-Type', 'text/event-stream'); + res.setHeader('Cache-Control', 'no-cache'); + res.setHeader('Connection', 'keep-alive'); + res.setHeader('X-Accel-Buffering', 'no'); + res.flushHeaders(); + + const completionsUrl = config.github.copilot.apiEndpoints.GITHUB_COPILOT_COMPLETIONS; + const promptText = Array.isArray(prompt) ? prompt.join('\n') : prompt; + + const response = await fetch(completionsUrl, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${copilotToken.token}`, + 'X-Request-Id': uuidv4(), + 'Vscode-Machineid': machineId, + 'Vscode-Sessionid': sessionId, + 'User-Agent': 'GitHubCopilotChat/0.22.2', + 'Editor-Version': 'vscode/1.96.0', + 'Editor-Plugin-Version': 'copilot-chat/0.22.2', + 'Copilot-Integration-Id': 'vscode-chat', + 'Openai-Intent': 'copilot-ghost' + }, + body: JSON.stringify({ + prompt: promptText, + suffix: request.suffix || '', + max_tokens: request.max_tokens || 500, + temperature: request.temperature || 0.1, + top_p: request.top_p || 1, + n: request.n || 1, + stream: true, + stop: request.stop || ['\n\n'], + extra: { + language: 'typescript', + next_indent: 0, + trim_by_indentation: true, + } + }), + }); + + if (!response.ok) { + logger.error('Stream connection error', { + status: response.status, + statusText: response.statusText + }); + throw new Error(`Stream connection error: ${response.status} ${response.statusText}`); + } + + if (!response.body) { + throw new Error('No response body'); + } + + // Create SSE parser + const parser = createParser({ + onEvent(event: EventSourceMessage) { + const data = event.data; + + if (data === '[DONE]') { + res.write('data: [DONE]\n\n'); + return; + } + + try { + const parsed = JSON.parse(data); + const text = parsed.choices?.[0]?.text || ''; + + // Convert to legacy completion format + const legacyFormatted = { + id: `cmpl-${uuidv4()}`, + object: 'text_completion', + created: Math.floor(Date.now() / 1000), + model, + choices: [ + { + text: text, + index: 0, + logprobs: null, + finish_reason: parsed.choices?.[0]?.finish_reason || null + } + ] + }; + + res.write(`data: ${JSON.stringify(legacyFormatted)}\n\n`); + + if (text) { + const estimatedTokens = Math.ceil(text.length / 4); + trackRequest(sessionId, estimatedTokens); + } + } catch (error) { + logger.error('Error parsing stream message:', error); + res.write(`data: ${JSON.stringify({ error: String(error) })}\n\n`); + } + } + }); + + // Process the stream + const reader = response.body; + reader.on('data', (chunk: Buffer) => { + parser.feed(chunk.toString()); + }); + + reader.on('end', () => { + res.end(); + }); + + reader.on('error', (err: Error) => { + logger.error('SSE stream error:', err); + res.write(`data: ${JSON.stringify({ error: String(err) })}\n\n`); + res.end(); + }); + + } catch (error) { + logger.error('Error in streaming legacy completion:', error); + + if (!res.headersSent) { + return next(error); + } + + try { + res.write(`data: ${JSON.stringify({ error: String(error) })}\n\n`); + res.end(); + } catch (streamError) { + logger.error('Error sending error response to stream:', streamError); + } + } +} + // POST /v1/chat/completions - Create a completion openaiRoutes.post('/chat/completions', requireAuth, async (req, res, next) => { // Track this request diff --git a/src/services/copilot-service.ts b/src/services/copilot-service.ts index e6efbe7..6a8222c 100644 --- a/src/services/copilot-service.ts +++ b/src/services/copilot-service.ts @@ -89,32 +89,30 @@ export function convertMessagesToCopilotPrompt(messages: OpenAIMessage[]): strin return ''; } - let systemPrompt = ''; - let userPrompts = ''; - let assistantResponses = ''; + let prompt = ''; - // Process messages in order to construct a coherent prompt + // Process messages in order to preserve conversation flow for (const message of messages) { if (!message.role || !message.content) continue; switch (message.role) { case 'system': - systemPrompt += message.content + '\n\n'; + prompt += message.content + '\n\n'; break; case 'user': - userPrompts += 'User: ' + message.content + '\n\n'; + prompt += 'User: ' + message.content + '\n\n'; break; case 'assistant': - assistantResponses += 'Assistant: ' + message.content + '\n\n'; + prompt += 'Assistant: ' + message.content + '\n\n'; break; } } // Ensure it ends with a user message to prompt a response const lastMessage = messages[messages.length - 1]; - const needsAssistantPrompt = lastMessage.role !== 'user'; + const needsAssistantPrompt = lastMessage.role === 'user'; - return systemPrompt + userPrompts + assistantResponses + (needsAssistantPrompt ? '' : 'Assistant: '); + return prompt + (needsAssistantPrompt ? 'Assistant: ' : ''); } /** @@ -141,8 +139,8 @@ export function detectLanguageFromMessages(messages: OpenAIMessage[]): string { return codeBlockMatch[1].toLowerCase(); } - // Check for file extensions in the message - const fileExtensionMatch = content.match(/\.([a-zA-Z0-9]+)(?:\s|"|')/); + // Check for file extensions in the message (followed by space, quote, or end of word boundary) + const fileExtensionMatch = content.match(/\.([a-zA-Z0-9]+)(?:\s|"|'|$|\?)/); if (fileExtensionMatch && fileExtensionMatch[1]) { const ext = fileExtensionMatch[1].toLowerCase(); const extToLang: Record = { diff --git a/src/types/openai.ts b/src/types/openai.ts index 915a1fd..79c49d9 100644 --- a/src/types/openai.ts +++ b/src/types/openai.ts @@ -57,6 +57,46 @@ export interface OpenAIModelList { data: OpenAIModel[]; } +// Legacy Completions API Types (for /v1/completions - used by Cursor tab completions) +export interface LegacyCompletionRequest { + model: string; + prompt: string | string[]; + suffix?: string; + max_tokens?: number; + temperature?: number; + top_p?: number; + n?: number; + stream?: boolean; + logprobs?: number; + echo?: boolean; + stop?: string | string[]; + presence_penalty?: number; + frequency_penalty?: number; + best_of?: number; + logit_bias?: Record; + user?: string; +} + +export interface LegacyCompletionChoice { + text: string; + index: number; + logprobs: null; + finish_reason: string | null; +} + +export interface LegacyCompletion { + id: string; + object: 'text_completion'; + created: number; + model: string; + choices: LegacyCompletionChoice[]; + usage?: { + prompt_tokens: number; + completion_tokens: number; + total_tokens: number; + }; +} + // OpenAI Responses API Types export interface ResponsesInput { type?: 'message'; // Optional - OpenAI-style messages may not have this From 565c9108477c3ab3aafa516f7bed543ff4a310f8 Mon Sep 17 00:00:00 2001 From: Youssef Adel Date: Mon, 2 Feb 2026 03:41:33 +0200 Subject: [PATCH 05/16] feat: implement auto-opening of authentication/setup pages and add setup page; update navigation links --- src/index.ts | 32 ++- src/public/auth.html | 12 +- src/public/setup.html | 475 ++++++++++++++++++++++++++++++++++++++++++ src/public/usage.html | 1 + 4 files changed, 517 insertions(+), 3 deletions(-) create mode 100644 src/public/setup.html diff --git a/src/index.ts b/src/index.ts index 5604a44..f0d4731 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,26 @@ import { app } from './server.js'; import { config } from './config/index.js'; import { logger } from './utils/logger.js'; +import { isTokenValid, hasGithubToken } from './services/auth-service.js'; +import { exec } from 'child_process'; +import { platform } from 'os'; + +/** + * Opens a URL in the default browser + */ +function openBrowser(url: string): void { + const command = platform() === 'win32' + ? `start "" "${url}"` + : platform() === 'darwin' + ? `open "${url}"` + : `xdg-open "${url}"`; + + exec(command, (error) => { + if (error) { + logger.warn('Could not open browser automatically. Please visit:', url); + } + }); +} const startServer = () => { const port = config.server.port; @@ -8,8 +28,18 @@ const startServer = () => { try { app.listen(port, () => { - logger.info(`Server running at http://${host}:${port}/`); + const serverUrl = `http://${host}:${port}`; + logger.info(`Server running at ${serverUrl}/`); logger.info('Press CTRL-C to stop the server'); + + // Auto-open appropriate page based on authentication status + if (!isTokenValid() && !hasGithubToken()) { + logger.info('No valid authentication found. Opening auth page...'); + openBrowser(`${serverUrl}/auth.html`); + } else { + logger.info('Authentication tokens found. Opening setup page...'); + openBrowser(`${serverUrl}/setup.html`); + } }); } catch (error) { logger.error('Error starting server:', error); diff --git a/src/public/auth.html b/src/public/auth.html index fab29b3..7f2a11c 100644 --- a/src/public/auth.html +++ b/src/public/auth.html @@ -92,6 +92,7 @@

GitHub Copilot Proxy Authentication

@@ -246,7 +247,7 @@

Setup Instructions

if (data.status === 'authenticated') { isComplete = true; - showAuthenticatedState(data); + showAuthenticatedState(data, true); // Redirect to setup } else { verificationStatus.textContent = `Waiting for verification... (${attempts + 1})`; attempts++; @@ -268,7 +269,7 @@

Setup Instructions

} } - function showAuthenticatedState(data) { + function showAuthenticatedState(data, redirectToSetup = false) { statusDisplay.className = 'status success'; statusDisplay.textContent = 'You are authenticated with GitHub Copilot!'; @@ -282,6 +283,13 @@

Setup Instructions

} else { tokenExpiry.textContent = 'Unknown'; } + + // Auto-redirect to setup page after successful authentication + if (redirectToSetup) { + setTimeout(() => { + window.location.href = '/setup.html'; + }, 1500); + } } function showUnauthenticatedState() { diff --git a/src/public/setup.html b/src/public/setup.html new file mode 100644 index 0000000..cfe77f6 --- /dev/null +++ b/src/public/setup.html @@ -0,0 +1,475 @@ + + + + + + GitHub Copilot Proxy - Setup & Integration + + + + + +
+ Checking authentication status... +
+ + +
+

⚡ Quick Start

+

Your proxy is running at: http://localhost:3000

+ +

Available Endpoints

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
EndpointDescriptionUse Case
/v1/modelsList available modelsModel discovery
/v1/chat/completionsChat completions APICursor chat, Continue, LangChain
/v1/completionsLegacy completions APICursor tab completions
/v1/responsesOpenAI Responses APIOpenAI Agents SDK
+ + +
+
+ + +
+

🖱️ Cursor IDE Recommended

+

Bypass Cursor's 500 requests/month limit by using your GitHub Copilot subscription.

+ +

1 Open Cursor Settings (Ctrl+, or Cmd+,)

+

2 Navigate to ModelsOpenAI API Key

+

3 Enter any dummy API key (e.g., sk-dummy)

+

4 Set Override OpenAI Base URL to:

+
+ http://localhost:3000/v1 + +
+

5 Use models like gpt-4o, claude-sonnet-4, or gemini-2.5-pro

+
+ + +
+

🦀 OpenClaw Gateway Recommended

+

Use with OpenClaw for additional features and model routing.

+ +

1 Install OpenClaw:

+
+ npm install -g openclaw +
+ +

2 Run with this proxy as the backend:

+
+ openclaw gateway --upstream http://localhost:3000 --port 18789 +
+ +

3 Configure Cursor to use OpenClaw gateway at http://localhost:18789/v1

+
+ + +
+

▶️ Continue Extension

+

Use with Continue VS Code extension.

+ +

Add to your ~/.continue/config.json:

+
+{ + "models": [ + { + "title": "GitHub Copilot (via Proxy)", + "provider": "openai", + "model": "gpt-4o", + "apiBase": "http://localhost:3000/v1", + "apiKey": "dummy" + } + ] +} + +
+
+ + +
+

🤖 Aider

+

Use with Aider AI pair programming.

+ +
+# Set environment variables +export OPENAI_API_BASE=http://localhost:3000/v1 +export OPENAI_API_KEY=dummy + +# Run Aider +aider --model gpt-4o +
+
+ + +
+

🦜 LangChain & 🦙 LlamaIndex Advanced

+ +

LangChain (Python):

+
+from langchain_openai import ChatOpenAI + +llm = ChatOpenAI( + model="gpt-4o", + base_url="http://localhost:3000/v1", + api_key="dummy" +) +
+ +

LlamaIndex (Python):

+
+from llama_index.llms.openai import OpenAI + +llm = OpenAI( + model="gpt-4o", + api_base="http://localhost:3000/v1", + api_key="dummy" +) +
+
+ + +
+

🤖 Available Models

+

These models are available through the proxy:

+ +

Claude (Anthropic)

+ claude-opus-4.5 claude-sonnet-4.5 claude-sonnet-4 claude-haiku-4.5 + +

GPT (OpenAI/Azure)

+ gpt-4o gpt-4o-mini gpt-4.1 gpt-4 gpt-3.5-turbo + +

Gemini (Google)

+ gemini-2.5-pro gemini-3-pro-preview gemini-3-flash-preview + +

Reasoning Models

+ o1-preview o1-mini o3-mini +
+ + + + diff --git a/src/public/usage.html b/src/public/usage.html index 69c30b5..d9d2a86 100644 --- a/src/public/usage.html +++ b/src/public/usage.html @@ -127,6 +127,7 @@

GitHub Copilot Proxy - Usage Dashboard

From 00ec776199567ef80388ddc971e3d605e55492d8 Mon Sep 17 00:00:00 2001 From: Youssef Adel Date: Tue, 3 Feb 2026 00:26:38 +0200 Subject: [PATCH 06/16] feat: add OpenClaw Gateway Daemon and WhatsApp login scripts; update package.json for new scripts --- openclaw-gateway-daemon.ps1 | 48 +++++++++++++++++++++++++++++++++++++ openclaw-whatsapp-login.ps1 | 29 ++++++++++++++++++++++ package.json | 5 ++-- 3 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 openclaw-gateway-daemon.ps1 create mode 100644 openclaw-whatsapp-login.ps1 diff --git a/openclaw-gateway-daemon.ps1 b/openclaw-gateway-daemon.ps1 new file mode 100644 index 0000000..8bcdbd2 --- /dev/null +++ b/openclaw-gateway-daemon.ps1 @@ -0,0 +1,48 @@ +# OpenClaw Gateway Daemon +# Runs the gateway infinitely, auto-respawns on crash + +$ErrorActionPreference = "Continue" + +$port = 18789 +$restartDelay = 3 # seconds to wait before respawning + +Write-Host "========================================" -ForegroundColor Cyan +Write-Host " OpenClaw Gateway Daemon" -ForegroundColor Cyan +Write-Host " Port: $port" -ForegroundColor Cyan +Write-Host " Press Ctrl+C to stop" -ForegroundColor Yellow +Write-Host "========================================" -ForegroundColor Cyan + +$crashCount = 0 + +while ($true) { + $startTime = Get-Date + $crashCount++ + + Write-Host "" + Write-Host "[$(Get-Date -Format 'HH:mm:ss')] Starting gateway (attempt #$crashCount)..." -ForegroundColor Green + + try { + openclaw gateway --port $port --verbose + $exitCode = $LASTEXITCODE + } + catch { + $exitCode = 1 + Write-Host "[$(Get-Date -Format 'HH:mm:ss')] Exception: $_" -ForegroundColor Red + } + + $runtime = (Get-Date) - $startTime + + Write-Host "" + Write-Host "[$(Get-Date -Format 'HH:mm:ss')] Gateway exited with code $exitCode after $($runtime.ToString('hh\:mm\:ss'))" -ForegroundColor Yellow + + # Reset crash count if it ran for more than 1 minute (stable) + if ($runtime.TotalMinutes -gt 1) { + $crashCount = 0 + } + + # Exponential backoff for rapid crashes (max 30 seconds) + $delay = [Math]::Min($restartDelay * [Math]::Pow(2, [Math]::Min($crashCount - 1, 3)), 30) + + Write-Host "[$(Get-Date -Format 'HH:mm:ss')] Respawning in $delay seconds..." -ForegroundColor Cyan + Start-Sleep -Seconds $delay +} diff --git a/openclaw-whatsapp-login.ps1 b/openclaw-whatsapp-login.ps1 new file mode 100644 index 0000000..c78e1c4 --- /dev/null +++ b/openclaw-whatsapp-login.ps1 @@ -0,0 +1,29 @@ +# OpenClaw WhatsApp Channel Login Script +# This script logs into the WhatsApp channel with the default account + +Write-Host "========================================" -ForegroundColor Cyan +Write-Host " OpenClaw WhatsApp Channel Login" -ForegroundColor Cyan +Write-Host "========================================" -ForegroundColor Cyan +Write-Host "" + +try { + Write-Host "Initiating WhatsApp channel login..." -ForegroundColor Yellow + + # Run the openclaw channels login command + openclaw channels login --channel whatsapp --account default + + if ($LASTEXITCODE -eq 0) { + Write-Host "" + Write-Host "WhatsApp channel login completed successfully!" -ForegroundColor Green + } else { + Write-Host "" + Write-Host "WhatsApp channel login failed with exit code: $LASTEXITCODE" -ForegroundColor Red + exit $LASTEXITCODE + } +} +catch { + Write-Host "" + Write-Host "Error occurred during WhatsApp channel login:" -ForegroundColor Red + Write-Host $_.Exception.Message -ForegroundColor Red + exit 1 +} diff --git a/package.json b/package.json index 726a101..e465fa7 100644 --- a/package.json +++ b/package.json @@ -8,10 +8,11 @@ "copy-public": "node -e \"require('fs').cpSync('src/public', 'dist/public', {recursive: true})\"", "start": "node dist/index.js", "start:verbose": "cross-env LOG_LEVEL=debug node dist/index.js", - "start:openclaw": "npm run build && concurrently --names \"proxy,gateway\" --prefix-colors \"cyan,magenta\" \"npm run start:verbose\" \"openclaw gateway --port 18789 --verbose\"", + "start:openclaw": "npm run build && concurrently --names \"proxy,gateway\" --prefix-colors \"cyan,magenta\" \"npm run start:verbose\" \"powershell -ExecutionPolicy Bypass -File \".\\openclaw-gateway-daemon.ps1\"\"", "dev": "ts-node src/index.ts", "lint": "eslint src/**/*.ts", - "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js" + "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js", + "whatsapp:login": "powershell -ExecutionPolicy Bypass -File \".\\openclaw-whatsapp-login.ps1\"" }, "repository": { "type": "git", From fd7fb868065f202e4507f416147d5ca0f22e1676 Mon Sep 17 00:00:00 2001 From: Youssef Adel Date: Tue, 3 Feb 2026 00:43:09 +0200 Subject: [PATCH 07/16] feat: enhance tool calling capabilities and update OpenAI types for improved function handling --- src/routes/openai.ts | 81 +++++++- src/services/copilot-service.ts | 330 ++++++++++++++++---------------- src/types/openai.ts | 71 ++++++- 3 files changed, 300 insertions(+), 182 deletions(-) diff --git a/src/routes/openai.ts b/src/routes/openai.ts index 84fd78e..19ab410 100644 --- a/src/routes/openai.ts +++ b/src/routes/openai.ts @@ -1,4 +1,4 @@ -import express from 'express'; +import express from 'express'; import fetch from 'node-fetch'; import { createParser, type EventSourceMessage } from 'eventsource-parser'; import { v4 as uuidv4 } from 'uuid'; @@ -13,7 +13,8 @@ import { detectLanguageFromMessages, makeCompletionRequest, convertResponsesInputToMessages, - mapToCopilotModel + mapToCopilotModel, + convertToolsForCopilot } from '../services/copilot-service.js'; import { OpenAICompletionRequest, @@ -557,7 +558,10 @@ async function handleStreamingCompletion( temperature: temperature || 0.7, top_p: top_p || 1, n: n || 1, - stream: true + stream: true, + ...(request.tools && request.tools.length > 0 && { tools: request.tools }), + ...(request.tool_choice && { tool_choice: request.tool_choice }), + ...(request.parallel_tool_calls !== undefined && { parallel_tool_calls: request.parallel_tool_calls }) }), }); @@ -600,7 +604,8 @@ async function handleStreamingCompletion( { index: 0, delta: { - content: content + content: content, + ...(parsed.choices?.[0]?.delta?.tool_calls && { tool_calls: parsed.choices[0].delta.tool_calls }) }, finish_reason: parsed.choices?.[0]?.finish_reason || null } @@ -789,6 +794,21 @@ async function handleStreamingResponses( let firstChunk = true; let completionSent = false; + // Convert tools to Copilot-compatible format + const convertedTools = convertToolsForCopilot(request.tools); + + // Debug log the request being made + const mappedModel = mapToCopilotModel(model || 'gpt-4o'); + logger.debug('Responses API streaming request details', { + chatUrl, + requestedModel: model, + mappedModel, + messageCount: messages.length, + hasTools: !!convertedTools, + originalToolCount: request.tools?.length || 0, + convertedToolCount: convertedTools?.length || 0 + }); + // Send initial response.created event res.write(`event: response.created\ndata: ${JSON.stringify({ type: 'response.created', @@ -824,16 +844,29 @@ async function handleStreamingResponses( temperature: request.temperature || 0.7, top_p: request.top_p || 1, n: 1, - stream: true + stream: true, + ...(convertedTools && convertedTools.length > 0 && { tools: convertedTools }), + ...(request.tool_choice && { tool_choice: request.tool_choice }), + ...(request.parallel_tool_calls !== undefined && { parallel_tool_calls: request.parallel_tool_calls }) }), }); if (!response.ok) { - logger.error('Stream connection error', { + // Read the error response body to understand the actual error + let errorBody = ''; + try { + errorBody = await response.text(); + } catch (e) { + errorBody = 'Unable to read error body'; + } + logger.error('Stream connection error (Responses API)', { status: response.status, - statusText: response.statusText + statusText: response.statusText, + errorBody, + requestModel: model, + mappedModel: mapToCopilotModel(model || 'gpt-4o') }); - throw new Error(`Stream connection error: ${response.status} ${response.statusText}`); + throw new Error(`Stream connection error: ${response.status} ${response.statusText} - ${errorBody}`); } if (!response.body) { @@ -916,6 +949,35 @@ async function handleStreamingResponses( // Chat completions uses delta.content, not text const text = parsed.choices?.[0]?.delta?.content || ''; + // Handle tool_calls from the model + const toolCalls = parsed.choices?.[0]?.delta?.tool_calls; + if (toolCalls && toolCalls.length > 0) { + for (const toolCall of toolCalls) { + if (toolCall.id && toolCall.function?.name) { + // Send function_call output item + const functionCallId = `call_${uuidv4()}`; + res.write(`event: response.output_item.added\ndata: ${JSON.stringify({ + type: 'response.output_item.added', + item: { + type: 'function_call', + id: functionCallId, + call_id: toolCall.id, + name: toolCall.function.name, + arguments: toolCall.function.arguments || '', + status: 'in_progress' + }, + output_index: 0 + })}\n\n`); + } else if (toolCall.function?.arguments) { + // Stream function arguments delta + res.write(`event: response.function_call_arguments.delta\ndata: ${JSON.stringify({ + type: 'response.function_call_arguments.delta', + delta: toolCall.function.arguments + })}\n\n`); + } + } + } + if (text) { // On first chunk, send output_item.added and content_part.added if (firstChunk) { @@ -1078,3 +1140,6 @@ async function handleStreamingResponses( } } } + + + diff --git a/src/services/copilot-service.ts b/src/services/copilot-service.ts index 6a8222c..7e5e33e 100644 --- a/src/services/copilot-service.ts +++ b/src/services/copilot-service.ts @@ -1,23 +1,19 @@ -import fetch from 'node-fetch'; +import fetch from 'node-fetch'; import { v4 as uuidv4 } from 'uuid'; import { config } from '../config/index.js'; -import { - OpenAIMessage, +import { + OpenAIMessage, OpenAICompletionRequest, ResponsesInput, - ResponsesContentPart + ResponsesContentPart, + Tool, + ToolCall } from '../types/openai.js'; import { CopilotCompletionResponse } from '../types/github.js'; import { getMachineId } from '../utils/machine-id.js'; import { logger } from '../utils/logger.js'; -/** - * Model name mapping from client-requested names to Copilot API model names - * Based on actual Copilot API /models endpoint response - * Copilot uses "claude-{tier}-{version}" format (e.g., claude-opus-4.5) - */ const MODEL_MAPPING: Record = { - // Claude models - Copilot uses "claude-{tier}-{version}" format 'claude-4.5-opus': 'claude-opus-4.5', 'claude-opus-4.5': 'claude-opus-4.5', 'claude-4-opus': 'claude-opus-4.5', @@ -31,8 +27,6 @@ const MODEL_MAPPING: Record = { 'claude-3.5-sonnet': 'claude-sonnet-4', 'claude-3-opus': 'claude-opus-4.5', 'claude-3-sonnet': 'claude-sonnet-4', - - // GPT models 'gpt-4o': 'gpt-4o', 'gpt-4o-mini': 'gpt-4o-mini', 'gpt-4.1': 'gpt-4.1', @@ -42,147 +36,111 @@ const MODEL_MAPPING: Record = { 'gpt-5.2': 'gpt-5.2', 'gpt-5-codex': 'gpt-5-codex', 'gpt-5.1-codex-max': 'gpt-5.1-codex-max', - - // Gemini models 'gemini-2.5-pro': 'gemini-2.5-pro', 'gemini-3-pro': 'gemini-3-pro-preview', 'gemini-3-pro-preview': 'gemini-3-pro-preview', 'gemini-3-flash': 'gemini-3-flash-preview', 'gemini-3-flash-preview': 'gemini-3-flash-preview', - - // o1/o3 reasoning models 'o1': 'o1-preview', 'o1-preview': 'o1-preview', 'o1-mini': 'o1-mini', 'o3-mini': 'o3-mini', - - // Default fallback 'default': 'gpt-4o' }; -/** - * Maps a client-requested model name to a valid Copilot API model name - * - * @param requestedModel The model name requested by the client - * @returns A valid Copilot API model name - */ export function mapToCopilotModel(requestedModel: string): string { const mapped = MODEL_MAPPING[requestedModel.toLowerCase()]; if (mapped) { logger.debug('Model mapped', { from: requestedModel, to: mapped }); return mapped; } - - // If no mapping found, try to use the model as-is or default to gpt-4o - logger.warn('Unknown model requested, using default', { requestedModel, default: 'gpt-4o' }); - return 'gpt-4o'; + logger.warn('Unknown model requested, using as-is', { requestedModel }); + return requestedModel; } -/** - * Converts OpenAI messages format to GitHub Copilot prompt format - * - * @param messages Array of OpenAI messages - * @returns Formatted prompt string for Copilot - */ -export function convertMessagesToCopilotPrompt(messages: OpenAIMessage[]): string { - if (!messages || !Array.isArray(messages) || messages.length === 0) { - return ''; - } +// Convert tools from various formats (Responses API, custom, etc.) to Copilot-compatible format +export function convertToolsForCopilot(tools?: any[]): Tool[] | undefined { + if (!tools || tools.length === 0) return undefined; - let prompt = ''; + const convertedTools: Tool[] = []; - // Process messages in order to preserve conversation flow - for (const message of messages) { - if (!message.role || !message.content) continue; + for (const tool of tools) { + // Skip invalid tools + if (!tool) continue; - switch (message.role) { - case 'system': - prompt += message.content + '\n\n'; - break; - case 'user': - prompt += 'User: ' + message.content + '\n\n'; - break; - case 'assistant': - prompt += 'Assistant: ' + message.content + '\n\n'; - break; + // Handle standard function type + if (tool.type === 'function' && tool.function) { + // Ensure the function has a valid name + if (tool.function.name && typeof tool.function.name === 'string' && tool.function.name.length > 0) { + convertedTools.push({ + type: 'function' as const, + function: { + name: tool.function.name, + description: tool.function.description || '', + parameters: tool.function.parameters || { type: 'object', properties: {} }, + strict: tool.function.strict + } + }); + } else { + logger.warn('Skipping tool with invalid function name', { tool }); + } + } + // Handle custom type (some APIs use this) + else if (tool.type === 'custom' && tool.custom) { + if (tool.custom.name && typeof tool.custom.name === 'string' && tool.custom.name.length > 0) { + convertedTools.push({ + type: 'function' as const, + function: { + name: tool.custom.name, + description: tool.custom.description || '', + parameters: tool.custom.parameters || { type: 'object', properties: {} } + } + }); + } else { + logger.warn('Skipping custom tool with invalid name', { tool }); + } + } + // Handle direct function definition (legacy format) + else if (tool.name && typeof tool.name === 'string') { + convertedTools.push({ + type: 'function' as const, + function: { + name: tool.name, + description: tool.description || '', + parameters: tool.parameters || { type: 'object', properties: {} } + } + }); + } + // Handle web_search_preview and other special types - skip these + else if (tool.type === 'web_search_preview' || tool.type === 'code_interpreter' || tool.type === 'file_search') { + logger.debug('Skipping unsupported tool type', { toolType: tool.type }); + } + else { + logger.warn('Skipping tool with unrecognized format', { tool }); } } - // Ensure it ends with a user message to prompt a response - const lastMessage = messages[messages.length - 1]; - const needsAssistantPrompt = lastMessage.role === 'user'; - - return prompt + (needsAssistantPrompt ? 'Assistant: ' : ''); -} - -/** - * Detects programming language from the message content - * - * @param messages Array of OpenAI messages - * @returns Detected language or default to javascript - */ -export function detectLanguageFromMessages(messages: OpenAIMessage[]): string { - if (!messages || !Array.isArray(messages) || messages.length === 0) { - return 'javascript'; - } - - const lastUserMessage = [...messages].reverse().find(m => m.role === 'user'); - if (!lastUserMessage || !lastUserMessage.content) { - return 'javascript'; - } - - const content = lastUserMessage.content; - - // Check for code blocks with language specifications - const codeBlockMatch = content.match(/```(\w+)/); - if (codeBlockMatch && codeBlockMatch[1]) { - return codeBlockMatch[1].toLowerCase(); + if (convertedTools.length === 0) { + return undefined; } - // Check for file extensions in the message (followed by space, quote, or end of word boundary) - const fileExtensionMatch = content.match(/\.([a-zA-Z0-9]+)(?:\s|"|'|$|\?)/); - if (fileExtensionMatch && fileExtensionMatch[1]) { - const ext = fileExtensionMatch[1].toLowerCase(); - const extToLang: Record = { - 'js': 'javascript', - 'ts': 'typescript', - 'py': 'python', - 'java': 'java', - 'c': 'c', - 'cpp': 'cpp', - 'cs': 'csharp', - 'go': 'go', - 'rb': 'ruby', - 'php': 'php', - 'html': 'html', - 'css': 'css', - 'json': 'json', - 'md': 'markdown' - }; - return extToLang[ext] || 'javascript'; - } + logger.debug('Tools converted for Copilot', { + originalCount: tools.length, + convertedCount: convertedTools.length, + toolNames: convertedTools.map(t => t.function.name) + }); - return 'javascript'; + return convertedTools; } -/** - * Makes a non-streaming request to GitHub Copilot Chat API - * - * @param request OpenAI-format completion request - * @param copilotToken Copilot authentication token - * @returns Promise with the completion response - */ export async function makeCompletionRequest( request: OpenAICompletionRequest, copilotToken: string ): Promise { - const { model, messages, temperature, max_tokens, top_p, n } = request; - - // Get machine ID for request + const { model, messages, temperature, max_tokens, top_p, n, tools, tool_choice, parallel_tool_calls } = request; const machineId = getMachineId(); - - // Use chat completions endpoint for chat requests const chatUrl = config.github.copilot.apiEndpoints.GITHUB_COPILOT_CHAT; + const headers = { 'Content-Type': 'application/json', 'Authorization': `Bearer ${copilotToken}`, @@ -195,12 +153,10 @@ export async function makeCompletionRequest( 'Copilot-Integration-Id': 'vscode-chat', 'Openai-Intent': 'conversation-agent' }; - - // Map the requested model to a valid Copilot model + const copilotModel = mapToCopilotModel(model || 'gpt-4o'); - - // Use OpenAI chat completions format - const body = { + + const body: Record = { model: copilotModel, messages, max_tokens: max_tokens || 4096, @@ -209,26 +165,44 @@ export async function makeCompletionRequest( n: n || 1, stream: false }; - + + if (tools && tools.length > 0) { + body.tools = convertToolsForCopilot(tools); + logger.debug('Including tools in request', { toolCount: tools.length, toolNames: tools.map(t => t.function.name) }); + } + + if (tool_choice) { + body.tool_choice = tool_choice; + } + + if (parallel_tool_calls !== undefined) { + body.parallel_tool_calls = parallel_tool_calls; + } + try { - logger.debug('Making chat completion request to Copilot', { chatUrl, model: copilotModel, requestedModel: model }); + logger.debug('Making chat completion request to Copilot', { + chatUrl, + model: copilotModel, + hasTools: !!tools, + toolChoice: tool_choice + }); const response = await fetch(chatUrl, { method: 'POST', headers, body: JSON.stringify(body) }); - + if (!response.ok) { const errorText = await response.text(); - logger.error('Copilot API error', { - status: response.status, + logger.error('Copilot API error', { + status: response.status, statusText: response.statusText, error: errorText }); throw new Error(`Copilot API error: ${response.status} ${response.statusText}`); } - + const data = await response.json() as CopilotCompletionResponse; return data; } catch (error) { @@ -237,51 +211,40 @@ export async function makeCompletionRequest( } } -/** - * Converts OpenAI Responses API input to standard OpenAI messages format - * - * @param input Responses API input (string or array of ResponsesInput) - * @param instructions Optional system instructions - * @returns Array of OpenAI messages - */ export function convertResponsesInputToMessages( input: string | ResponsesInput[], instructions?: string ): OpenAIMessage[] { const messages: OpenAIMessage[] = []; - - // Add system instructions if provided + if (instructions) { - messages.push({ - role: 'system', - content: instructions - }); + messages.push({ role: 'system', content: instructions }); } - - // Handle simple string input + if (typeof input === 'string') { - messages.push({ - role: 'user', - content: input - }); + messages.push({ role: 'user', content: input }); return messages; } - - // Handle array of ResponsesInput or OpenAI-style messages + if (Array.isArray(input)) { for (const item of input) { - let content: string; - let itemRole: string; - - // Check if this is Responses API format (has type: 'message') or OpenAI-style (has role directly) + if (item.type === 'function_call_output') { + messages.push({ + role: 'tool', + content: item.output || '', + tool_call_id: item.call_id + }); + continue; + } + if (item.type === 'message' || (item.role && !item.type)) { - // Handle content - can be string or array of content parts + let content: string; + if (typeof item.content === 'string') { content = item.content; } else if (Array.isArray(item.content)) { - // Extract text from content parts content = item.content - .filter((part): part is ResponsesContentPart => + .filter((part): part is ResponsesContentPart => part.type === 'input_text' || part.type === 'output_text' || part.type === 'text' ) .map(part => part.text) @@ -289,20 +252,59 @@ export function convertResponsesInputToMessages( } else { content = ''; } - - // Map Responses API roles to OpenAI message roles - itemRole = item.role === 'user' ? 'user' : - item.role === 'assistant' ? 'assistant' : - item.role === 'system' ? 'system' : - item.role === 'developer' ? 'system' : 'user'; - + + const itemRole = item.role === 'user' ? 'user' : + item.role === 'assistant' ? 'assistant' : + item.role === 'system' ? 'system' : + item.role === 'developer' ? 'system' : 'user'; + messages.push({ - role: itemRole as 'system' | 'user' | 'assistant' | 'function', + role: itemRole as 'system' | 'user' | 'assistant' | 'function' | 'tool', content }); } } } - + return messages; } + +export function convertMessagesToCopilotPrompt(messages: OpenAIMessage[]): string { + if (!messages || !Array.isArray(messages) || messages.length === 0) return ''; + + let prompt = ''; + for (const message of messages) { + if (!message.role || !message.content) continue; + switch (message.role) { + case 'system': prompt += message.content + '\n\n'; break; + case 'user': prompt += 'User: ' + message.content + '\n\n'; break; + case 'assistant': prompt += 'Assistant: ' + message.content + '\n\n'; break; + } + } + + const lastMessage = messages[messages.length - 1]; + const needsAssistantPrompt = lastMessage.role === 'user'; + return prompt + (needsAssistantPrompt ? 'Assistant: ' : ''); +} + +export function detectLanguageFromMessages(messages: OpenAIMessage[]): string { + if (!messages || !Array.isArray(messages) || messages.length === 0) return 'javascript'; + const lastUserMessage = [...messages].reverse().find(m => m.role === 'user'); + if (!lastUserMessage || !lastUserMessage.content) return 'javascript'; + + const content = lastUserMessage.content; + const codeBlockMatch = content.match(/```(\w+)/); + if (codeBlockMatch && codeBlockMatch[1]) return codeBlockMatch[1].toLowerCase(); + + const fileExtensionMatch = content.match(/\.([a-zA-Z0-9]+)(?:\s|"|'|$|\?)/); + if (fileExtensionMatch && fileExtensionMatch[1]) { + const ext = fileExtensionMatch[1].toLowerCase(); + const extToLang: Record = { + 'js': 'javascript', 'ts': 'typescript', 'py': 'python', 'java': 'java', + 'c': 'c', 'cpp': 'cpp', 'cs': 'csharp', 'go': 'go', 'rb': 'ruby', + 'php': 'php', 'html': 'html', 'css': 'css', 'json': 'json', 'md': 'markdown' + }; + return extToLang[ext] || 'javascript'; + } + return 'javascript'; +} diff --git a/src/types/openai.ts b/src/types/openai.ts index 79c49d9..040abba 100644 --- a/src/types/openai.ts +++ b/src/types/openai.ts @@ -1,11 +1,40 @@ +// ============================================ +// UPDATED TYPES - E:\work\openClaw\github-copilot-proxy\src\types\openai.ts +// ============================================ + +// Tool definition for function calling +export interface ToolFunction { + name: string; + description?: string; + parameters?: Record; + strict?: boolean; +} + +export interface Tool { + type: 'function'; + function: ToolFunction; +} + +// Tool call in assistant message +export interface ToolCall { + id: string; + type: 'function'; + function: { + name: string; + arguments: string; + }; +} + export interface OpenAIMessage { - role: 'system' | 'user' | 'assistant' | 'function'; + role: 'system' | 'user' | 'assistant' | 'function' | 'tool'; content: string | null; name?: string; function_call?: { name: string; arguments: string; }; + tool_calls?: ToolCall[]; + tool_call_id?: string; } export interface OpenAICompletionRequest { @@ -21,14 +50,19 @@ export interface OpenAICompletionRequest { frequency_penalty?: number; logit_bias?: Record; user?: string; + // Legacy function calling functions?: any[]; function_call?: 'auto' | 'none' | { name: string }; + // Modern tool calling + tools?: Tool[]; + tool_choice?: 'auto' | 'none' | 'required' | { type: 'function'; function: { name: string } }; + parallel_tool_calls?: boolean; } export interface OpenAICompletionChoice { index: number; message?: OpenAIMessage; - delta?: Partial; + delta?: Partial & { tool_calls?: Partial[] }; finish_reason: string | null; } @@ -99,9 +133,11 @@ export interface LegacyCompletion { // OpenAI Responses API Types export interface ResponsesInput { - type?: 'message'; // Optional - OpenAI-style messages may not have this - role: 'user' | 'assistant' | 'system' | 'developer'; - content: string | ResponsesContentPart[]; + type?: 'message' | 'function_call_output'; + role?: 'user' | 'assistant' | 'system' | 'developer'; + content?: string | ResponsesContentPart[]; + call_id?: string; + output?: string; } export interface ResponsesContentPart { @@ -109,6 +145,16 @@ export interface ResponsesContentPart { text: string; } +// Responses API tool output +export interface ResponsesToolOutput { + type: 'function_call'; + id: string; + call_id: string; + name: string; + arguments: string; + status?: 'completed' | 'in_progress'; +} + export interface ResponsesRequest { model: string; input: string | ResponsesInput[]; @@ -117,19 +163,24 @@ export interface ResponsesRequest { max_output_tokens?: number; top_p?: number; stream?: boolean; - tools?: any[]; - tool_choice?: string | { type: string; name: string }; + tools?: Tool[]; + tool_choice?: 'auto' | 'none' | 'required' | { type: 'function'; name: string }; + parallel_tool_calls?: boolean; metadata?: Record; store?: boolean; previous_response_id?: string; } export interface ResponsesOutput { - type: 'message'; + type: 'message' | 'function_call'; id: string; status: 'completed' | 'in_progress' | 'incomplete'; - role: 'assistant'; - content: ResponsesContentPart[]; + role?: 'assistant'; + content?: ResponsesContentPart[]; + // For function_call type + call_id?: string; + name?: string; + arguments?: string; } export interface ResponsesResponse { From fb48ba906b99aae9550380142bfd9278f68fe096 Mon Sep 17 00:00:00 2001 From: Youssef Adel Date: Tue, 3 Feb 2026 00:49:42 +0200 Subject: [PATCH 08/16] feat: implement fixToolMessagePairing function to ensure correct tool message pairing and enhance logging for invalid tools --- src/routes/openai.ts | 19 +++++++++--- src/services/copilot-service.ts | 55 ++++++++++++++++++++++++++++++--- 2 files changed, 64 insertions(+), 10 deletions(-) diff --git a/src/routes/openai.ts b/src/routes/openai.ts index 19ab410..118ff86 100644 --- a/src/routes/openai.ts +++ b/src/routes/openai.ts @@ -14,7 +14,8 @@ import { makeCompletionRequest, convertResponsesInputToMessages, mapToCopilotModel, - convertToolsForCopilot + convertToolsForCopilot, + fixToolMessagePairing } from '../services/copilot-service.js'; import { OpenAICompletionRequest, @@ -514,7 +515,8 @@ async function handleStreamingCompletion( ) { try { const request = req.body as OpenAICompletionRequest; - const { messages, temperature, max_tokens, top_p, n, model = 'gpt-4' } = request; + const { messages: rawMessages, temperature, max_tokens, top_p, n, model = 'gpt-4' } = request; + const messages = fixToolMessagePairing(rawMessages); const copilotToken = getCopilotToken(); if (!copilotToken || !copilotToken.token) { @@ -694,7 +696,8 @@ openaiRoutes.post('/responses', requireAuth, async (req, res, next) => { } // Convert Responses API input to OpenAI messages format - const messages = convertResponsesInputToMessages(input, instructions); + const rawMessages = convertResponsesInputToMessages(input, instructions); + const messages = fixToolMessagePairing(rawMessages); // Handle streaming response if (stream) { @@ -797,13 +800,17 @@ async function handleStreamingResponses( // Convert tools to Copilot-compatible format const convertedTools = convertToolsForCopilot(request.tools); + // Fix tool message pairing to avoid orphaned tool_results + const fixedMessages = fixToolMessagePairing(messages); + // Debug log the request being made const mappedModel = mapToCopilotModel(model || 'gpt-4o'); logger.debug('Responses API streaming request details', { chatUrl, requestedModel: model, mappedModel, - messageCount: messages.length, + originalMessageCount: messages.length, + fixedMessageCount: fixedMessages.length, hasTools: !!convertedTools, originalToolCount: request.tools?.length || 0, convertedToolCount: convertedTools?.length || 0 @@ -839,7 +846,7 @@ async function handleStreamingResponses( }, body: JSON.stringify({ model: mapToCopilotModel(model || 'gpt-4o'), - messages, + messages: fixedMessages, max_tokens: request.max_output_tokens || 4096, temperature: request.temperature || 0.7, top_p: request.top_p || 1, @@ -1143,3 +1150,5 @@ async function handleStreamingResponses( + + diff --git a/src/services/copilot-service.ts b/src/services/copilot-service.ts index 7e5e33e..bd21b76 100644 --- a/src/services/copilot-service.ts +++ b/src/services/copilot-service.ts @@ -82,7 +82,7 @@ export function convertToolsForCopilot(tools?: any[]): Tool[] | undefined { } }); } else { - logger.warn('Skipping tool with invalid function name', { tool }); + logger.warn('Skipping tool with invalid function name', { tool: JSON.stringify(tool).substring(0, 200) }); } } // Handle custom type (some APIs use this) @@ -97,7 +97,7 @@ export function convertToolsForCopilot(tools?: any[]): Tool[] | undefined { } }); } else { - logger.warn('Skipping custom tool with invalid name', { tool }); + logger.warn('Skipping custom tool with invalid name', { tool: JSON.stringify(tool).substring(0, 200) }); } } // Handle direct function definition (legacy format) @@ -116,7 +116,7 @@ export function convertToolsForCopilot(tools?: any[]): Tool[] | undefined { logger.debug('Skipping unsupported tool type', { toolType: tool.type }); } else { - logger.warn('Skipping tool with unrecognized format', { tool }); + logger.warn('Skipping tool with unrecognized format', { tool: JSON.stringify(tool).substring(0, 200) }); } } @@ -133,11 +133,55 @@ export function convertToolsForCopilot(tools?: any[]): Tool[] | undefined { return convertedTools; } +/** + * Validates and fixes message history to ensure tool_use/tool_result pairing is correct. + * Claude requires that each tool_result references a tool_use from the immediately preceding assistant message. + */ +export function fixToolMessagePairing(messages: OpenAIMessage[]): OpenAIMessage[] { + const fixed: OpenAIMessage[] = []; + const toolUseIds = new Set(); + + for (let i = 0; i < messages.length; i++) { + const msg = messages[i]; + + // Track tool_use IDs from assistant messages + if (msg.role === 'assistant' && msg.tool_calls) { + for (const tc of msg.tool_calls) { + if (tc.id) toolUseIds.add(tc.id); + } + } + + // For tool messages, check if the tool_call_id exists + if (msg.role === 'tool' && msg.tool_call_id) { + if (!toolUseIds.has(msg.tool_call_id)) { + // This tool_result references a tool_use that doesn't exist + // Convert it to a regular user message with context + logger.warn('Orphaned tool_result found, converting to user message', { + tool_call_id: msg.tool_call_id + }); + fixed.push({ + role: 'user', + content: `[Previous tool result: ${msg.content}]` + }); + continue; + } + } + + fixed.push(msg); + } + + return fixed; +} + export async function makeCompletionRequest( request: OpenAICompletionRequest, copilotToken: string ): Promise { - const { model, messages, temperature, max_tokens, top_p, n, tools, tool_choice, parallel_tool_calls } = request; + const { model, temperature, max_tokens, top_p, n, tools, tool_choice, parallel_tool_calls } = request; + + // Fix tool message pairing before sending + const messages = fixToolMessagePairing(request.messages); + const machineId = getMachineId(); const chatUrl = config.github.copilot.apiEndpoints.GITHUB_COPILOT_CHAT; @@ -184,7 +228,8 @@ export async function makeCompletionRequest( chatUrl, model: copilotModel, hasTools: !!tools, - toolChoice: tool_choice + toolChoice: tool_choice, + messageCount: messages.length }); const response = await fetch(chatUrl, { From a10cd15f2d55248c11dd98ad0c9dc20903e649b0 Mon Sep 17 00:00:00 2001 From: Youssef Adel Date: Tue, 3 Feb 2026 01:23:58 +0200 Subject: [PATCH 09/16] feat: enhance logging for streaming responses and track tool calls for improved monitoring --- src/routes/openai.ts | 41 +++++++++++++++++++++++++++++++---- src/services/usage-service.ts | 3 ++- 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/src/routes/openai.ts b/src/routes/openai.ts index 118ff86..2517dae 100644 --- a/src/routes/openai.ts +++ b/src/routes/openai.ts @@ -796,6 +796,11 @@ async function handleStreamingResponses( let accumulatedText = ''; let firstChunk = true; let completionSent = false; + const startTime = Date.now(); + + // Track tool calls for logging + const toolCallsReceived: Array<{id: string, name: string, argumentsLength: number}> = []; + let totalChunks = 0; // Convert tools to Copilot-compatible format const convertedTools = convertToolsForCopilot(request.tools); @@ -961,6 +966,21 @@ async function handleStreamingResponses( if (toolCalls && toolCalls.length > 0) { for (const toolCall of toolCalls) { if (toolCall.id && toolCall.function?.name) { + // Log tool call received + logger.info('Tool call received', { + responseId, + toolId: toolCall.id, + toolName: toolCall.function.name, + model: mappedModel + }); + + // Track for final summary + toolCallsReceived.push({ + id: toolCall.id, + name: toolCall.function.name, + argumentsLength: (toolCall.function.arguments || '').length + }); + // Send function_call output item const functionCallId = `call_${uuidv4()}`; res.write(`event: response.output_item.added\ndata: ${JSON.stringify({ @@ -1027,9 +1047,8 @@ async function handleStreamingResponses( delta: text }; res.write(`event: response.output_text.delta\ndata: ${JSON.stringify(deltaEvent)}\n\n`); - logger.debug('Sent delta event', { text: text.substring(0, 50) }); - // Track tokens + // Track tokens (silently) const estimatedTokens = Math.ceil(text.length / 4); trackRequest(sessionId, estimatedTokens); } @@ -1046,12 +1065,26 @@ async function handleStreamingResponses( // Process the stream for Responses API const reader = response.body; reader.on('data', (chunk: Buffer) => { - logger.debug('Responses: Received chunk from Copilot', { length: chunk.length }); + totalChunks++; parser.feed(chunk.toString()); }); reader.on('end', () => { - logger.debug('Responses: Stream ended', { totalTextLength: accumulatedText.length }); + const duration = Date.now() - startTime; + const estimatedTokens = Math.ceil(accumulatedText.length / 4); + + // Comprehensive final response log + logger.info('Response stream completed', { + responseId, + model: mappedModel, + duration: `${duration}ms`, + textLength: accumulatedText.length, + estimatedTokens, + totalChunks, + toolCallCount: toolCallsReceived.length, + toolsCalled: toolCallsReceived.map(t => t.name), + preview: accumulatedText.substring(0, 100) + (accumulatedText.length > 100 ? '...' : '') + }); // Send completion events when stream ends (Copilot doesn't send [DONE]) if (accumulatedText.length > 0 && !completionSent) { diff --git a/src/services/usage-service.ts b/src/services/usage-service.ts index 4841ac9..6616eac 100644 --- a/src/services/usage-service.ts +++ b/src/services/usage-service.ts @@ -67,7 +67,8 @@ export function trackRequest(sessionId: string, tokenCount = 0): void { entry => entry.timestamp >= fiveMinutesAgo ); - logger.debug(`Tracked request for session ${sessionId.substring(0, 8)}...: +${tokenCount} tokens`); + // Only log significant token updates (avoid per-chunk logging noise) + // Logged at higher thresholds or when explicitly needed } /** From 01bf879a5df0c5c72dfb3b5cf50923979ef91e6e Mon Sep 17 00:00:00 2001 From: Youssef Adel Date: Tue, 3 Feb 2026 01:37:48 +0200 Subject: [PATCH 10/16] feat: enhance fixToolMessagePairing function to log summary of orphaned tool results --- src/services/copilot-service.ts | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/services/copilot-service.ts b/src/services/copilot-service.ts index bd21b76..b9e6448 100644 --- a/src/services/copilot-service.ts +++ b/src/services/copilot-service.ts @@ -140,6 +140,7 @@ export function convertToolsForCopilot(tools?: any[]): Tool[] | undefined { export function fixToolMessagePairing(messages: OpenAIMessage[]): OpenAIMessage[] { const fixed: OpenAIMessage[] = []; const toolUseIds = new Set(); + const orphanedToolResults: string[] = []; for (let i = 0; i < messages.length; i++) { const msg = messages[i]; @@ -156,12 +157,10 @@ export function fixToolMessagePairing(messages: OpenAIMessage[]): OpenAIMessage[ if (!toolUseIds.has(msg.tool_call_id)) { // This tool_result references a tool_use that doesn't exist // Convert it to a regular user message with context - logger.warn('Orphaned tool_result found, converting to user message', { - tool_call_id: msg.tool_call_id - }); + orphanedToolResults.push(msg.tool_call_id); fixed.push({ role: 'user', - content: `[Previous tool result: ${msg.content}]` + content: `[Previous tool result: ${typeof msg.content === 'string' ? msg.content.substring(0, 200) : msg.content}${typeof msg.content === 'string' && msg.content.length > 200 ? '...' : ''}]` }); continue; } @@ -170,6 +169,15 @@ export function fixToolMessagePairing(messages: OpenAIMessage[]): OpenAIMessage[ fixed.push(msg); } + // Log summary of orphaned tool results (not each one individually) + if (orphanedToolResults.length > 0) { + logger.debug('Fixed orphaned tool_results in message history', { + count: orphanedToolResults.length, + toolCallIds: orphanedToolResults.slice(0, 3).map(id => id.substring(0, 20) + '...'), + hasMore: orphanedToolResults.length > 3 + }); + } + return fixed; } From 95298c91cf785c7b85e512303f1eee5d58a38e5f Mon Sep 17 00:00:00 2001 From: Youssef Adel Date: Tue, 3 Feb 2026 17:03:52 +0200 Subject: [PATCH 11/16] feat: enhance OpenClaw Gateway Daemon with smart error detection and logging for WhatsApp and critical errors --- openclaw-gateway-daemon.ps1 | 199 +++++++++++++++++++++++++++++++++--- 1 file changed, 186 insertions(+), 13 deletions(-) diff --git a/openclaw-gateway-daemon.ps1 b/openclaw-gateway-daemon.ps1 index 8bcdbd2..0d6360a 100644 --- a/openclaw-gateway-daemon.ps1 +++ b/openclaw-gateway-daemon.ps1 @@ -1,48 +1,221 @@ # OpenClaw Gateway Daemon # Runs the gateway infinitely, auto-respawns on crash +# Smart error detection for WhatsApp, DNS, connection issues $ErrorActionPreference = "Continue" $port = 18789 $restartDelay = 3 # seconds to wait before respawning +$logFile = "openclaw-gateway-daemon.log" + +# Error patterns that trigger immediate restart +$criticalErrors = @( + "Web connection closed.*status 408", + "getaddrinfo ENOTFOUND", + "ENOTFOUND web\.whatsapp\.com", + "channel exited", + "connection lost", + "connection timeout", + "Request Time-out", + "WebSocket Error", + "Fatal error", + "cannot connect", + "ECONNREFUSED", + "ETIMEDOUT" +) + +# Error patterns that trigger WhatsApp login +$whatsappLoginErrors = @( + "WhatsApp.*auth", + "WhatsApp.*login", + "WhatsApp.*session", + "WhatsApp.*QR", + "device.*not.*registered", + "session.*expired", + "authentication.*failed" +) Write-Host "========================================" -ForegroundColor Cyan -Write-Host " OpenClaw Gateway Daemon" -ForegroundColor Cyan +Write-Host " OpenClaw Gateway Daemon (Smart)" -ForegroundColor Cyan Write-Host " Port: $port" -ForegroundColor Cyan +Write-Host " Log: $logFile" -ForegroundColor Cyan Write-Host " Press Ctrl+C to stop" -ForegroundColor Yellow Write-Host "========================================" -ForegroundColor Cyan +function Log { + param([string]$Message, [string]$Color = "White") + $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" + $logMessage = "[$timestamp] $Message" + Write-Host $logMessage -ForegroundColor $Color + Add-Content -Path $logFile -Value $logMessage +} + +function CheckForWhatsAppLogin { + param([string]$Output, [string]$ErrorOutput) + + $allOutput = "$Output`n$ErrorOutput" + + foreach ($pattern in $whatsappLoginErrors) { + if ($allOutput -match $pattern) { + return $true, $pattern + } + } + + return $false, "" +} + +function RunWhatsAppLogin { + Log "WhatsApp login required - running login script..." "Yellow" + + $scriptPath = Join-Path $PSScriptRoot "openclaw-whatsapp-login.ps1" + if (Test-Path $scriptPath) { + try { + Log "Executing: $scriptPath" "Cyan" + & $scriptPath + Log "WhatsApp login script completed successfully" "Green" + return $true + } catch { + Log "WhatsApp login script failed: $_" "Red" + return $false + } + } else { + Log "WhatsApp login script not found at: $scriptPath" "Red" + return $false + } +} + +function CheckForCriticalError { + param([string]$Output, [string]$ErrorOutput) + + $allOutput = "$Output`n$ErrorOutput" + + foreach ($pattern in $criticalErrors) { + if ($allOutput -match $pattern) { + return $true, $pattern + } + } + + return $false, "" +} + $crashCount = 0 +$stableRuntime = 60 # seconds - if runs longer than this, reset crash count while ($true) { $startTime = Get-Date $crashCount++ - Write-Host "" - Write-Host "[$(Get-Date -Format 'HH:mm:ss')] Starting gateway (attempt #$crashCount)..." -ForegroundColor Green + Log "" "Gray" + Log "Starting gateway (attempt #$crashCount)..." "Green" + + $processOutput = @() + $processError = @() + $isCriticalError = $false try { - openclaw gateway --port $port --verbose - $exitCode = $LASTEXITCODE + # Start process and capture output in real-time + $process = Start-Process -FilePath "openclaw" -ArgumentList "gateway --port $port --verbose" ` + -RedirectStandardOutput $env:TEMP\gateway_stdout.tmp ` + -RedirectStandardError $env:TEMP\gateway_stderr.tmp ` + -PassThru -NoNewWindow + + $processId = $process.Id + Log "Gateway process started (PID: $processId)" "Green" + + # Monitor process and check for critical errors every 500ms + $monitorInterval = 500 # milliseconds + $lastCheckTime = Get-Date + + while (!$process.HasExited) { + # Check for critical errors in output files + if (Test-Path $env:TEMP\gateway_stdout.tmp) { + $stdout = Get-Content $env:TEMP\gateway_stdout.tmp -Raw -ErrorAction SilentlyContinue + $processOutput += $stdout.Split("`n") + } + + if (Test-Path $env:TEMP\gateway_stderr.tmp) { + $stderr = Get-Content $env:TEMP\gateway_stderr.tmp -Raw -ErrorAction SilentlyContinue + $processError += $stderr.Split("`n") + } + + # Check for WhatsApp login errors first + $hasWhatsAppError, $whatsappPattern = CheckForWhatsAppLogin ($processOutput -join "`n") ($processError -join "`n") + + if ($hasWhatsAppError) { + Log "WhatsApp error detected: $whatsappPattern" "Yellow" + Stop-Process -Id $processId -Force -ErrorAction SilentlyContinue + Start-Sleep -Milliseconds 500 + + # Run WhatsApp login script + $loginSuccess = RunWhatsAppLogin + + if ($loginSuccess) { + Log "Restarting gateway after WhatsApp login..." "Green" + $isCriticalError = $false # Don't count this as critical for backoff + } else { + Log "WhatsApp login failed, will retry..." "Red" + $isCriticalError = $true + } + + break + } + + # Check for critical error patterns + $hasCriticalError, $matchedPattern = CheckForCriticalError ($processOutput -join "`n") ($processError -join "`n") + + if ($hasCriticalError) { + Log "Critical error detected: $matchedPattern" "Red" + Log "Terminating gateway process..." "Yellow" + $isCriticalError = $true + Stop-Process -Id $processId -Force -ErrorAction SilentlyContinue + Start-Sleep -Milliseconds 500 + break + } + + Start-Sleep -Milliseconds $monitorInterval + } + + $exitCode = $process.ExitCode } catch { $exitCode = 1 - Write-Host "[$(Get-Date -Format 'HH:mm:ss')] Exception: $_" -ForegroundColor Red + Log "Exception: $_" "Red" + $isCriticalError = $true + } + + # Read final output + if (Test-Path $env:TEMP\gateway_stdout.tmp) { + $finalStdout = Get-Content $env:TEMP\gateway_stdout.tmp -Raw -ErrorAction SilentlyContinue + Remove-Item $env:TEMP\gateway_stdout.tmp -Force -ErrorAction SilentlyContinue + } + + if (Test-Path $env:TEMP\gateway_stderr.tmp) { + $finalStderr = Get-Content $env:TEMP\gateway_stderr.tmp -Raw -ErrorAction SilentlyContinue + Remove-Item $env:TEMP\gateway_stderr.tmp -Force -ErrorAction SilentlyContinue } $runtime = (Get-Date) - $startTime - Write-Host "" - Write-Host "[$(Get-Date -Format 'HH:mm:ss')] Gateway exited with code $exitCode after $($runtime.ToString('hh\:mm\:ss'))" -ForegroundColor Yellow + Log "Gateway exited with code $exitCode after $($runtime.TotalSeconds)s" $(if ($isCriticalError) { "Red" } else { "Yellow" }) - # Reset crash count if it ran for more than 1 minute (stable) - if ($runtime.TotalMinutes -gt 1) { + # Reset crash count if stable run + if ($runtime.TotalSeconds -gt $stableRuntime) { + Log "Stable run detected, resetting crash counter" "Green" $crashCount = 0 } # Exponential backoff for rapid crashes (max 30 seconds) - $delay = [Math]::Min($restartDelay * [Math]::Pow(2, [Math]::Min($crashCount - 1, 3)), 30) + # But reduce delay if critical error (start immediately) + if ($isCriticalError -and $crashCount -gt 1) { + $delay = 1 # Quick restart on critical errors after first crash + Log "Critical error mode: quick restart" "Cyan" + } else { + $delay = [Math]::Min($restartDelay * [Math]::Pow(2, [Math]::Min($crashCount - 1, 3)), 30) + } - Write-Host "[$(Get-Date -Format 'HH:mm:ss')] Respawning in $delay seconds..." -ForegroundColor Cyan - Start-Sleep -Seconds $delay + if ($delay -gt 0) { + Log "Respawning in $delay seconds..." "Cyan" + Start-Sleep -Seconds $delay + } } + From 4bb240979291c8a0ee8d3a3fa023faffa93a3b67 Mon Sep 17 00:00:00 2001 From: Youssef Adel Date: Thu, 5 Feb 2026 19:08:09 +0200 Subject: [PATCH 12/16] feat: enhance OpenClaw Gateway Daemon with improved installation checks and error handling --- openclaw-gateway-daemon.ps1 | 169 ++++++++++++++++++++++++++++++++---- src/public/setup.html | 4 +- 2 files changed, 156 insertions(+), 17 deletions(-) diff --git a/openclaw-gateway-daemon.ps1 b/openclaw-gateway-daemon.ps1 index 0d6360a..86dde30 100644 --- a/openclaw-gateway-daemon.ps1 +++ b/openclaw-gateway-daemon.ps1 @@ -4,10 +4,25 @@ $ErrorActionPreference = "Continue" -$port = 18789 +$port = 18791 $restartDelay = 3 # seconds to wait before respawning $logFile = "openclaw-gateway-daemon.log" +# Check if openclaw is installed +function CheckOpenClawInstalled { + try { + # Use cmd /c for reliable npx execution on Windows + $output = cmd /c "openclaw --version 2>&1" + if ($LASTEXITCODE -eq 0) { + return $true + } + } catch { + return $false + } + + return $false +} + # Error patterns that trigger immediate restart $criticalErrors = @( "Web connection closed.*status 408", @@ -21,7 +36,17 @@ $criticalErrors = @( "Fatal error", "cannot connect", "ECONNREFUSED", - "ETIMEDOUT" + "ETIMEDOUT", + "FailoverError.*401 Authentication required", + "401 Authentication required.*auth" +) + +# Error patterns that are expected/non-critical (don't log as critical) +$expectedErrors = @( + "unauthorized.*token_missing", + "unauthorized conn=", + "closed before connect", + "connect failed" ) # Error patterns that trigger WhatsApp login @@ -32,7 +57,9 @@ $whatsappLoginErrors = @( "WhatsApp.*QR", "device.*not.*registered", "session.*expired", - "authentication.*failed" + "authentication.*failed", + "401 Authentication required", + "FailoverError.*401" ) Write-Host "========================================" -ForegroundColor Cyan @@ -42,6 +69,20 @@ Write-Host " Log: $logFile" -ForegroundColor Cyan Write-Host " Press Ctrl+C to stop" -ForegroundColor Yellow Write-Host "========================================" -ForegroundColor Cyan +# Check if openclaw CLI is installed +Write-Host "`nChecking OpenClaw installation..." -ForegroundColor Yellow +if (-not (CheckOpenClawInstalled)) { + Write-Host "ERROR: OpenClaw CLI is not installed or not in PATH!" -ForegroundColor Red + Write-Host "`nTo fix this, run:" -ForegroundColor Yellow + Write-Host " npm install -g openclaw" -ForegroundColor Cyan + Write-Host "`nOr install from: https://github.com/openclaw/openclaw" -ForegroundColor Cyan + Write-Host "`nDaemon cannot start without OpenClaw installed." -ForegroundColor Red + exit 1 +} + +Write-Host "OpenClaw CLI found in PATH" -ForegroundColor Green +Write-Host "" + function Log { param([string]$Message, [string]$Color = "White") $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" @@ -89,6 +130,13 @@ function CheckForCriticalError { $allOutput = "$Output`n$ErrorOutput" + # Check if it's an expected/non-critical error first + foreach ($pattern in $expectedErrors) { + if ($allOutput -match $pattern) { + return $false, "" + } + } + foreach ($pattern in $criticalErrors) { if ($allOutput -match $pattern) { return $true, $pattern @@ -114,10 +162,11 @@ while ($true) { try { # Start process and capture output in real-time - $process = Start-Process -FilePath "openclaw" -ArgumentList "gateway --port $port --verbose" ` + # Use cmd /c to invoke npx (more reliable on Windows) + $process = Start-Process -FilePath "cmd" -ArgumentList "/c", "openclaw gateway --port $port --verbose" ` -RedirectStandardOutput $env:TEMP\gateway_stdout.tmp ` -RedirectStandardError $env:TEMP\gateway_stderr.tmp ` - -PassThru -NoNewWindow + -PassThru -NoNewWindow -ErrorAction Stop $processId = $process.Id Log "Gateway process started (PID: $processId)" "Green" @@ -126,16 +175,60 @@ while ($true) { $monitorInterval = 500 # milliseconds $lastCheckTime = Get-Date - while (!$process.HasExited) { + while ($null -ne $process -and !$process.HasExited) { # Check for critical errors in output files if (Test-Path $env:TEMP\gateway_stdout.tmp) { - $stdout = Get-Content $env:TEMP\gateway_stdout.tmp -Raw -ErrorAction SilentlyContinue - $processOutput += $stdout.Split("`n") + try { + $stdout = Get-Content $env:TEMP\gateway_stdout.tmp -Raw -ErrorAction SilentlyContinue + if ($null -ne $stdout -and $stdout.Length -gt 0) { + # Log new output lines + $newLines = $stdout.Split("`n") | Where-Object { $_ -and $_ -notin $processOutput } + foreach ($line in $newLines) { + if ($line.Trim()) { + # Clean up the log line - remove trailing content after parenthesis + $cleanLine = $line -replace '\s*\(.*$', '' + Log "[OpenClaw] $cleanLine" "Cyan" + + # Check if canvas/gateway is mounted and open browser + if ($line -match "canvas.*mounted at\s+(https?://[^\s]+)") { + $url = $matches[1] + Log "Gateway ready! Opening $url in browser..." "Green" + Start-Process $url -ErrorAction SilentlyContinue + } + + $processOutput += $line + } + } + } + } catch { + # Ignore file read errors + } } if (Test-Path $env:TEMP\gateway_stderr.tmp) { - $stderr = Get-Content $env:TEMP\gateway_stderr.tmp -Raw -ErrorAction SilentlyContinue - $processError += $stderr.Split("`n") + try { + $stderr = Get-Content $env:TEMP\gateway_stderr.tmp -Raw -ErrorAction SilentlyContinue + if ($null -ne $stderr -and $stderr.Length -gt 0) { + # Log new error lines + $newLines = $stderr.Split("`n") | Where-Object { $_ -and $_ -notin $processError } + foreach ($line in $newLines) { + if ($line.Trim()) { + # Clean up the log line + $cleanLine = $line -replace '\s*\(.*$', '' + + # Identify auth errors and provide helpful context + if ($cleanLine -match "unauthorized|token_missing|connect failed") { + Log "[OpenClaw] $cleanLine (authentication - configure OpenClaw token to fix)" "Magenta" + } else { + Log "[OpenClaw ERROR] $cleanLine" "Yellow" + } + $processError += $line + } + } + } + } catch { + # Ignore file read errors + } } # Check for WhatsApp login errors first @@ -175,25 +268,71 @@ while ($true) { Start-Sleep -Milliseconds $monitorInterval } - $exitCode = $process.ExitCode + # Ensure process object is valid before accessing ExitCode + if ($null -ne $process) { + $exitCode = $process.ExitCode + } else { + $exitCode = 1 + } } catch { + $errorMsg = $_.Exception.Message $exitCode = 1 - Log "Exception: $_" "Red" + Log "Exception: $errorMsg" "Red" + + # Check for specific Windows executable error + if ($errorMsg -match "not a valid Win32 application|cannot find the path|npx") { + Log "FATAL: OpenClaw could not be executed" "Red" + Log "Please ensure npm and Node.js are installed: https://nodejs.org/" "Yellow" + Log "Then install OpenClaw: npm install -g openclaw" "Yellow" + Log "Daemon will exit." "Red" + exit 1 + } + $isCriticalError = $true } - # Read final output + # Read final output and display any remaining logs + $hasOutput = $false + if (Test-Path $env:TEMP\gateway_stdout.tmp) { - $finalStdout = Get-Content $env:TEMP\gateway_stdout.tmp -Raw -ErrorAction SilentlyContinue + try { + $finalStdout = Get-Content $env:TEMP\gateway_stdout.tmp -Raw -ErrorAction SilentlyContinue + if ($null -ne $finalStdout -and $finalStdout.Length -gt 0) { + $hasOutput = $true + Log "=== OpenClaw Output ===" "Cyan" + $finalStdout.Split("`n") | ForEach-Object { + if ($_.Trim()) { + $cleanLine = $_ -replace '\s*\(.*$', '' + Log $cleanLine "Cyan" + } + } + } + } catch { } Remove-Item $env:TEMP\gateway_stdout.tmp -Force -ErrorAction SilentlyContinue } if (Test-Path $env:TEMP\gateway_stderr.tmp) { - $finalStderr = Get-Content $env:TEMP\gateway_stderr.tmp -Raw -ErrorAction SilentlyContinue + try { + $finalStderr = Get-Content $env:TEMP\gateway_stderr.tmp -Raw -ErrorAction SilentlyContinue + if ($null -ne $finalStderr -and $finalStderr.Length -gt 0) { + $hasOutput = $true + Log "=== OpenClaw Errors ===" "Yellow" + $finalStderr.Split("`n") | ForEach-Object { + if ($_.Trim()) { + $cleanLine = $_ -replace '\s*\(.*$', '' + Log $cleanLine "Yellow" + } + } + } + } catch { } Remove-Item $env:TEMP\gateway_stderr.tmp -Force -ErrorAction SilentlyContinue } + if (-not $hasOutput -and $exitCode -ne 0) { + Log "Gateway exited with no output. Check if OpenClaw CLI is properly configured." "Yellow" + } + $runtime = (Get-Date) - $startTime Log "Gateway exited with code $exitCode after $($runtime.TotalSeconds)s" $(if ($isCriticalError) { "Red" } else { "Yellow" }) diff --git a/src/public/setup.html b/src/public/setup.html index cfe77f6..3085939 100644 --- a/src/public/setup.html +++ b/src/public/setup.html @@ -288,10 +288,10 @@

🦀 OpenClaw Gateway Recommended

2 Run with this proxy as the backend:

- openclaw gateway --upstream http://localhost:3000 --port 18789 + openclaw gateway --upstream http://localhost:3000 --port 18791
-

3 Configure Cursor to use OpenClaw gateway at http://localhost:18789/v1

+

3 Configure Cursor to use OpenClaw gateway at http://localhost:18791/v1

From f59ddb4d5b939361f45065f27330e28db119a569 Mon Sep 17 00:00:00 2001 From: Youssef Adel Date: Mon, 23 Feb 2026 03:54:07 +0200 Subject: [PATCH 13/16] feat: update server port to 3000 and enhance usage tracking with sliding window rate limiting --- .env.example | 2 +- README.md | 36 +++++++++++++++++------------------ src/services/usage-service.ts | 30 +++++++++++++++++++++-------- 3 files changed, 41 insertions(+), 27 deletions(-) diff --git a/.env.example b/.env.example index 4900a32..91d681b 100644 --- a/.env.example +++ b/.env.example @@ -1,5 +1,5 @@ # Server Configuration -PORT=18790 +PORT=3000 HOST=localhost NODE_ENV=development diff --git a/README.md b/README.md index 8717f24..cab38fa 100644 --- a/README.md +++ b/README.md @@ -91,9 +91,9 @@ Automatically translates common model name variations: 2. Go to Settings > API Keys 3. In the "Override OpenAI Base URL" section, enter: ``` - http://localhost:18790/v1 + http://localhost:3000/v1 ``` -4. Go to http://localhost:18790/auth.html in your browser +4. Go to http://localhost:3000/auth.html in your browser 5. Follow the authentication steps to connect to GitHub ## 🐾 OpenClaw Integration @@ -117,10 +117,10 @@ This proxy fully supports [OpenClaw](https://github.com/openclaw/openclaw), an A # openclaw.config.yaml provider: type: openai - baseUrl: http://localhost:18790/v1 + baseUrl: http://localhost:3000/v1 ``` -3. Authenticate at `http://localhost:18790/auth.html` +3. Authenticate at `http://localhost:3000/auth.html` ### OpenClaw Agent Categories @@ -142,7 +142,7 @@ This proxy fully supports [OpenClaw](https://github.com/openclaw/openclaw), an A "title": "GitHub Copilot via Proxy", "provider": "openai", "model": "gpt-4o", - "apiBase": "http://localhost:18790/v1", + "apiBase": "http://localhost:3000/v1", "apiKey": "dummy" }] } @@ -151,7 +151,7 @@ This proxy fully supports [OpenClaw](https://github.com/openclaw/openclaw), an A ### Aider (AI Pair Programming) ```bash # Set environment variables -export OPENAI_API_BASE=http://localhost:18790/v1 +export OPENAI_API_BASE=http://localhost:3000/v1 export OPENAI_API_KEY=dummy # Run Aider with any supported model @@ -165,7 +165,7 @@ from langchain_openai import ChatOpenAI llm = ChatOpenAI( model="gpt-4o", - base_url="http://localhost:18790/v1", + base_url="http://localhost:3000/v1", api_key="dummy" # Not validated, but required ) @@ -178,7 +178,7 @@ from llama_index.llms.openai import OpenAI llm = OpenAI( model="claude-sonnet-4.5", - api_base="http://localhost:18790/v1", + api_base="http://localhost:3000/v1", api_key="dummy" ) ``` @@ -188,7 +188,7 @@ llm = OpenAI( from openai import OpenAI client = OpenAI( - base_url="http://localhost:18790/v1", + base_url="http://localhost:3000/v1", api_key="dummy" ) @@ -207,7 +207,7 @@ for chunk in response: import OpenAI from 'openai'; const openai = new OpenAI({ - baseURL: 'http://localhost:18790/v1', + baseURL: 'http://localhost:3000/v1', apiKey: 'dummy' }); @@ -225,10 +225,10 @@ for await (const chunk of stream) { ### cURL / REST API ```bash # List available models -curl http://localhost:18790/v1/models +curl http://localhost:3000/v1/models # Chat completion -curl http://localhost:18790/v1/chat/completions \ +curl http://localhost:3000/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-4o", @@ -237,7 +237,7 @@ curl http://localhost:18790/v1/chat/completions \ }' # Responses API (newer format) -curl http://localhost:18790/v1/responses \ +curl http://localhost:3000/v1/responses \ -H "Content-Type: application/json" \ -d '{ "model": "claude-sonnet-4.5", @@ -264,7 +264,7 @@ curl http://localhost:18790/v1/responses \ ### Basic Chat Completion ```bash -curl -X POST http://localhost:18790/v1/chat/completions \ +curl -X POST http://localhost:3000/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-4o", @@ -277,7 +277,7 @@ curl -X POST http://localhost:18790/v1/chat/completions \ ### Streaming Response ```bash -curl -X POST http://localhost:18790/v1/chat/completions \ +curl -X POST http://localhost:3000/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ "model": "claude-sonnet-4.5", @@ -288,7 +288,7 @@ curl -X POST http://localhost:18790/v1/chat/completions \ ### Responses API Format ```bash -curl -X POST http://localhost:18790/v1/responses \ +curl -X POST http://localhost:3000/v1/responses \ -H "Content-Type: application/json" \ -d '{ "model": "gemini-2.5-pro", @@ -339,7 +339,7 @@ npm run lint # Run linting ### Environment Variables | Variable | Default | Description | |----------|---------|-------------| -| `PORT` | `18790` | Server port | +| `PORT` | `3000` | Server port | | `HOST` | `localhost` | Server host | | `LOG_LEVEL` | `info` | Logging level (`error`, `warn`, `info`, `debug`) | @@ -360,7 +360,7 @@ npm run lint # Run linting ▼ ┌────────────────────────────────┐ │ GitHub Copilot Proxy │ - │ http://localhost:18790/v1 │ + │ http://localhost:3000/v1 │ │ │ │ • /v1/chat/completions │ │ • /v1/responses │ diff --git a/src/services/usage-service.ts b/src/services/usage-service.ts index 6616eac..26eb52a 100644 --- a/src/services/usage-service.ts +++ b/src/services/usage-service.ts @@ -8,6 +8,8 @@ interface UsageMetrics { tokenCount: number; lastRequestTime: number; startTime: number; + // Track request timestamps for sliding window rate limiting + requestTimestamps: number[]; // Track tokens used per minute window tokenTimestamps: Array<{ tokens: number; @@ -32,6 +34,7 @@ export function initializeUsage(sessionId: string): void { tokenCount: 0, lastRequestTime: Date.now(), startTime: Date.now(), + requestTimestamps: [], tokenTimestamps: [] }; logger.debug(`Initialized usage tracking for session: ${sessionId.substring(0, 8)}...`); @@ -53,6 +56,9 @@ export function trackRequest(sessionId: string, tokenCount = 0): void { usage[sessionId].tokenCount += tokenCount; usage[sessionId].lastRequestTime = now; + // Record request timestamp for sliding window rate limiting + usage[sessionId].requestTimestamps.push(now); + // Record token usage with timestamp for rate limiting over time if (tokenCount > 0) { usage[sessionId].tokenTimestamps.push({ @@ -61,8 +67,11 @@ export function trackRequest(sessionId: string, tokenCount = 0): void { }); } - // Clean up old token timestamps (older than 5 minutes) + // Clean up old timestamps (older than 5 minutes) const fiveMinutesAgo = now - 5 * 60 * 1000; + usage[sessionId].requestTimestamps = usage[sessionId].requestTimestamps.filter( + ts => ts >= fiveMinutesAgo + ); usage[sessionId].tokenTimestamps = usage[sessionId].tokenTimestamps.filter( entry => entry.timestamp >= fiveMinutesAgo ); @@ -125,13 +134,17 @@ export function checkRateLimit( const now = Date.now(); const oneMinuteAgo = now - 60 * 1000; - // Simple rate limiting based on requests in the last minute - // In a production app, you'd implement a sliding window algorithm - if ( - usage[sessionId].requestCount > maxRequestsPerMinute && - usage[sessionId].lastRequestTime > oneMinuteAgo - ) { - const retryAfter = Math.ceil((usage[sessionId].lastRequestTime + 60 * 1000 - now) / 1000); + // Sliding window rate limiting: count only requests within the last minute + const recentRequests = usage[sessionId].requestTimestamps.filter( + ts => ts >= oneMinuteAgo + ).length; + + if (recentRequests >= maxRequestsPerMinute) { + // Find the oldest request in the window to calculate when a slot frees up + const oldestInWindow = usage[sessionId].requestTimestamps + .filter(ts => ts >= oneMinuteAgo) + .sort((a, b) => a - b)[0]; + const retryAfter = Math.ceil((oldestInWindow + 60 * 1000 - now) / 1000); return { limited: true, retryAfter: Math.max(1, retryAfter) }; } @@ -149,6 +162,7 @@ export function resetUsage(sessionId: string): void { tokenCount: 0, lastRequestTime: Date.now(), startTime: Date.now(), + requestTimestamps: [], tokenTimestamps: [] }; logger.info(`Reset usage metrics for session: ${sessionId.substring(0, 8)}...`); From 17d186128674d2f968f2e220a1f6324b2fc46f03 Mon Sep 17 00:00:00 2001 From: Youssef Adel Date: Mon, 23 Feb 2026 05:09:22 +0200 Subject: [PATCH 14/16] feat: add development script for live-reload and enhance model mapping with detailed comments --- .gitignore | 3 + dev.ps1 | 92 +++++++++++++++++++++ package.json | 3 + src/routes/openai.ts | 139 ++++++++------------------------ src/services/copilot-service.ts | 97 ++++++++++++++-------- 5 files changed, 196 insertions(+), 138 deletions(-) create mode 100644 dev.ps1 diff --git a/.gitignore b/.gitignore index 8831576..46cc025 100644 --- a/.gitignore +++ b/.gitignore @@ -36,6 +36,9 @@ build/ out/ .next/ +# Dev-mode temp loader +.dev-entry.mjs + # Coverage directory used by tools like istanbul coverage/ *.lcov diff --git a/dev.ps1 b/dev.ps1 new file mode 100644 index 0000000..cc52a4e --- /dev/null +++ b/dev.ps1 @@ -0,0 +1,92 @@ +<# +.SYNOPSIS + Development server with live-reload. Watches for file changes in src/, + rebuilds TypeScript, copies public assets, and restarts the server. + +.DESCRIPTION + Uses Node --watch to monitor source files. On any change the process + is automatically restarted. The script first does a full build so that + dist/ is up-to-date, then launches with --watch. + +.EXAMPLE + .\dev.ps1 + .\dev.ps1 -Verbose +#> +param( + [switch]$Verbose +) + +$ErrorActionPreference = "Stop" +Set-Location $PSScriptRoot + +Write-Host "`n=== github-copilot-proxy | dev mode ===" -ForegroundColor Cyan +Write-Host "Watching src/ for changes — auto-rebuild & restart`n" -ForegroundColor DarkGray + +# ── 1. Initial build ──────────────────────────────────────────────── +Write-Host "[1/2] Building project..." -ForegroundColor Yellow +npm run build +if ($LASTEXITCODE -ne 0) { + Write-Host "Build failed. Fix errors above and re-run." -ForegroundColor Red + exit 1 +} +Write-Host "[1/2] Build OK`n" -ForegroundColor Green + +# ── 2. Start with --watch ─────────────────────────────────────────── +# Node >= 22 has stable --watch support. We watch the src/ directory +# so that any .ts / .html change triggers a restart. The before-restart +# hook re-runs the build so dist/ stays current. +Write-Host "[2/2] Starting server in watch mode...`n" -ForegroundColor Yellow + +$env:NODE_ENV = "development" +if ($Verbose) { $env:LOG_LEVEL = "debug" } + +# We use a small wrapper: on each restart we rebuild then launch. +# Node's --watch-path lets us scope what triggers restarts. +$watchPaths = @( + "--watch-path=src" +) + +# Build the command +# --watch restarts the *entry* process on file change. +# We chain: build first, then start from dist/. +$nodeBin = "node" +$args = @( + "--watch" + "--watch-path=src" + "--watch-preserve-output" + "-e" + # Inline JS: run build, then import the app + "const{execSync}=require('child_process');try{execSync('npm run build',{stdio:'inherit'})}catch{process.exit(1)};import('./dist/index.js')" +) + +# node --watch does not work well with inline -e + dynamic import in all +# versions, so instead we use a tiny loader script. +$loaderContent = @" +import { execSync } from 'child_process'; + +// Rebuild on every (re)start so dist/ is up-to-date +try { + execSync('npx tsc && node -e "require(''fs'').cpSync(''src/public'',''dist/public'',{recursive:true})"', { + stdio: 'inherit', + cwd: import.meta.dirname ?? '.', + }); +} catch { + console.error('\x1b[31mBuild failed — waiting for next change...\x1b[0m'); + // Keep process alive so --watch can restart on next save + await new Promise(() => {}); +} + +// Start the actual server +await import('./dist/index.js'); +"@ + +$loaderPath = Join-Path $PSScriptRoot ".dev-entry.mjs" +Set-Content -Path $loaderPath -Value $loaderContent -Encoding UTF8 + +try { + & $nodeBin --watch --watch-path=src --watch-preserve-output $loaderPath +} +finally { + # Clean up the temp loader + if (Test-Path $loaderPath) { Remove-Item $loaderPath -Force } +} diff --git a/package.json b/package.json index e465fa7..fa7a44e 100644 --- a/package.json +++ b/package.json @@ -7,9 +7,12 @@ "build": "tsc && npm run copy-public", "copy-public": "node -e \"require('fs').cpSync('src/public', 'dist/public', {recursive: true})\"", "start": "node dist/index.js", + "start:build": "npm run build && npm run start", "start:verbose": "cross-env LOG_LEVEL=debug node dist/index.js", "start:openclaw": "npm run build && concurrently --names \"proxy,gateway\" --prefix-colors \"cyan,magenta\" \"npm run start:verbose\" \"powershell -ExecutionPolicy Bypass -File \".\\openclaw-gateway-daemon.ps1\"\"", "dev": "ts-node src/index.ts", + "dev:watch": "powershell -ExecutionPolicy Bypass -File \".\\dev.ps1\"", + "dev:watch:verbose": "powershell -ExecutionPolicy Bypass -File \".\\dev.ps1\" -Verbose", "lint": "eslint src/**/*.ts", "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js", "whatsapp:login": "powershell -ExecutionPolicy Bypass -File \".\\openclaw-whatsapp-login.ps1\"" diff --git a/src/routes/openai.ts b/src/routes/openai.ts index 2517dae..234d304 100644 --- a/src/routes/openai.ts +++ b/src/routes/openai.ts @@ -77,112 +77,39 @@ openaiRoutes.get('/models', requireAuth, (req, res) => { res.json({ object: 'list', data: [ - // Claude Models (Anthropic) - { - id: 'claude-opus-4.5', - object: 'model', - created: timestamp, - owned_by: 'anthropic', - }, - { - id: 'claude-sonnet-4.5', - object: 'model', - created: timestamp, - owned_by: 'anthropic', - }, - { - id: 'claude-sonnet-4', - object: 'model', - created: timestamp, - owned_by: 'anthropic', - }, - { - id: 'claude-haiku-4.5', - object: 'model', - created: timestamp, - owned_by: 'anthropic', - }, - // GPT Models (OpenAI/Azure) - { - id: 'gpt-4o', - object: 'model', - created: timestamp, - owned_by: 'azure-openai', - }, - { - id: 'gpt-4o-mini', - object: 'model', - created: timestamp, - owned_by: 'azure-openai', - }, - { - id: 'gpt-4.1', - object: 'model', - created: timestamp, - owned_by: 'azure-openai', - }, - { - id: 'gpt-4', - object: 'model', - created: timestamp, - owned_by: 'azure-openai', - }, - { - id: 'gpt-3.5-turbo', - object: 'model', - created: timestamp, - owned_by: 'azure-openai', - }, - { - id: 'gpt-5.2', - object: 'model', - created: timestamp, - owned_by: 'openai', - }, - { - id: 'gpt-5-codex', - object: 'model', - created: timestamp, - owned_by: 'openai', - }, - // Gemini Models (Google) - { - id: 'gemini-2.5-pro', - object: 'model', - created: timestamp, - owned_by: 'google', - }, - { - id: 'gemini-3-pro-preview', - object: 'model', - created: timestamp, - owned_by: 'google', - }, - { - id: 'gemini-3-flash-preview', - object: 'model', - created: timestamp, - owned_by: 'google', - }, - // o1/o3 Reasoning Models - { - id: 'o1-preview', - object: 'model', - created: timestamp, - owned_by: 'openai', - }, - { - id: 'o1-mini', - object: 'model', - created: timestamp, - owned_by: 'openai', - }, - { - id: 'o3-mini', - object: 'model', - created: timestamp, - owned_by: 'openai', - } + // ── Anthropic Claude ───────────────────────────────────────── + { id: 'claude-haiku-4.5', object: 'model', created: timestamp, owned_by: 'anthropic' }, + { id: 'claude-opus-4.5', object: 'model', created: timestamp, owned_by: 'anthropic' }, + { id: 'claude-opus-4.6', object: 'model', created: timestamp, owned_by: 'anthropic' }, + { id: 'claude-opus-4.6-fast', object: 'model', created: timestamp, owned_by: 'anthropic' }, + { id: 'claude-sonnet-4', object: 'model', created: timestamp, owned_by: 'anthropic' }, + { id: 'claude-sonnet-4.5', object: 'model', created: timestamp, owned_by: 'anthropic' }, + { id: 'claude-sonnet-4.6', object: 'model', created: timestamp, owned_by: 'anthropic' }, + + // ── OpenAI GPT ────────────────────────────────────────────── + { id: 'gpt-4o', object: 'model', created: timestamp, owned_by: 'openai' }, + { id: 'gpt-4.1', object: 'model', created: timestamp, owned_by: 'openai' }, + { id: 'gpt-5-mini', object: 'model', created: timestamp, owned_by: 'openai' }, + { id: 'gpt-5.1', object: 'model', created: timestamp, owned_by: 'openai' }, + { id: 'gpt-5.1-codex', object: 'model', created: timestamp, owned_by: 'openai' }, + { id: 'gpt-5.1-codex-mini', object: 'model', created: timestamp, owned_by: 'openai' }, + { id: 'gpt-5.1-codex-max', object: 'model', created: timestamp, owned_by: 'openai' }, + { id: 'gpt-5.2', object: 'model', created: timestamp, owned_by: 'openai' }, + { id: 'gpt-5.2-codex', object: 'model', created: timestamp, owned_by: 'openai' }, + { id: 'gpt-5.3-codex', object: 'model', created: timestamp, owned_by: 'openai' }, + + // ── Google Gemini ─────────────────────────────────────────── + { id: 'gemini-2.5-pro', object: 'model', created: timestamp, owned_by: 'google' }, + { id: 'gemini-3-flash', object: 'model', created: timestamp, owned_by: 'google' }, + { id: 'gemini-3-pro', object: 'model', created: timestamp, owned_by: 'google' }, + { id: 'gemini-3.1-pro', object: 'model', created: timestamp, owned_by: 'google' }, + + // ── xAI ───────────────────────────────────────────────────── + { id: 'grok-code-fast-1', object: 'model', created: timestamp, owned_by: 'xai' }, + + // ── GitHub fine-tuned ─────────────────────────────────────── + { id: 'raptor-mini', object: 'model', created: timestamp, owned_by: 'github' }, + { id: 'goldeneye', object: 'model', created: timestamp, owned_by: 'github' }, ] }); }); diff --git a/src/services/copilot-service.ts b/src/services/copilot-service.ts index b9e6448..e829c40 100644 --- a/src/services/copilot-service.ts +++ b/src/services/copilot-service.ts @@ -14,38 +14,71 @@ import { getMachineId } from '../utils/machine-id.js'; import { logger } from '../utils/logger.js'; const MODEL_MAPPING: Record = { - 'claude-4.5-opus': 'claude-opus-4.5', - 'claude-opus-4.5': 'claude-opus-4.5', - 'claude-4-opus': 'claude-opus-4.5', - 'claude-opus-4': 'claude-opus-4.5', - 'claude-4.5-sonnet': 'claude-sonnet-4.5', - 'claude-sonnet-4.5': 'claude-sonnet-4.5', - 'claude-4-sonnet': 'claude-sonnet-4', - 'claude-sonnet-4': 'claude-sonnet-4', - 'claude-4.5-haiku': 'claude-haiku-4.5', - 'claude-haiku-4.5': 'claude-haiku-4.5', - 'claude-3.5-sonnet': 'claude-sonnet-4', - 'claude-3-opus': 'claude-opus-4.5', - 'claude-3-sonnet': 'claude-sonnet-4', - 'gpt-4o': 'gpt-4o', - 'gpt-4o-mini': 'gpt-4o-mini', - 'gpt-4.1': 'gpt-4.1', - 'gpt-4-turbo': 'gpt-4-0125-preview', - 'gpt-4': 'gpt-4', - 'gpt-3.5-turbo': 'gpt-3.5-turbo', - 'gpt-5.2': 'gpt-5.2', - 'gpt-5-codex': 'gpt-5-codex', - 'gpt-5.1-codex-max': 'gpt-5.1-codex-max', - 'gemini-2.5-pro': 'gemini-2.5-pro', - 'gemini-3-pro': 'gemini-3-pro-preview', - 'gemini-3-pro-preview': 'gemini-3-pro-preview', - 'gemini-3-flash': 'gemini-3-flash-preview', - 'gemini-3-flash-preview': 'gemini-3-flash-preview', - 'o1': 'o1-preview', - 'o1-preview': 'o1-preview', - 'o1-mini': 'o1-mini', - 'o3-mini': 'o3-mini', - 'default': 'gpt-4o' + // ── Anthropic Claude ───────────────────────────────────────────── + 'claude-haiku-4.5': 'claude-haiku-4.5', + 'claude-4.5-haiku': 'claude-haiku-4.5', + 'claude-opus-4.5': 'claude-opus-4.5', + 'claude-4.5-opus': 'claude-opus-4.5', + 'claude-opus-4.6': 'claude-opus-4.6', + 'claude-4.6-opus': 'claude-opus-4.6', + 'claude-opus-4.6-fast': 'claude-opus-4.6-fast', + 'claude-sonnet-4': 'claude-sonnet-4', + 'claude-4-sonnet': 'claude-sonnet-4', + 'claude-sonnet-4.5': 'claude-sonnet-4.5', + 'claude-4.5-sonnet': 'claude-sonnet-4.5', + 'claude-sonnet-4.6': 'claude-sonnet-4.6', + 'claude-4.6-sonnet': 'claude-sonnet-4.6', + + // ── OpenAI GPT ────────────────────────────────────────────────── + 'gpt-4o': 'gpt-4o', + 'gpt-4.1': 'gpt-4.1', + 'gpt-5-mini': 'gpt-5-mini', + 'gpt-5.1': 'gpt-5.1', + 'gpt-5.1-codex': 'gpt-5.1-codex', + 'gpt-5.1-codex-mini': 'gpt-5.1-codex-mini', + 'gpt-5.1-codex-max': 'gpt-5.1-codex-max', + 'gpt-5.2': 'gpt-5.2', + 'gpt-5.2-codex': 'gpt-5.2-codex', + 'gpt-5.3-codex': 'gpt-5.3-codex', + + // ── Google Gemini ─────────────────────────────────────────────── + 'gemini-2.5-pro': 'gemini-2.5-pro', + 'gemini-3-flash': 'gemini-3-flash', + 'gemini-3-pro': 'gemini-3-pro', + 'gemini-3.1-pro': 'gemini-3.1-pro', + + // ── xAI ───────────────────────────────────────────────────────── + 'grok-code-fast-1': 'grok-code-fast-1', + + // ── GitHub fine-tuned ─────────────────────────────────────────── + 'raptor-mini': 'raptor-mini', + 'goldeneye': 'goldeneye', + + // ── Backward-compatible aliases for retired models ────────────── + 'claude-3.5-sonnet': 'claude-sonnet-4.6', // retired 2025-11-06 + 'claude-3-opus': 'claude-opus-4.6', // retired + 'claude-3-sonnet': 'claude-sonnet-4.6', // retired + 'claude-opus-4': 'claude-opus-4.6', // retired 2025-10-23 + 'claude-4-opus': 'claude-opus-4.6', // retired + 'claude-opus-4.1': 'claude-opus-4.6', // retired 2026-02-17 + 'gpt-4': 'gpt-4.1', // legacy + 'gpt-4-turbo': 'gpt-4.1', // legacy + 'gpt-4o-mini': 'gpt-5-mini', // legacy + 'gpt-3.5-turbo': 'gpt-4.1', // legacy + 'gpt-5': 'gpt-5.2', // retired 2026-02-17 + 'gpt-5-codex': 'gpt-5.2-codex', // retired 2026-02-17 + 'o1': 'gpt-5-mini', // retired 2025-10-23 + 'o1-preview': 'gpt-5-mini', // retired 2025-10-23 + 'o1-mini': 'gpt-5-mini', // retired 2025-10-23 + 'o3': 'gpt-5.2', // retired 2025-10-23 + 'o3-mini': 'gpt-5-mini', // retired 2025-10-23 + 'o4-mini': 'gpt-5-mini', // retired 2025-10-23 + 'gemini-2.0-flash': 'gemini-2.5-pro', // retired 2025-10-23 + 'gemini-3-pro-preview': 'gemini-3-pro', // alias + 'gemini-3-flash-preview': 'gemini-3-flash', // alias + + // ── Default ───────────────────────────────────────────────────── + 'default': 'gpt-4o' }; export function mapToCopilotModel(requestedModel: string): string { From 1f746571ca21bb1ad0976747062c1a81e809dca9 Mon Sep 17 00:00:00 2001 From: Youssef Adel Date: Mon, 23 Feb 2026 05:11:34 +0200 Subject: [PATCH 15/16] fix: correct wording in development script output for clarity --- dev.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev.ps1 b/dev.ps1 index cc52a4e..5949ab5 100644 --- a/dev.ps1 +++ b/dev.ps1 @@ -20,7 +20,7 @@ $ErrorActionPreference = "Stop" Set-Location $PSScriptRoot Write-Host "`n=== github-copilot-proxy | dev mode ===" -ForegroundColor Cyan -Write-Host "Watching src/ for changes — auto-rebuild & restart`n" -ForegroundColor DarkGray +Write-Host "Watching src/ for changes - auto-rebuild and restart`n" -ForegroundColor DarkGray # ── 1. Initial build ──────────────────────────────────────────────── Write-Host "[1/2] Building project..." -ForegroundColor Yellow From 05a747a7d5779cc13b7b5abb918a36d7f2f0a8d1 Mon Sep 17 00:00:00 2001 From: Youssef Adel Date: Mon, 23 Feb 2026 05:12:33 +0200 Subject: [PATCH 16/16] refactor: simplify development script by removing redundant build steps --- dev.ps1 | 74 +++++---------------------------------------------------- 1 file changed, 6 insertions(+), 68 deletions(-) diff --git a/dev.ps1 b/dev.ps1 index 5949ab5..d4d982b 100644 --- a/dev.ps1 +++ b/dev.ps1 @@ -5,8 +5,7 @@ .DESCRIPTION Uses Node --watch to monitor source files. On any change the process - is automatically restarted. The script first does a full build so that - dist/ is up-to-date, then launches with --watch. + is automatically restarted with a fresh build. .EXAMPLE .\dev.ps1 @@ -22,71 +21,10 @@ Set-Location $PSScriptRoot Write-Host "`n=== github-copilot-proxy | dev mode ===" -ForegroundColor Cyan Write-Host "Watching src/ for changes - auto-rebuild and restart`n" -ForegroundColor DarkGray -# ── 1. Initial build ──────────────────────────────────────────────── -Write-Host "[1/2] Building project..." -ForegroundColor Yellow -npm run build -if ($LASTEXITCODE -ne 0) { - Write-Host "Build failed. Fix errors above and re-run." -ForegroundColor Red - exit 1 -} -Write-Host "[1/2] Build OK`n" -ForegroundColor Green - -# ── 2. Start with --watch ─────────────────────────────────────────── -# Node >= 22 has stable --watch support. We watch the src/ directory -# so that any .ts / .html change triggers a restart. The before-restart -# hook re-runs the build so dist/ stays current. -Write-Host "[2/2] Starting server in watch mode...`n" -ForegroundColor Yellow - -$env:NODE_ENV = "development" +# Set environment +$env:NODE_ENV = "development" if ($Verbose) { $env:LOG_LEVEL = "debug" } -# We use a small wrapper: on each restart we rebuild then launch. -# Node's --watch-path lets us scope what triggers restarts. -$watchPaths = @( - "--watch-path=src" -) - -# Build the command -# --watch restarts the *entry* process on file change. -# We chain: build first, then start from dist/. -$nodeBin = "node" -$args = @( - "--watch" - "--watch-path=src" - "--watch-preserve-output" - "-e" - # Inline JS: run build, then import the app - "const{execSync}=require('child_process');try{execSync('npm run build',{stdio:'inherit'})}catch{process.exit(1)};import('./dist/index.js')" -) - -# node --watch does not work well with inline -e + dynamic import in all -# versions, so instead we use a tiny loader script. -$loaderContent = @" -import { execSync } from 'child_process'; - -// Rebuild on every (re)start so dist/ is up-to-date -try { - execSync('npx tsc && node -e "require(''fs'').cpSync(''src/public'',''dist/public'',{recursive:true})"', { - stdio: 'inherit', - cwd: import.meta.dirname ?? '.', - }); -} catch { - console.error('\x1b[31mBuild failed — waiting for next change...\x1b[0m'); - // Keep process alive so --watch can restart on next save - await new Promise(() => {}); -} - -// Start the actual server -await import('./dist/index.js'); -"@ - -$loaderPath = Join-Path $PSScriptRoot ".dev-entry.mjs" -Set-Content -Path $loaderPath -Value $loaderContent -Encoding UTF8 - -try { - & $nodeBin --watch --watch-path=src --watch-preserve-output $loaderPath -} -finally { - # Clean up the temp loader - if (Test-Path $loaderPath) { Remove-Item $loaderPath -Force } -} +# Launch Node with --watch pointed at src/ +# .dev-entry.mjs handles: tsc build -> copy public -> start server +node --watch --watch-path=src --watch-preserve-output .dev-entry.mjs