diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 60144add1..9ac01bfa6 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -16,32 +16,47 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 + - uses: actions/checkout@v6 + + - name: Install pnpm + uses: pnpm/action-setup@v4 + id: pnpm-install + with: + run_install: false + - uses: actions/setup-node@v6 with: node-version: 24 - cache: npm + cache: pnpm + cache-dependency-path: pnpm-lock.yaml - - run: npm ci - - run: npm run check - - run: npm run build + - run: pnpm install + - run: pnpm run check:all + - run: pnpm run build:all test: runs-on: ubuntu-latest strategy: fail-fast: false matrix: - node-version: [18, 24] + node-version: [22, 24] steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 + - uses: actions/checkout@v6 + + - name: Install pnpm + uses: pnpm/action-setup@v4 + id: pnpm-install + with: + run_install: false + - uses: actions/setup-node@v6 with: node-version: ${{ matrix.node-version }} - cache: npm + cache: pnpm + cache-dependency-path: pnpm-lock.yaml + + - run: pnpm install - - run: npm ci - - run: npm test + - run: pnpm test:all publish: runs-on: ubuntu-latest @@ -55,13 +70,19 @@ jobs: steps: - uses: actions/checkout@v4 + + - name: Install pnpm + uses: pnpm/action-setup@v4 + id: pnpm-install + with: + run_install: false - uses: actions/setup-node@v4 with: node-version: 24 - cache: npm + cache: pnpm + cache-dependency-path: pnpm-lock.yaml registry-url: 'https://registry.npmjs.org' - - - run: npm ci + - run: pnpm install - name: Determine npm tag id: npm-tag @@ -84,6 +105,6 @@ jobs: echo "tag=" >> $GITHUB_OUTPUT fi - - run: npm publish --provenance --access public ${{ steps.npm-tag.outputs.tag }} + - run: pnpm publish --provenance --access public ${{ steps.npm-tag.outputs.tag }} env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 00ffd6efe..2a1e20c1e 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -1,6 +1,8 @@ name: Publish Any Commit + permissions: contents: read + on: pull_request: push: @@ -14,14 +16,31 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 + - uses: actions/checkout@v6 + + - name: Install pnpm + uses: pnpm/action-setup@v4 + with: + run_install: false + + - name: Setup Node.js + uses: actions/setup-node@v6 with: node-version: 24 - cache: npm + cache: pnpm + cache-dependency-path: pnpm-lock.yaml + registry-url: 'https://registry.npmjs.org' + + - name: Install dependencies + run: pnpm install + + - name: Build packages + run: pnpm run build:all + + - name: Publish preview for @modelcontextprotocol/sdk-client + working-directory: packages/client + run: npx pkg-pr-new publish - - run: npm ci - - name: Build - run: npm run build - - name: Publish + - name: Publish preview for @modelcontextprotocol/sdk-server + working-directory: packages/server run: npx pkg-pr-new publish diff --git a/common/eslint-config/eslint.config.mjs b/common/eslint-config/eslint.config.mjs new file mode 100644 index 000000000..0ceb926d4 --- /dev/null +++ b/common/eslint-config/eslint.config.mjs @@ -0,0 +1,63 @@ +// @ts-check + +import eslint from '@eslint/js'; +import tseslint from 'typescript-eslint'; +import eslintConfigPrettier from 'eslint-config-prettier/flat'; +import nodePlugin from 'eslint-plugin-n'; +import importPlugin from 'eslint-plugin-import'; +import { fileURLToPath } from 'node:url'; +import path from 'node:path'; +import simpleImportSortPlugin from 'eslint-plugin-simple-import-sort'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); + +export default tseslint.config( + eslint.configs.recommended, + ...tseslint.configs.recommended, + importPlugin.flatConfigs.recommended, + importPlugin.flatConfigs.typescript, + { + languageOptions: { + parserOptions: { + // Ensure consumers of this shared config get a stable tsconfig root + tsconfigRootDir: __dirname + } + }, + linterOptions: { + reportUnusedDisableDirectives: false + }, + plugins: { + n: nodePlugin, + 'simple-import-sort': simpleImportSortPlugin + }, + settings: { + 'import/resolver': { + typescript: { + // Let the TS resolver handle NodeNext-style imports like "./foo.js" + extensions: ['.js', '.jsx', '.ts', '.tsx', '.d.ts'], + // Use the tsconfig in each package root (when running ESLint from that package) + project: 'tsconfig.json' + } + } + }, + rules: { + '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }], + 'n/prefer-node-protocol': 'error', + '@typescript-eslint/consistent-type-imports': ['error', { disallowTypeAnnotations: false }], + 'simple-import-sort/imports': 'warn', + 'simple-import-sort/exports': 'warn' + } + }, + { + // Ignore generated protocol types everywhere + ignores: ['**/spec.types.ts'] + }, + { + files: ['src/client/**/*.ts', 'src/server/**/*.ts'], + ignores: ['**/*.test.ts'], + rules: { + 'no-console': 'error' + } + }, + eslintConfigPrettier +); diff --git a/common/eslint-config/package.json b/common/eslint-config/package.json new file mode 100644 index 000000000..5f67d650e --- /dev/null +++ b/common/eslint-config/package.json @@ -0,0 +1,36 @@ +{ + "name": "@modelcontextprotocol/eslint-config", + "private": true, + "main": "eslint.config.mjs", + "type": "module", + "exports": { + ".": "./eslint.config.mjs" + }, + "dependencies": { + "typescript": "catalog:" + }, + "repository": { + "type": "git", + "url": "https://github.com/modelcontextprotocol/typescript-sdk.git" + }, + "bugs": { + "url": "https://github.com/modelcontextprotocol/typescript-sdk/issues" + }, + "homepage": "https://github.com/modelcontextprotocol/typescript-sdk/tree/develop/common/eslint-config", + "publishConfig": { + "registry": "https://npm.pkg.github.com/" + }, + "version": "2.0.0", + "devDependencies": { + "@eslint/js": "^9.39.1", + "eslint": "^9.8.0", + "eslint-config-prettier": "^10.1.8", + "eslint-import-resolver-typescript": "^4.4.4", + "eslint-plugin-import": "^2.32.0", + "eslint-plugin-n": "^17.23.1", + "eslint-plugin-simple-import-sort": "^12.1.1", + "prettier": "3.6.2", + "typescript": "^5.5.4", + "typescript-eslint": "^8.48.1" + } +} diff --git a/common/tsconfig/package.json b/common/tsconfig/package.json new file mode 100644 index 000000000..bbb1f2ebd --- /dev/null +++ b/common/tsconfig/package.json @@ -0,0 +1,21 @@ +{ + "name": "@modelcontextprotocol/tsconfig", + "private": true, + "main": "tsconfig.json", + "type": "module", + "dependencies": { + "typescript": "catalog:" + }, + "repository": { + "type": "git", + "url": "https://github.com/modelcontextprotocol/typescript-sdk.git" + }, + "bugs": { + "url": "https://github.com/modelcontextprotocol/typescript-sdk/issues" + }, + "homepage": "https://github.com/modelcontextprotocol/typescript-sdk/tree/develop/common/ts-config", + "publishConfig": { + "registry": "https://npm.pkg.github.com/" + }, + "version": "2.0.0" +} diff --git a/tsconfig.json b/common/tsconfig/tsconfig.json similarity index 51% rename from tsconfig.json rename to common/tsconfig/tsconfig.json index c7346e4fe..bb020a0f7 100644 --- a/tsconfig.json +++ b/common/tsconfig/tsconfig.json @@ -1,8 +1,18 @@ { "compilerOptions": { - "target": "es2018", - "module": "Node16", - "moduleResolution": "Node16", + "target": "esnext", + "lib": ["esnext"], + "module": "NodeNext", + "moduleResolution": "NodeNext", + "allowSyntheticDefaultImports": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedIndexedAccess": true, + "noImplicitOverride": true, + "experimentalDecorators": true, + "emitDecoratorMetadata": true, + "libReplacement": false, + "noImplicitReturns": true, + "incremental": true, "declaration": true, "declarationMap": true, "sourceMap": true, @@ -17,7 +27,5 @@ "pkce-challenge": ["./node_modules/pkce-challenge/dist/index.node"] }, "types": ["node", "vitest/globals"] - }, - "include": ["src/**/*", "test/**/*"], - "exclude": ["node_modules", "dist"] + } } diff --git a/common/vitest-config/package.json b/common/vitest-config/package.json new file mode 100644 index 000000000..8dc9d0368 --- /dev/null +++ b/common/vitest-config/package.json @@ -0,0 +1,28 @@ +{ + "name": "@modelcontextprotocol/vitest-config", + "private": true, + "main": "vitest.config.mjs", + "type": "module", + "exports": { + ".": "./vitest.config.js" + }, + "dependencies": { + "typescript": "catalog:" + }, + "repository": { + "type": "git", + "url": "https://github.com/modelcontextprotocol/typescript-sdk.git" + }, + "bugs": { + "url": "https://github.com/modelcontextprotocol/typescript-sdk/issues" + }, + "homepage": "https://github.com/modelcontextprotocol/typescript-sdk/tree/develop/common/vitest-config", + "publishConfig": { + "registry": "https://npm.pkg.github.com/" + }, + "version": "2.0.0", + "devDependencies": { + "@modelcontextprotocol/tsconfig": "workspace:^", + "vite-tsconfig-paths": "^5.1.4" + } +} diff --git a/common/vitest-config/tsconfig.json b/common/vitest-config/tsconfig.json new file mode 100644 index 000000000..6e58368d2 --- /dev/null +++ b/common/vitest-config/tsconfig.json @@ -0,0 +1,8 @@ +{ + "include": ["./"], + "extends": "@modelcontextprotocol/tsconfig", + "compilerOptions": { + "noEmit": true, + "allowJs": true + } +} diff --git a/common/vitest-config/vitest.config.js b/common/vitest-config/vitest.config.js new file mode 100644 index 000000000..9d1a094e7 --- /dev/null +++ b/common/vitest-config/vitest.config.js @@ -0,0 +1,25 @@ +import { defineConfig } from 'vitest/config'; +import tsconfigPaths from 'vite-tsconfig-paths'; +import path from 'node:path'; +import url from 'node:url'; + +const ignorePatterns = ['**/dist/**']; +const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); + +export default defineConfig({ + test: { + globals: true, + environment: 'node', + include: ['test/**/*.test.ts'], + exclude: ignorePatterns, + deps: { + moduleDirectories: ['node_modules', path.resolve(__dirname, '../../packages'), path.resolve(__dirname, '../../common')] + }, + poolOptions: { + threads: { + useAtomics: true + } + } + }, + plugins: [tsconfigPaths()] +}); diff --git a/eslint.config.mjs b/eslint.config.mjs deleted file mode 100644 index fdfab80e2..000000000 --- a/eslint.config.mjs +++ /dev/null @@ -1,34 +0,0 @@ -// @ts-check - -import eslint from '@eslint/js'; -import tseslint from 'typescript-eslint'; -import eslintConfigPrettier from 'eslint-config-prettier/flat'; -import nodePlugin from 'eslint-plugin-n'; - -export default tseslint.config( - eslint.configs.recommended, - ...tseslint.configs.recommended, - { - linterOptions: { - reportUnusedDisableDirectives: false - }, - plugins: { - n: nodePlugin - }, - rules: { - '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }], - 'n/prefer-node-protocol': 'error' - } - }, - { - ignores: ['src/spec.types.ts'] - }, - { - files: ['src/client/**/*.ts', 'src/server/**/*.ts'], - ignores: ['**/*.test.ts'], - rules: { - 'no-console': 'error' - } - }, - eslintConfigPrettier -); diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index d32963a73..000000000 --- a/package-lock.json +++ /dev/null @@ -1,4578 +0,0 @@ -{ - "name": "@modelcontextprotocol/sdk", - "version": "1.24.3", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "@modelcontextprotocol/sdk", - "version": "1.24.3", - "license": "MIT", - "dependencies": { - "ajv": "^8.17.1", - "ajv-formats": "^3.0.1", - "content-type": "^1.0.5", - "cors": "^2.8.5", - "cross-spawn": "^7.0.5", - "eventsource": "^3.0.2", - "eventsource-parser": "^3.0.0", - "express": "^5.0.1", - "express-rate-limit": "^7.5.0", - "jose": "^6.1.1", - "json-schema-typed": "^8.0.2", - "pkce-challenge": "^5.0.0", - "raw-body": "^3.0.0", - "zod": "^3.25 || ^4.0", - "zod-to-json-schema": "^3.25.0" - }, - "devDependencies": { - "@cfworker/json-schema": "^4.1.1", - "@eslint/js": "^9.39.1", - "@types/content-type": "^1.1.8", - "@types/cors": "^2.8.17", - "@types/cross-spawn": "^6.0.6", - "@types/eventsource": "^1.1.15", - "@types/express": "^5.0.0", - "@types/express-serve-static-core": "^5.1.0", - "@types/node": "^22.12.0", - "@types/supertest": "^6.0.2", - "@types/ws": "^8.5.12", - "@typescript/native-preview": "^7.0.0-dev.20251103.1", - "eslint": "^9.8.0", - "eslint-config-prettier": "^10.1.8", - "eslint-plugin-n": "^17.23.1", - "prettier": "3.6.2", - "supertest": "^7.0.0", - "tsx": "^4.16.5", - "typescript": "^5.5.4", - "typescript-eslint": "^8.48.1", - "vitest": "^4.0.8", - "ws": "^8.18.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@cfworker/json-schema": "^4.1.1", - "zod": "^3.25 || ^4.0" - }, - "peerDependenciesMeta": { - "@cfworker/json-schema": { - "optional": true - }, - "zod": { - "optional": false - } - } - }, - "node_modules/@cfworker/json-schema": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/@cfworker/json-schema/-/json-schema-4.1.1.tgz", - "integrity": "sha512-gAmrUZSGtKc3AiBL71iNWxDsyUC5uMaKKGdvzYsBoTW/xi42JQHl7eKV2OYzCUqvc+D2RCcf7EXY2iCyFIk6og==", - "dev": true, - "license": "MIT" - }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.0.tgz", - "integrity": "sha512-O7vun9Sf8DFjH2UtqK8Ku3LkquL9SZL8OLY1T5NZkA34+wG3OQF7cl4Ql8vdNzM6fzBbYfLaiRLIOZ+2FOCgBQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.0.tgz", - "integrity": "sha512-PTyWCYYiU0+1eJKmw21lWtC+d08JDZPQ5g+kFyxP0V+es6VPPSUhM6zk8iImp2jbV6GwjX4pap0JFbUQN65X1g==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.0.tgz", - "integrity": "sha512-grvv8WncGjDSyUBjN9yHXNt+cq0snxXbDxy5pJtzMKGmmpPxeAmAhWxXI+01lU5rwZomDgD3kJwulEnhTRUd6g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.0.tgz", - "integrity": "sha512-m/ix7SfKG5buCnxasr52+LI78SQ+wgdENi9CqyCXwjVR2X4Jkz+BpC3le3AoBPYTC9NHklwngVXvbJ9/Akhrfg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.0.tgz", - "integrity": "sha512-mVwdUb5SRkPayVadIOI78K7aAnPamoeFR2bT5nszFUZ9P8UpK4ratOdYbZZXYSqPKMHfS1wdHCJk1P1EZpRdvw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.0.tgz", - "integrity": "sha512-DgDaYsPWFTS4S3nWpFcMn/33ZZwAAeAFKNHNa1QN0rI4pUjgqf0f7ONmXf6d22tqTY+H9FNdgeaAa+YIFUn2Rg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.0.tgz", - "integrity": "sha512-VN4ocxy6dxefN1MepBx/iD1dH5K8qNtNe227I0mnTRjry8tj5MRk4zprLEdG8WPyAPb93/e4pSgi1SoHdgOa4w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.0.tgz", - "integrity": "sha512-mrSgt7lCh07FY+hDD1TxiTyIHyttn6vnjesnPoVDNmDfOmggTLXRv8Id5fNZey1gl/V2dyVK1VXXqVsQIiAk+A==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.0.tgz", - "integrity": "sha512-vkB3IYj2IDo3g9xX7HqhPYxVkNQe8qTK55fraQyTzTX/fxaDtXiEnavv9geOsonh2Fd2RMB+i5cbhu2zMNWJwg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.0.tgz", - "integrity": "sha512-9QAQjTWNDM/Vk2bgBl17yWuZxZNQIF0OUUuPZRKoDtqF2k4EtYbpyiG5/Dk7nqeK6kIJWPYldkOcBqjXjrUlmg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.0.tgz", - "integrity": "sha512-43ET5bHbphBegyeqLb7I1eYn2P/JYGNmzzdidq/w0T8E2SsYL1U6un2NFROFRg1JZLTzdCoRomg8Rvf9M6W6Gg==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.0.tgz", - "integrity": "sha512-fC95c/xyNFueMhClxJmeRIj2yrSMdDfmqJnyOY4ZqsALkDrrKJfIg5NTMSzVBr5YW1jf+l7/cndBfP3MSDpoHw==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.0.tgz", - "integrity": "sha512-nkAMFju7KDW73T1DdH7glcyIptm95a7Le8irTQNO/qtkoyypZAnjchQgooFUDQhNAy4iu08N79W4T4pMBwhPwQ==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.0.tgz", - "integrity": "sha512-NhyOejdhRGS8Iwv+KKR2zTq2PpysF9XqY+Zk77vQHqNbo/PwZCzB5/h7VGuREZm1fixhs4Q/qWRSi5zmAiO4Fw==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.0.tgz", - "integrity": "sha512-5S/rbP5OY+GHLC5qXp1y/Mx//e92L1YDqkiBbO9TQOvuFXM+iDqUNG5XopAnXoRH3FjIUDkeGcY1cgNvnXp/kA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.0.tgz", - "integrity": "sha512-XM2BFsEBz0Fw37V0zU4CXfcfuACMrppsMFKdYY2WuTS3yi8O1nFOhil/xhKTmE1nPmVyvQJjJivgDT+xh8pXJA==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.0.tgz", - "integrity": "sha512-9yl91rHw/cpwMCNytUDxwj2XjFpxML0y9HAOH9pNVQDpQrBxHy01Dx+vaMu0N1CKa/RzBD2hB4u//nfc+Sd3Cw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.0.tgz", - "integrity": "sha512-RuG4PSMPFfrkH6UwCAqBzauBWTygTvb1nxWasEJooGSJ/NwRw7b2HOwyRTQIU97Hq37l3npXoZGYMy3b3xYvPw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.0.tgz", - "integrity": "sha512-jl+qisSB5jk01N5f7sPCsBENCOlPiS/xptD5yxOx2oqQfyourJwIKLRA2yqWdifj3owQZCL2sn6o08dBzZGQzA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.0.tgz", - "integrity": "sha512-21sUNbq2r84YE+SJDfaQRvdgznTD8Xc0oc3p3iW/a1EVWeNj/SdUCbm5U0itZPQYRuRTW20fPMWMpcrciH2EJw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.0.tgz", - "integrity": "sha512-2gwwriSMPcCFRlPlKx3zLQhfN/2WjJ2NSlg5TKLQOJdV0mSxIcYNTMhk3H3ulL/cak+Xj0lY1Ym9ysDV1igceg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.0.tgz", - "integrity": "sha512-bxI7ThgLzPrPz484/S9jLlvUAHYMzy6I0XiU1ZMeAEOBcS0VePBFxh1JjTQt3Xiat5b6Oh4x7UC7IwKQKIJRIg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.0.tgz", - "integrity": "sha512-ZUAc2YK6JW89xTbXvftxdnYy3m4iHIkDtK3CLce8wg8M2L+YZhIvO1DKpxrd0Yr59AeNNkTiic9YLf6FTtXWMw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.0.tgz", - "integrity": "sha512-eSNxISBu8XweVEWG31/JzjkIGbGIJN/TrRoiSVZwZ6pkC6VX4Im/WV2cz559/TXLcYbcrDN8JtKgd9DJVIo8GA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.0.tgz", - "integrity": "sha512-ZENoHJBxA20C2zFzh6AI4fT6RraMzjYw4xKWemRTRmRVtN9c5DcH9r/f2ihEkMjOW5eGgrwCslG/+Y/3bL+DHQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", - "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==", - "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/eslint-utils/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, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", - "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", - "dev": true, - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/config-array": { - "version": "0.21.1", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz", - "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/object-schema": "^2.1.7", - "debug": "^4.3.1", - "minimatch": "^3.1.2" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/config-helpers": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", - "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^0.17.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/core": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", - "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@types/json-schema": "^7.0.15" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz", - "integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^10.0.1", - "globals": "^14.0.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.1", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.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/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/js": { - "version": "9.39.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.1.tgz", - "integrity": "sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" - } - }, - "node_modules/@eslint/object-schema": { - "version": "2.1.7", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", - "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/plugin-kit": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", - "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^0.17.0", - "levn": "^0.4.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@humanfs/core": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", - "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanfs/node": { - "version": "0.16.7", - "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", - "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@humanfs/core": "^0.19.1", - "@humanwhocodes/retry": "^0.4.0" - }, - "engines": { - "node": ">=18.18.0" - } - }, - "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, - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/retry": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", - "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "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/@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/@paralleldrive/cuid2": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/@paralleldrive/cuid2/-/cuid2-2.2.2.tgz", - "integrity": "sha512-ZOBkgDwEdoYVlSeRbYYXs0S9MejQofiVYoTbKzy/6GQa39/q5tQU2IX46+shYnUkpEl3wc+J6wRlar7r2EK2xA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@noble/hashes": "^1.1.5" - } - }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.53.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.53.2.tgz", - "integrity": "sha512-yDPzwsgiFO26RJA4nZo8I+xqzh7sJTZIWQOxn+/XOdPE31lAvLIYCKqjV+lNH/vxE2L2iH3plKxDCRK6i+CwhA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.53.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.53.2.tgz", - "integrity": "sha512-k8FontTxIE7b0/OGKeSN5B6j25EuppBcWM33Z19JoVT7UTXFSo3D9CdU39wGTeb29NO3XxpMNauh09B+Ibw+9g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.53.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.53.2.tgz", - "integrity": "sha512-A6s4gJpomNBtJ2yioj8bflM2oogDwzUiMl2yNJ2v9E7++sHrSrsQ29fOfn5DM/iCzpWcebNYEdXpaK4tr2RhfQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.53.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.53.2.tgz", - "integrity": "sha512-e6XqVmXlHrBlG56obu9gDRPW3O3hLxpwHpLsBJvuI8qqnsrtSZ9ERoWUXtPOkY8c78WghyPHZdmPhHLWNdAGEw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.53.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.53.2.tgz", - "integrity": "sha512-v0E9lJW8VsrwPux5Qe5CwmH/CF/2mQs6xU1MF3nmUxmZUCHazCjLgYvToOk+YuuUqLQBio1qkkREhxhc656ViA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.53.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.53.2.tgz", - "integrity": "sha512-ClAmAPx3ZCHtp6ysl4XEhWU69GUB1D+s7G9YjHGhIGCSrsg00nEGRRZHmINYxkdoJehde8VIsDC5t9C0gb6yqA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.53.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.53.2.tgz", - "integrity": "sha512-EPlb95nUsz6Dd9Qy13fI5kUPXNSljaG9FiJ4YUGU1O/Q77i5DYFW5KR8g1OzTcdZUqQQ1KdDqsTohdFVwCwjqg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.53.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.53.2.tgz", - "integrity": "sha512-BOmnVW+khAUX+YZvNfa0tGTEMVVEerOxN0pDk2E6N6DsEIa2Ctj48FOMfNDdrwinocKaC7YXUZ1pHlKpnkja/Q==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.53.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.53.2.tgz", - "integrity": "sha512-Xt2byDZ+6OVNuREgBXr4+CZDJtrVso5woFtpKdGPhpTPHcNG7D8YXeQzpNbFRxzTVqJf7kvPMCub/pcGUWgBjA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.53.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.53.2.tgz", - "integrity": "sha512-+LdZSldy/I9N8+klim/Y1HsKbJ3BbInHav5qE9Iy77dtHC/pibw1SR/fXlWyAk0ThnpRKoODwnAuSjqxFRDHUQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.53.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.53.2.tgz", - "integrity": "sha512-8ms8sjmyc1jWJS6WdNSA23rEfdjWB30LH8Wqj0Cqvv7qSHnvw6kgMMXRdop6hkmGPlyYBdRPkjJnj3KCUHV/uQ==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.53.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.53.2.tgz", - "integrity": "sha512-3HRQLUQbpBDMmzoxPJYd3W6vrVHOo2cVW8RUo87Xz0JPJcBLBr5kZ1pGcQAhdZgX9VV7NbGNipah1omKKe23/g==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.53.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.53.2.tgz", - "integrity": "sha512-fMjKi+ojnmIvhk34gZP94vjogXNNUKMEYs+EDaB/5TG/wUkoeua7p7VCHnE6T2Tx+iaghAqQX8teQzcvrYpaQA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.53.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.53.2.tgz", - "integrity": "sha512-XuGFGU+VwUUV5kLvoAdi0Wz5Xbh2SrjIxCtZj6Wq8MDp4bflb/+ThZsVxokM7n0pcbkEr2h5/pzqzDYI7cCgLQ==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.53.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.53.2.tgz", - "integrity": "sha512-w6yjZF0P+NGzWR3AXWX9zc0DNEGdtvykB03uhonSHMRa+oWA6novflo2WaJr6JZakG2ucsyb+rvhrKac6NIy+w==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.53.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.53.2.tgz", - "integrity": "sha512-yo8d6tdfdeBArzC7T/PnHd7OypfI9cbuZzPnzLJIyKYFhAQ8SvlkKtKBMbXDxe1h03Rcr7u++nFS7tqXz87Gtw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.53.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.53.2.tgz", - "integrity": "sha512-ah59c1YkCxKExPP8O9PwOvs+XRLKwh/mV+3YdKqQ5AMQ0r4M4ZDuOrpWkUaqO7fzAHdINzV9tEVu8vNw48z0lA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.53.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.53.2.tgz", - "integrity": "sha512-4VEd19Wmhr+Zy7hbUsFZ6YXEiP48hE//KPLCSVNY5RMGX2/7HZ+QkN55a3atM1C/BZCGIgqN+xrVgtdak2S9+A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ] - }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.53.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.53.2.tgz", - "integrity": "sha512-IlbHFYc/pQCgew/d5fslcy1KEaYVCJ44G8pajugd8VoOEI8ODhtb/j8XMhLpwHCMB3yk2J07ctup10gpw2nyMA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.53.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.53.2.tgz", - "integrity": "sha512-lNlPEGgdUfSzdCWU176ku/dQRnA7W+Gp8d+cWv73jYrb8uT7HTVVxq62DUYxjbaByuf1Yk0RIIAbDzp+CnOTFg==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.53.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.53.2.tgz", - "integrity": "sha512-S6YojNVrHybQis2lYov1sd+uj7K0Q05NxHcGktuMMdIQ2VixGwAfbJ23NnlvvVV1bdpR2m5MsNBViHJKcA4ADw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.53.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.53.2.tgz", - "integrity": "sha512-k+/Rkcyx//P6fetPoLMb8pBeqJBNGx81uuf7iljX9++yNBVRDQgD04L+SVXmXmh5ZP4/WOp4mWF0kmi06PW2tA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@standard-schema/spec": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz", - "integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/body-parser": { - "version": "1.19.5", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", - "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/connect": "*", - "@types/node": "*" - } - }, - "node_modules/@types/chai": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", - "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/deep-eql": "*", - "assertion-error": "^2.0.1" - } - }, - "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, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/content-type": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/@types/content-type/-/content-type-1.1.8.tgz", - "integrity": "sha512-1tBhmVUeso3+ahfyaKluXe38p+94lovUZdoVfQ3OnJo9uJC42JT7CBoN3k9HYhAae+GwiBYmHu+N9FZhOG+2Pg==", - "dev": true - }, - "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.17", - "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz", - "integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/cross-spawn": { - "version": "6.0.6", - "resolved": "https://registry.npmjs.org/@types/cross-spawn/-/cross-spawn-6.0.6.tgz", - "integrity": "sha512-fXRhhUkG4H3TQk5dBhQ7m/JDdSNHKwR2BBia62lhwEIq9xGiQKLxd6LymNhn47SjXhsUEPmxi+PKw2OkW4LLjA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/deep-eql": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", - "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/eventsource": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/@types/eventsource/-/eventsource-1.1.15.tgz", - "integrity": "sha512-XQmGcbnxUNa06HR3VBVkc9+A2Vpi9ZyLJcdS5dwaQQ/4ZMWFO+5c90FnMUpbtMZwB/FChoYHwuVg8TvkECacTA==", - "dev": true - }, - "node_modules/@types/express": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.0.tgz", - "integrity": "sha512-DvZriSMehGHL1ZNLzi6MidnsDhUZM/x2pRdDIKdwbUNqqwHxMlRdkxtn6/EPKyqKpHqTl/4nRZsRNLpZxZRpPQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^5.0.0", - "@types/qs": "*", - "@types/serve-static": "*" - } - }, - "node_modules/@types/express-serve-static-core": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.1.0.tgz", - "integrity": "sha512-jnHMsrd0Mwa9Cf4IdOzbz543y4XJepXrbia2T4b6+spXC2We3t1y6K44D3mR8XMFSXMCf3/l7rCgddfx7UNVBA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*", - "@types/send": "*" - } - }, - "node_modules/@types/http-errors": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", - "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", - "dev": true - }, - "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 - }, - "node_modules/@types/node": { - "version": "22.19.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.1.tgz", - "integrity": "sha512-LCCV0HdSZZZb34qifBsyWlUmok6W7ouER+oQIGBScS8EsZsQbrtFTUrDX4hOl+CS6p7cnNC4td+qrSVGSCTUfQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.21.0" - } - }, - "node_modules/@types/qs": { - "version": "6.9.18", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.18.tgz", - "integrity": "sha512-kK7dgTYDyGqS+e2Q4aK9X3D7q234CIZ1Bv0q/7Z5IwRDoADNU81xXJK/YVyLbLTZCoIwUoDoffFeF+p/eIklAA==", - "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/send": { - "version": "0.17.4", - "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", - "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", - "dev": true, - "dependencies": { - "@types/mime": "^1", - "@types/node": "*" - } - }, - "node_modules/@types/serve-static": { - "version": "1.15.7", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", - "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", - "dev": true, - "dependencies": { - "@types/http-errors": "*", - "@types/node": "*", - "@types/send": "*" - } - }, - "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.2", - "resolved": "https://registry.npmjs.org/@types/supertest/-/supertest-6.0.2.tgz", - "integrity": "sha512-137ypx2lk/wTQbW6An6safu9hXmajAifU/s7szAHLN/FeIm5w7yR0Wkl9fdJMRSHwOn4HLAI0DaB2TOORuhPDg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/methods": "^1.1.4", - "@types/superagent": "^8.1.0" - } - }, - "node_modules/@types/ws": { - "version": "8.5.12", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.12.tgz", - "integrity": "sha512-3tPRkv1EtkDpzlgyKyI8pGsGZAGPEaXeu0DOj5DI25Ja91bdAYddYHbADRYVrZMRbfW+1l5YwXVDKohDJNQxkQ==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.48.1.tgz", - "integrity": "sha512-X63hI1bxl5ohelzr0LY5coufyl0LJNthld+abwxpCoo6Gq+hSqhKwci7MUWkXo67mzgUK6YFByhmaHmUcuBJmA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.48.1", - "@typescript-eslint/type-utils": "8.48.1", - "@typescript-eslint/utils": "8.48.1", - "@typescript-eslint/visitor-keys": "8.48.1", - "graphemer": "^1.4.0", - "ignore": "^7.0.0", - "natural-compare": "^1.4.0", - "ts-api-utils": "^2.1.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^8.48.1", - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", - "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "8.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.48.1.tgz", - "integrity": "sha512-PC0PDZfJg8sP7cmKe6L3QIL8GZwU5aRvUFedqSIpw3B+QjRSUZeeITC2M5XKeMXEzL6wccN196iy3JLwKNvDVA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@typescript-eslint/scope-manager": "8.48.1", - "@typescript-eslint/types": "8.48.1", - "@typescript-eslint/typescript-estree": "8.48.1", - "@typescript-eslint/visitor-keys": "8.48.1", - "debug": "^4.3.4" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/project-service": { - "version": "8.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.48.1.tgz", - "integrity": "sha512-HQWSicah4s9z2/HifRPQ6b6R7G+SBx64JlFQpgSSHWPKdvCZX57XCbszg/bapbRsOEv42q5tayTYcEFpACcX1w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.48.1", - "@typescript-eslint/types": "^8.48.1", - "debug": "^4.3.4" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "8.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.48.1.tgz", - "integrity": "sha512-rj4vWQsytQbLxC5Bf4XwZ0/CKd362DkWMUkviT7DCS057SK64D5lH74sSGzhI6PDD2HCEq02xAP9cX68dYyg1w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.48.1", - "@typescript-eslint/visitor-keys": "8.48.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.48.1.tgz", - "integrity": "sha512-k0Jhs4CpEffIBm6wPaCXBAD7jxBtrHjrSgtfCjUvPp9AZ78lXKdTR8fxyZO5y4vWNlOvYXRtngSZNSn+H53Jkw==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "8.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.48.1.tgz", - "integrity": "sha512-1jEop81a3LrJQLTf/1VfPQdhIY4PlGDBc/i67EVWObrtvcziysbLN3oReexHOM6N3jyXgCrkBsZpqwH0hiDOQg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.48.1", - "@typescript-eslint/typescript-estree": "8.48.1", - "@typescript-eslint/utils": "8.48.1", - "debug": "^4.3.4", - "ts-api-utils": "^2.1.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/types": { - "version": "8.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.48.1.tgz", - "integrity": "sha512-+fZ3LZNeiELGmimrujsDCT4CRIbq5oXdHe7chLiW8qzqyPMnn1puNstCrMNVAqwcl2FdIxkuJ4tOs/RFDBVc/Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.48.1.tgz", - "integrity": "sha512-/9wQ4PqaefTK6POVTjJaYS0bynCgzh6ClJHGSBj06XEHjkfylzB+A3qvyaXnErEZSaxhIo4YdyBgq6j4RysxDg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/project-service": "8.48.1", - "@typescript-eslint/tsconfig-utils": "8.48.1", - "@typescript-eslint/types": "8.48.1", - "@typescript-eslint/visitor-keys": "8.48.1", - "debug": "^4.3.4", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "tinyglobby": "^0.2.15", - "ts-api-utils": "^2.1.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/typescript-estree/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/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "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/@typescript-eslint/utils": { - "version": "8.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.48.1.tgz", - "integrity": "sha512-fAnhLrDjiVfey5wwFRwrweyRlCmdz5ZxXz2G/4cLn0YDLjTapmN4gcCsTBR1N2rWnZSDeWpYtgLDsJt+FpmcwA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.7.0", - "@typescript-eslint/scope-manager": "8.48.1", - "@typescript-eslint/types": "8.48.1", - "@typescript-eslint/typescript-estree": "8.48.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.48.1.tgz", - "integrity": "sha512-BmxxndzEWhE4TIEEMBs8lP3MBWN3jFPs/p6gPm/wkv02o41hI6cq9AuSmGAaTTHPtA1FTi2jBre4A9rm5ZmX+Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.48.1", - "eslint-visitor-keys": "^4.2.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript/native-preview": { - "version": "7.0.0-dev.20251103.1", - "resolved": "https://registry.npmjs.org/@typescript/native-preview/-/native-preview-7.0.0-dev.20251103.1.tgz", - "integrity": "sha512-Pcyltv+XIbaCoRaD3btY3qu+B1VzvEgNGlq1lM0O11QTPRLHyoEfvtLqyPKuSDgD90gDbtCPGUppVkpQouLBVQ==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsgo": "bin/tsgo.js" - }, - "optionalDependencies": { - "@typescript/native-preview-darwin-arm64": "7.0.0-dev.20251103.1", - "@typescript/native-preview-darwin-x64": "7.0.0-dev.20251103.1", - "@typescript/native-preview-linux-arm": "7.0.0-dev.20251103.1", - "@typescript/native-preview-linux-arm64": "7.0.0-dev.20251103.1", - "@typescript/native-preview-linux-x64": "7.0.0-dev.20251103.1", - "@typescript/native-preview-win32-arm64": "7.0.0-dev.20251103.1", - "@typescript/native-preview-win32-x64": "7.0.0-dev.20251103.1" - } - }, - "node_modules/@typescript/native-preview-darwin-arm64": { - "version": "7.0.0-dev.20251103.1", - "resolved": "https://registry.npmjs.org/@typescript/native-preview-darwin-arm64/-/native-preview-darwin-arm64-7.0.0-dev.20251103.1.tgz", - "integrity": "sha512-yqUxUts3zpxy0x+Rk/9VC+ZiwzXTiuNpgLbhLAR1inFxuk0kTM8xoQERaIk+DUn6guEmRiCzOw23aJ9u6E+GfA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@typescript/native-preview-darwin-x64": { - "version": "7.0.0-dev.20251103.1", - "resolved": "https://registry.npmjs.org/@typescript/native-preview-darwin-x64/-/native-preview-darwin-x64-7.0.0-dev.20251103.1.tgz", - "integrity": "sha512-jboMuar6TgvnnOZk8t/X2gZp4TUtsP9xtUnLEMEHRPWK3LFBJpjDFRUH70vOpW9hWIKYajlkF8JutclCPX5sBQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@typescript/native-preview-linux-arm": { - "version": "7.0.0-dev.20251103.1", - "resolved": "https://registry.npmjs.org/@typescript/native-preview-linux-arm/-/native-preview-linux-arm-7.0.0-dev.20251103.1.tgz", - "integrity": "sha512-QY+0W9TPxHub8vSFjemo3txSpCNGw3LqnrLKKlGUIuLW+Ohproo+o7Fq21dksPQ4g0NDWY19qlm/36QhsXKRNQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@typescript/native-preview-linux-arm64": { - "version": "7.0.0-dev.20251103.1", - "resolved": "https://registry.npmjs.org/@typescript/native-preview-linux-arm64/-/native-preview-linux-arm64-7.0.0-dev.20251103.1.tgz", - "integrity": "sha512-PZewTo76n2chP8o0Fwq2543jVVSY7aiZMBsapB82+w/XecFuCQtFRYNN02x6pjHeVjgv5fcWS3+LzHa1zv10qw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@typescript/native-preview-linux-x64": { - "version": "7.0.0-dev.20251103.1", - "resolved": "https://registry.npmjs.org/@typescript/native-preview-linux-x64/-/native-preview-linux-x64-7.0.0-dev.20251103.1.tgz", - "integrity": "sha512-wdFUmmz5XFUvWQ54l3f8ODah86b6Z4FnG9gndjOdYRY2FGDCOdmeoBqLHDiGUIzTHr5FMMyz2EfScN+qtUh4Dw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@typescript/native-preview-win32-arm64": { - "version": "7.0.0-dev.20251103.1", - "resolved": "https://registry.npmjs.org/@typescript/native-preview-win32-arm64/-/native-preview-win32-arm64-7.0.0-dev.20251103.1.tgz", - "integrity": "sha512-A00+b8mbwJ4RFwXZN4vNcIBGZcdBCFm23lBhw8uaUgLY1Ot81FZvJE3YZcbRrZwEiyrwd3hAMdnDBWUwMA9YqA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@typescript/native-preview-win32-x64": { - "version": "7.0.0-dev.20251103.1", - "resolved": "https://registry.npmjs.org/@typescript/native-preview-win32-x64/-/native-preview-win32-x64-7.0.0-dev.20251103.1.tgz", - "integrity": "sha512-25Pqk65M3fjQdsnwBLym5ALSdQlQAqHKrzZOkIs1uFKxIfZ5s9658Kjfj2fiMX5m3imk9IqzpP+fvKbgP1plIw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@vitest/expect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.0.8.tgz", - "integrity": "sha512-Rv0eabdP/xjAHQGr8cjBm+NnLHNoL268lMDK85w2aAGLFoVKLd8QGnVon5lLtkXQCoYaNL0wg04EGnyKkkKhPA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@standard-schema/spec": "^1.0.0", - "@types/chai": "^5.2.2", - "@vitest/spy": "4.0.8", - "@vitest/utils": "4.0.8", - "chai": "^6.2.0", - "tinyrainbow": "^3.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/pretty-format": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.0.8.tgz", - "integrity": "sha512-qRrjdRkINi9DaZHAimV+8ia9Gq6LeGz2CgIEmMLz3sBDYV53EsnLZbJMR1q84z1HZCMsf7s0orDgZn7ScXsZKg==", - "dev": true, - "license": "MIT", - "dependencies": { - "tinyrainbow": "^3.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/runner": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.0.8.tgz", - "integrity": "sha512-mdY8Sf1gsM8hKJUQfiPT3pn1n8RF4QBcJYFslgWh41JTfrK1cbqY8whpGCFzBl45LN028g0njLCYm0d7XxSaQQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/utils": "4.0.8", - "pathe": "^2.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/snapshot": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.0.8.tgz", - "integrity": "sha512-Nar9OTU03KGiubrIOFhcfHg8FYaRaNT+bh5VUlNz8stFhCZPNrJvmZkhsr1jtaYvuefYFwK2Hwrq026u4uPWCw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/pretty-format": "4.0.8", - "magic-string": "^0.30.21", - "pathe": "^2.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/spy": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.0.8.tgz", - "integrity": "sha512-nvGVqUunyCgZH7kmo+Ord4WgZ7lN0sOULYXUOYuHr55dvg9YvMz3izfB189Pgp28w0vWFbEEfNc/c3VTrqrXeA==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/utils": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.0.8.tgz", - "integrity": "sha512-pdk2phO5NDvEFfUTxcTP8RFYjVj/kfLSPIN5ebP2Mu9kcIMeAQTbknqcFEyBcC4z2pJlJI9aS5UQjcYfhmKAow==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/pretty-format": "4.0.8", - "tinyrainbow": "^3.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/accepts": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", - "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", - "license": "MIT", - "dependencies": { - "mime-types": "^3.0.0", - "negotiator": "^1.0.0" - }, - "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/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-formats": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", - "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", - "license": "MIT", - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, - "node_modules/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, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "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/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/assertion-error": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", - "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - } - }, - "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/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 - }, - "node_modules/body-parser": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.1.tgz", - "integrity": "sha512-nfDwkulwiZYQIGwxdy0RUmowMhKcFVcYXUU7m4QlKYim1rUtg83xm2yjZ40QjDuc291AJjjeSc9b++AWHSgSHw==", - "license": "MIT", - "dependencies": { - "bytes": "^3.1.2", - "content-type": "^1.0.5", - "debug": "^4.4.3", - "http-errors": "^2.0.0", - "iconv-lite": "^0.7.0", - "on-finished": "^2.4.1", - "qs": "^6.14.0", - "raw-body": "^3.0.1", - "type-is": "^2.0.1" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "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/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "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.3", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.3.tgz", - "integrity": "sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "get-intrinsic": "^1.2.6" - }, - "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/chai": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.1.tgz", - "integrity": "sha512-p4Z49OGG5W/WBCPSS/dH3jQ73kD6tiMmUM+bckNK6Jr5JHMG3k9bg/BvKR8lKmtVBKmOiuVaV2ws8s9oSbwysg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "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, - "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/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, - "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 - }, - "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/content-disposition": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz", - "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==", - "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==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", - "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", - "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", - "license": "MIT", - "engines": { - "node": ">=6.6.0" - } - }, - "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.5", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", - "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", - "license": "MIT", - "dependencies": { - "object-assign": "^4", - "vary": "^1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/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 - }, - "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==", - "engines": { - "node": ">= 0.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/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/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/enhanced-resolve": { - "version": "5.18.3", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz", - "integrity": "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "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-module-lexer": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", - "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", - "dev": true, - "license": "MIT" - }, - "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/esbuild": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.0.tgz", - "integrity": "sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.0", - "@esbuild/android-arm": "0.25.0", - "@esbuild/android-arm64": "0.25.0", - "@esbuild/android-x64": "0.25.0", - "@esbuild/darwin-arm64": "0.25.0", - "@esbuild/darwin-x64": "0.25.0", - "@esbuild/freebsd-arm64": "0.25.0", - "@esbuild/freebsd-x64": "0.25.0", - "@esbuild/linux-arm": "0.25.0", - "@esbuild/linux-arm64": "0.25.0", - "@esbuild/linux-ia32": "0.25.0", - "@esbuild/linux-loong64": "0.25.0", - "@esbuild/linux-mips64el": "0.25.0", - "@esbuild/linux-ppc64": "0.25.0", - "@esbuild/linux-riscv64": "0.25.0", - "@esbuild/linux-s390x": "0.25.0", - "@esbuild/linux-x64": "0.25.0", - "@esbuild/netbsd-arm64": "0.25.0", - "@esbuild/netbsd-x64": "0.25.0", - "@esbuild/openbsd-arm64": "0.25.0", - "@esbuild/openbsd-x64": "0.25.0", - "@esbuild/sunos-x64": "0.25.0", - "@esbuild/win32-arm64": "0.25.0", - "@esbuild/win32-ia32": "0.25.0", - "@esbuild/win32-x64": "0.25.0" - } - }, - "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, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "9.39.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.1.tgz", - "integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.8.0", - "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.21.1", - "@eslint/config-helpers": "^0.4.2", - "@eslint/core": "^0.17.0", - "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.39.1", - "@eslint/plugin-kit": "^0.4.1", - "@humanfs/node": "^0.16.6", - "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.4.2", - "@types/estree": "^1.0.6", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.6", - "debug": "^4.3.2", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.4.0", - "eslint-visitor-keys": "^4.2.1", - "espree": "^10.4.0", - "esquery": "^1.5.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^8.0.0", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" - }, - "peerDependencies": { - "jiti": "*" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - } - } - }, - "node_modules/eslint-compat-utils": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/eslint-compat-utils/-/eslint-compat-utils-0.5.1.tgz", - "integrity": "sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "semver": "^7.5.4" - }, - "engines": { - "node": ">=12" - }, - "peerDependencies": { - "eslint": ">=6.0.0" - } - }, - "node_modules/eslint-config-prettier": { - "version": "10.1.8", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz", - "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", - "dev": true, - "license": "MIT", - "bin": { - "eslint-config-prettier": "bin/cli.js" - }, - "funding": { - "url": "https://opencollective.com/eslint-config-prettier" - }, - "peerDependencies": { - "eslint": ">=7.0.0" - } - }, - "node_modules/eslint-plugin-es-x": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-es-x/-/eslint-plugin-es-x-7.8.0.tgz", - "integrity": "sha512-7Ds8+wAAoV3T+LAKeu39Y5BzXCrGKrcISfgKEqTS4BDN8SFEDQd0S43jiQ8vIa3wUKD07qitZdfzlenSi8/0qQ==", - "dev": true, - "funding": [ - "https://github.com/sponsors/ota-meshi", - "https://opencollective.com/eslint" - ], - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.1.2", - "@eslint-community/regexpp": "^4.11.0", - "eslint-compat-utils": "^0.5.1" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": ">=8" - } - }, - "node_modules/eslint-plugin-n": { - "version": "17.23.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-17.23.1.tgz", - "integrity": "sha512-68PealUpYoHOBh332JLLD9Sj7OQUDkFpmcfqt8R9sySfFSeuGJjMTJQvCRRB96zO3A/PELRLkPrzsHmzEFQQ5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.5.0", - "enhanced-resolve": "^5.17.1", - "eslint-plugin-es-x": "^7.8.0", - "get-tsconfig": "^4.8.1", - "globals": "^15.11.0", - "globrex": "^0.1.2", - "ignore": "^5.3.2", - "semver": "^7.6.3", - "ts-declaration-location": "^1.0.6" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - }, - "peerDependencies": { - "eslint": ">=8.23.0" - } - }, - "node_modules/eslint-plugin-n/node_modules/globals": { - "version": "15.15.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-15.15.0.tgz", - "integrity": "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint-scope": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", - "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.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/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/espree": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", - "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^8.15.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.2.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esquery": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", - "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", - "dev": true, - "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, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "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": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.2.tgz", - "integrity": "sha512-YolzkJNxsTL3tCJMWFxpxtG2sCjbZ4LQUBUrkdaJK0ub0p6lmJt+2+1SwhKjLc652lpH9L/79Ptez972H9tphw==", - "license": "MIT", - "dependencies": { - "eventsource-parser": "^3.0.0" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/eventsource-parser": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.0.tgz", - "integrity": "sha512-T1C0XCUimhxVQzW4zFipdx0SficT651NnkR0ZSH3yQwh+mFMdLfgjABVi4YtMTtaL4s168593DaoaRLMqryavA==", - "license": "MIT", - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/expect-type": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.2.tgz", - "integrity": "sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/express": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", - "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", - "license": "MIT", - "peer": true, - "dependencies": { - "accepts": "^2.0.0", - "body-parser": "^2.2.1", - "content-disposition": "^1.0.0", - "content-type": "^1.0.5", - "cookie": "^0.7.1", - "cookie-signature": "^1.2.1", - "debug": "^4.4.0", - "depd": "^2.0.0", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "etag": "^1.8.1", - "finalhandler": "^2.1.0", - "fresh": "^2.0.0", - "http-errors": "^2.0.0", - "merge-descriptors": "^2.0.0", - "mime-types": "^3.0.0", - "on-finished": "^2.4.1", - "once": "^1.4.0", - "parseurl": "^1.3.3", - "proxy-addr": "^2.0.7", - "qs": "^6.14.0", - "range-parser": "^1.2.1", - "router": "^2.2.0", - "send": "^1.1.0", - "serve-static": "^2.2.0", - "statuses": "^2.0.1", - "type-is": "^2.0.1", - "vary": "^1.1.2" - }, - "engines": { - "node": ">= 18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/express-rate-limit": { - "version": "7.5.1", - "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-7.5.1.tgz", - "integrity": "sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw==", - "license": "MIT", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://github.com/sponsors/express-rate-limit" - }, - "peerDependencies": { - "express": ">= 4.11" - } - }, - "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==" - }, - "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 - }, - "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 - }, - "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/fast-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", - "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/file-entry-cache": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", - "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", - "dev": true, - "dependencies": { - "flat-cache": "^4.0.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/finalhandler": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", - "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", - "license": "MIT", - "dependencies": { - "debug": "^4.4.0", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "on-finished": "^2.4.1", - "parseurl": "^1.3.3", - "statuses": "^2.0.1" - }, - "engines": { - "node": ">= 18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "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, - "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": "4.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", - "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", - "dev": true, - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.4" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/flatted": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", - "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", - "dev": true - }, - "node_modules/form-data": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", - "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", - "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/form-data/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==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/form-data/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==", - "dev": true, - "license": "MIT", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/formidable": { - "version": "3.5.4", - "resolved": "https://registry.npmjs.org/formidable/-/formidable-3.5.4.tgz", - "integrity": "sha512-YikH+7CUTOtP44ZTnUhR7Ic2UASBPOqmaRkRKxRbywPTe5VxF7RRCck4af9wutiZ/QKM5nME9Bie2fFaPz5Gug==", - "dev": true, - "license": "MIT", - "dependencies": { - "@paralleldrive/cuid2": "^2.2.2", - "dezalgo": "^1.0.4", - "once": "^1.4.0" - }, - "engines": { - "node": ">=14.0.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==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", - "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "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, - "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==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-intrinsic": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.7.tgz", - "integrity": "sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "function-bind": "^1.1.2", - "get-proto": "^1.0.0", - "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-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-tsconfig": { - "version": "4.8.1", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.8.1.tgz", - "integrity": "sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==", - "dev": true, - "dependencies": { - "resolve-pkg-maps": "^1.0.0" - }, - "funding": { - "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" - } - }, - "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, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/globals": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globrex": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", - "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", - "dev": true, - "license": "MIT" - }, - "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/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, - "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==", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "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/iconv-lite": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz", - "integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==", - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true, - "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/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "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==", - "engines": { - "node": ">= 0.10" - } - }, - "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, - "engines": { - "node": ">=0.10.0" - } - }, - "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, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-promise": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", - "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", - "license": "MIT" - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" - }, - "node_modules/jose": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/jose/-/jose-6.1.1.tgz", - "integrity": "sha512-GWSqjfOPf4cWOkBzw5THBjtGPhXKqYnfRBzh4Ni+ArTrQQ9unvmsA3oFLqaYKoKe5sjWmGu5wVKg9Ft1i+LQfg==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/panva" - } - }, - "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/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 - }, - "node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "license": "MIT" - }, - "node_modules/json-schema-typed": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-8.0.2.tgz", - "integrity": "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==", - "license": "BSD-2-Clause" - }, - "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 - }, - "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, - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "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, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "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, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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 - }, - "node_modules/magic-string": { - "version": "0.30.21", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", - "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.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": "1.1.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", - "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/merge-descriptors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", - "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "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/mime-db": { - "version": "1.54.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", - "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", - "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", - "license": "MIT", - "dependencies": { - "mime-db": "^1.54.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "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/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, - "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "node_modules/negotiator": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", - "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "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==", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "dev": true, - "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, - "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, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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/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, - "engines": { - "node": ">=8" - } - }, - "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==", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-to-regexp": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz", - "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==", - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/pathe": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", - "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", - "dev": true, - "license": "MIT" - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true - }, - "node_modules/pkce-challenge": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.0.tgz", - "integrity": "sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ==", - "license": "MIT", - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/postcss": { - "version": "8.5.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", - "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "nanoid": "^3.3.11", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/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, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prettier": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", - "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", - "dev": true, - "license": "MIT", - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "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==", - "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/qs": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", - "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", - "license": "BSD-3-Clause", - "dependencies": { - "side-channel": "^1.1.0" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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": "3.0.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", - "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", - "license": "MIT", - "dependencies": { - "bytes": "~3.1.2", - "http-errors": "~2.0.1", - "iconv-lite": "~0.7.0", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve-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/resolve-pkg-maps": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", - "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", - "dev": true, - "funding": { - "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" - } - }, - "node_modules/rollup": { - "version": "4.53.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.53.2.tgz", - "integrity": "sha512-MHngMYwGJVi6Fmnk6ISmnk7JAHRNF0UkuucA0CUW3N3a4KnONPEZz+vUanQP/ZC/iY1Qkf3bwPWzyY84wEks1g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "1.0.8" - }, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.53.2", - "@rollup/rollup-android-arm64": "4.53.2", - "@rollup/rollup-darwin-arm64": "4.53.2", - "@rollup/rollup-darwin-x64": "4.53.2", - "@rollup/rollup-freebsd-arm64": "4.53.2", - "@rollup/rollup-freebsd-x64": "4.53.2", - "@rollup/rollup-linux-arm-gnueabihf": "4.53.2", - "@rollup/rollup-linux-arm-musleabihf": "4.53.2", - "@rollup/rollup-linux-arm64-gnu": "4.53.2", - "@rollup/rollup-linux-arm64-musl": "4.53.2", - "@rollup/rollup-linux-loong64-gnu": "4.53.2", - "@rollup/rollup-linux-ppc64-gnu": "4.53.2", - "@rollup/rollup-linux-riscv64-gnu": "4.53.2", - "@rollup/rollup-linux-riscv64-musl": "4.53.2", - "@rollup/rollup-linux-s390x-gnu": "4.53.2", - "@rollup/rollup-linux-x64-gnu": "4.53.2", - "@rollup/rollup-linux-x64-musl": "4.53.2", - "@rollup/rollup-openharmony-arm64": "4.53.2", - "@rollup/rollup-win32-arm64-msvc": "4.53.2", - "@rollup/rollup-win32-ia32-msvc": "4.53.2", - "@rollup/rollup-win32-x64-gnu": "4.53.2", - "@rollup/rollup-win32-x64-msvc": "4.53.2", - "fsevents": "~2.3.2" - } - }, - "node_modules/router": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", - "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", - "license": "MIT", - "dependencies": { - "debug": "^4.4.0", - "depd": "^2.0.0", - "is-promise": "^4.0.0", - "parseurl": "^1.3.3", - "path-to-regexp": "^8.0.0" - }, - "engines": { - "node": ">= 18" - } - }, - "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/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "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/send": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz", - "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==", - "license": "MIT", - "dependencies": { - "debug": "^4.3.5", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "etag": "^1.8.1", - "fresh": "^2.0.0", - "http-errors": "^2.0.0", - "mime-types": "^3.0.1", - "ms": "^2.1.3", - "on-finished": "^2.4.1", - "range-parser": "^1.2.1", - "statuses": "^2.0.1" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/serve-static": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz", - "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==", - "license": "MIT", - "dependencies": { - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "parseurl": "^1.3.3", - "send": "^1.2.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" - }, - "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==", - "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==", - "engines": { - "node": ">=8" - } - }, - "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/siginfo": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", - "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", - "dev": true, - "license": "ISC" - }, - "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/stackback": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", - "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", - "dev": true, - "license": "MIT" - }, - "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/std-env": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", - "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", - "dev": true, - "license": "MIT" - }, - "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": "9.0.2", - "resolved": "https://registry.npmjs.org/superagent/-/superagent-9.0.2.tgz", - "integrity": "sha512-xuW7dzkUpcJq7QnhOsnNUgtYp3xRwpt2F7abdRYIpCsAt0hhUqia0EdxyXZQQpNmGtsCzYHryaKSV3q3GJnq7w==", - "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": "^3.5.1", - "methods": "^1.1.2", - "mime": "2.6.0", - "qs": "^6.11.0" - }, - "engines": { - "node": ">=14.18.0" - } - }, - "node_modules/supertest": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/supertest/-/supertest-7.0.0.tgz", - "integrity": "sha512-qlsr7fIC0lSddmA3tzojvzubYxvlGtzumcdHgPwbFWMISQwL22MhM2Y3LNt+6w9Yyx7559VW5ab70dgphm8qQA==", - "dev": true, - "license": "MIT", - "dependencies": { - "methods": "^1.1.2", - "superagent": "^9.0.1" - }, - "engines": { - "node": ">=14.18.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, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tapable": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", - "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/tinybench": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", - "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", - "dev": true, - "license": "MIT" - }, - "node_modules/tinyexec": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", - "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", - "dev": true, - "license": "MIT" - }, - "node_modules/tinyglobby": { - "version": "0.2.15", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.3" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, - "node_modules/tinyglobby/node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/tinyglobby/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/tinyrainbow": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.0.3.tgz", - "integrity": "sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.0.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==", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/ts-api-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", - "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18.12" - }, - "peerDependencies": { - "typescript": ">=4.8.4" - } - }, - "node_modules/ts-declaration-location": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/ts-declaration-location/-/ts-declaration-location-1.0.7.tgz", - "integrity": "sha512-EDyGAwH1gO0Ausm9gV6T2nUvBgXT5kGoCMJPllOaooZ+4VvJiKBdZE7wK18N1deEowhcUptS+5GXZK8U/fvpwA==", - "dev": true, - "funding": [ - { - "type": "ko-fi", - "url": "https://ko-fi.com/rebeccastevens" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/ts-declaration-location" - } - ], - "license": "BSD-3-Clause", - "dependencies": { - "picomatch": "^4.0.2" - }, - "peerDependencies": { - "typescript": ">=4.0.0" - } - }, - "node_modules/ts-declaration-location/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/tsx": { - "version": "4.19.3", - "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.19.3.tgz", - "integrity": "sha512-4H8vUNGNjQ4V2EOoGw005+c+dGuPSnhpPBPHBtsZdGZBk/iJb4kguGlPWaZTZ3q5nMtFOEsY0nRDlh9PJyd6SQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "esbuild": "~0.25.0", - "get-tsconfig": "^4.7.5" - }, - "bin": { - "tsx": "dist/cli.mjs" - }, - "engines": { - "node": ">=18.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - } - }, - "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, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-is": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", - "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", - "license": "MIT", - "dependencies": { - "content-type": "^1.0.5", - "media-typer": "^1.1.0", - "mime-types": "^3.0.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/typescript": { - "version": "5.6.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", - "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", - "dev": true, - "peer": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/typescript-eslint": { - "version": "8.48.1", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.48.1.tgz", - "integrity": "sha512-FbOKN1fqNoXp1hIl5KYpObVrp0mCn+CLgn479nmu2IsRMrx2vyv74MmsBLVlhg8qVwNFGbXSp8fh1zp8pEoC2A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/eslint-plugin": "8.48.1", - "@typescript-eslint/parser": "8.48.1", - "@typescript-eslint/typescript-estree": "8.48.1", - "@typescript-eslint/utils": "8.48.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <6.0.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/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "engines": { - "node": ">= 0.8" - } - }, - "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/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/vitest": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.0.8.tgz", - "integrity": "sha512-urzu3NCEV0Qa0Y2PwvBtRgmNtxhj5t5ULw7cuKhIHh3OrkKTLlut0lnBOv9qe5OvbkMH2g38G7KPDCTpIytBVg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/expect": "4.0.8", - "@vitest/mocker": "4.0.8", - "@vitest/pretty-format": "4.0.8", - "@vitest/runner": "4.0.8", - "@vitest/snapshot": "4.0.8", - "@vitest/spy": "4.0.8", - "@vitest/utils": "4.0.8", - "debug": "^4.4.3", - "es-module-lexer": "^1.7.0", - "expect-type": "^1.2.2", - "magic-string": "^0.30.21", - "pathe": "^2.0.3", - "picomatch": "^4.0.3", - "std-env": "^3.10.0", - "tinybench": "^2.9.0", - "tinyexec": "^0.3.2", - "tinyglobby": "^0.2.15", - "tinyrainbow": "^3.0.3", - "vite": "^6.0.0 || ^7.0.0", - "why-is-node-running": "^2.3.0" - }, - "bin": { - "vitest": "vitest.mjs" - }, - "engines": { - "node": "^20.0.0 || ^22.0.0 || >=24.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "@edge-runtime/vm": "*", - "@types/debug": "^4.1.12", - "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", - "@vitest/browser-playwright": "4.0.8", - "@vitest/browser-preview": "4.0.8", - "@vitest/browser-webdriverio": "4.0.8", - "@vitest/ui": "4.0.8", - "happy-dom": "*", - "jsdom": "*" - }, - "peerDependenciesMeta": { - "@edge-runtime/vm": { - "optional": true - }, - "@types/debug": { - "optional": true - }, - "@types/node": { - "optional": true - }, - "@vitest/browser-playwright": { - "optional": true - }, - "@vitest/browser-preview": { - "optional": true - }, - "@vitest/browser-webdriverio": { - "optional": true - }, - "@vitest/ui": { - "optional": true - }, - "happy-dom": { - "optional": true - }, - "jsdom": { - "optional": true - } - } - }, - "node_modules/vitest/node_modules/@vitest/mocker": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.0.8.tgz", - "integrity": "sha512-9FRM3MZCedXH3+pIh+ME5Up2NBBHDq0wqwhOKkN4VnvCiKbVxddqH9mSGPZeawjd12pCOGnl+lo/ZGHt0/dQSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/spy": "4.0.8", - "estree-walker": "^3.0.3", - "magic-string": "^0.30.21" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "msw": "^2.4.9", - "vite": "^6.0.0 || ^7.0.0-0" - }, - "peerDependenciesMeta": { - "msw": { - "optional": true - }, - "vite": { - "optional": true - } - } - }, - "node_modules/vitest/node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/vitest/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/vitest/node_modules/vite": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.2.2.tgz", - "integrity": "sha512-BxAKBWmIbrDgrokdGZH1IgkIk/5mMHDreLDmCJ0qpyJaAteP8NvMhkwr/ZCQNqNH97bw/dANTE9PDzqwJghfMQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "esbuild": "^0.25.0", - "fdir": "^6.5.0", - "picomatch": "^4.0.3", - "postcss": "^8.5.6", - "rollup": "^4.43.0", - "tinyglobby": "^0.2.15" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^20.19.0 || >=22.12.0", - "jiti": ">=1.21.0", - "less": "^4.0.0", - "lightningcss": "^1.21.0", - "sass": "^1.70.0", - "sass-embedded": "^1.70.0", - "stylus": ">=0.54.8", - "sugarss": "^5.0.0", - "terser": "^5.16.0", - "tsx": "^4.8.1", - "yaml": "^2.4.2" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "jiti": { - "optional": true - }, - "less": { - "optional": true - }, - "lightningcss": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true - } - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/why-is-node-running": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", - "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", - "dev": true, - "license": "MIT", - "dependencies": { - "siginfo": "^2.0.0", - "stackback": "0.0.2" - }, - "bin": { - "why-is-node-running": "cli.js" - }, - "engines": { - "node": ">=8" - } - }, - "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, - "engines": { - "node": ">=0.10.0" - } - }, - "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==" - }, - "node_modules/ws": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", - "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", - "dev": true, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/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, - "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", - "peer": true, - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - }, - "node_modules/zod-to-json-schema": { - "version": "3.25.0", - "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.0.tgz", - "integrity": "sha512-HvWtU2UG41LALjajJrML6uQejQhNJx+JBO9IflpSja4R03iNWfKXrj6W2h7ljuLyc1nKS+9yDyL/9tD1U/yBnQ==", - "license": "ISC", - "peerDependencies": { - "zod": "^3.25 || ^4" - } - } - } -} diff --git a/package.json b/package.json index bfbc73802..8d21c999f 100644 --- a/package.json +++ b/package.json @@ -12,78 +12,22 @@ "url": "git+https://github.com/modelcontextprotocol/typescript-sdk.git" }, "engines": { - "node": ">=18" + "node": ">=20" }, + "packageManager": "pnpm@10.24.0", "keywords": [ "modelcontextprotocol", "mcp" ], - "exports": { - ".": { - "import": "./dist/esm/index.js", - "require": "./dist/cjs/index.js" - }, - "./client": { - "import": "./dist/esm/client/index.js", - "require": "./dist/cjs/client/index.js" - }, - "./server": { - "import": "./dist/esm/server/index.js", - "require": "./dist/cjs/server/index.js" - }, - "./validation": { - "import": "./dist/esm/validation/index.js", - "require": "./dist/cjs/validation/index.js" - }, - "./validation/ajv": { - "import": "./dist/esm/validation/ajv-provider.js", - "require": "./dist/cjs/validation/ajv-provider.js" - }, - "./validation/cfworker": { - "import": "./dist/esm/validation/cfworker-provider.js", - "require": "./dist/cjs/validation/cfworker-provider.js" - }, - "./experimental": { - "import": "./dist/esm/experimental/index.js", - "require": "./dist/cjs/experimental/index.js" - }, - "./experimental/tasks": { - "import": "./dist/esm/experimental/tasks/index.js", - "require": "./dist/cjs/experimental/tasks/index.js" - }, - "./*": { - "import": "./dist/esm/*", - "require": "./dist/cjs/*" - } - }, - "typesVersions": { - "*": { - "*": [ - "./dist/esm/*" - ] - } - }, - "files": [ - "dist" - ], "scripts": { "fetch:spec-types": "tsx scripts/fetch-spec-types.ts", - "typecheck": "tsgo --noEmit", - "build": "npm run build:esm && npm run build:cjs", - "build:esm": "mkdir -p dist/esm && echo '{\"type\": \"module\"}' > dist/esm/package.json && tsc -p tsconfig.prod.json", - "build:esm:w": "npm run build:esm -- -w", - "build:cjs": "mkdir -p dist/cjs && echo '{\"type\": \"commonjs\"}' > dist/cjs/package.json && tsc -p tsconfig.cjs.json", - "build:cjs:w": "npm run build:cjs -- -w", - "examples:simple-server:w": "tsx --watch src/examples/server/simpleStreamableHttp.ts --oauth", - "prepack": "npm run build:esm && npm run build:cjs", - "lint": "eslint src/ && prettier --check .", - "lint:fix": "eslint src/ --fix && prettier --write .", - "check": "npm run typecheck && npm run lint", - "test": "vitest run", - "test:watch": "vitest", - "start": "npm run server", - "server": "tsx watch --clear-screen=false scripts/cli.ts server", - "client": "tsx scripts/cli.ts client" + "typecheck:all": "pnpm -r typecheck", + "build:all": "pnpm -r build", + "prepack:all": "pnpm -r prepack", + "lint:all": "pnpm -r lint", + "lint:fix:all": "pnpm -r lint:fix", + "check:all": "pnpm -r typecheck && pnpm -r lint", + "test:all": "pnpm -r test" }, "dependencies": { "ajv": "^8.17.1", @@ -123,7 +67,7 @@ "@types/eventsource": "^1.1.15", "@types/express": "^5.0.0", "@types/express-serve-static-core": "^5.1.0", - "@types/node": "^22.12.0", + "@types/node": "^24.10.1", "@types/supertest": "^6.0.2", "@types/ws": "^8.5.12", "@typescript/native-preview": "^7.0.0-dev.20251103.1", @@ -133,7 +77,7 @@ "prettier": "3.6.2", "supertest": "^7.0.0", "tsx": "^4.16.5", - "typescript": "^5.5.4", + "typescript": "^5.9.3", "typescript-eslint": "^8.48.1", "vitest": "^4.0.8", "ws": "^8.18.0" diff --git a/packages/client/eslint.config.mjs b/packages/client/eslint.config.mjs new file mode 100644 index 000000000..951c9f3a9 --- /dev/null +++ b/packages/client/eslint.config.mjs @@ -0,0 +1,5 @@ +// @ts-check + +import baseConfig from '@modelcontextprotocol/eslint-config'; + +export default baseConfig; diff --git a/packages/client/package.json b/packages/client/package.json new file mode 100644 index 000000000..4fdca6b93 --- /dev/null +++ b/packages/client/package.json @@ -0,0 +1,107 @@ +{ + "name": "@modelcontextprotocol/sdk-client", + "version": "2.0.0-alpha.0", + "description": "Model Context Protocol implementation for TypeScript", + "license": "MIT", + "author": "Anthropic, PBC (https://anthropic.com)", + "homepage": "https://modelcontextprotocol.io", + "bugs": "https://github.com/modelcontextprotocol/typescript-sdk/issues", + "type": "module", + "repository": { + "type": "git", + "url": "git+https://github.com/modelcontextprotocol/typescript-sdk.git" + }, + "engines": { + "node": ">=18" + }, + "keywords": [ + "modelcontextprotocol", + "mcp" + ], + "exports": { + ".": { + "import": "./dist/index.js" + } + }, + "typesVersions": { + "*": { + "*": [ + "./dist/*" + ] + } + }, + "files": [ + "dist" + ], + "scripts": { + "typecheck": "tsc -p tsconfig.build.json --noEmit", + "build": "npm run build:esm", + "build:esm": "mkdir -p dist && echo '{\"type\": \"module\"}' > dist/package.json && tsc -p tsconfig.build.json", + "build:esm:w": "npm run build:esm -- -w", + "prepack": "npm run build:esm", + "lint": "eslint src/ && prettier --check .", + "lint:fix": "eslint src/ --fix && prettier --write .", + "check": "npm run typecheck && npm run lint", + "test": "vitest run", + "test:watch": "vitest", + "start": "npm run server", + "server": "tsx watch --clear-screen=false scripts/cli.ts server", + "client": "tsx scripts/cli.ts client" + }, + "dependencies": { + "@modelcontextprotocol/sdk-core": "workspace:^", + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1", + "content-type": "^1.0.5", + "cors": "^2.8.5", + "cross-spawn": "^7.0.5", + "eventsource": "^3.0.2", + "eventsource-parser": "^3.0.0", + "express": "^5.0.1", + "express-rate-limit": "^7.5.0", + "jose": "^6.1.1", + "json-schema-typed": "^8.0.2", + "pkce-challenge": "^5.0.0", + "raw-body": "^3.0.0", + "zod": "^3.25 || ^4.0", + "zod-to-json-schema": "^3.25.0" + }, + "peerDependencies": { + "@cfworker/json-schema": "^4.1.1", + "zod": "^3.25 || ^4.0" + }, + "peerDependenciesMeta": { + "@cfworker/json-schema": { + "optional": true + }, + "zod": { + "optional": false + } + }, + "devDependencies": { + "@modelcontextprotocol/tsconfig": "workspace:^", + "@modelcontextprotocol/vitest-config": "workspace:^", + "@modelcontextprotocol/eslint-config": "workspace:^", + "@cfworker/json-schema": "^4.1.1", + "@eslint/js": "^9.39.1", + "@types/content-type": "^1.1.8", + "@types/cors": "^2.8.17", + "@types/cross-spawn": "^6.0.6", + "@types/eventsource": "^1.1.15", + "@types/express": "^5.0.0", + "@types/express-serve-static-core": "^5.1.0", + "@types/supertest": "^6.0.2", + "@types/ws": "^8.5.12", + "@typescript/native-preview": "^7.0.0-dev.20251103.1", + "eslint": "^9.8.0", + "eslint-config-prettier": "^10.1.8", + "eslint-plugin-n": "^17.23.1", + "prettier": "3.6.2", + "supertest": "^7.0.0", + "tsx": "^4.16.5", + "typescript": "^5.5.4", + "typescript-eslint": "^8.48.1", + "vitest": "^4.0.8", + "ws": "^8.18.0" + } +} diff --git a/src/client/auth-extensions.ts b/packages/client/src/client/auth-extensions.ts similarity index 98% rename from src/client/auth-extensions.ts rename to packages/client/src/client/auth-extensions.ts index f3908d2c2..6155d749f 100644 --- a/src/client/auth-extensions.ts +++ b/packages/client/src/client/auth-extensions.ts @@ -5,9 +5,10 @@ * for common machine-to-machine authentication scenarios. */ -import type { JWK } from 'jose'; -import { OAuthClientInformation, OAuthClientMetadata, OAuthTokens } from '../shared/auth.js'; -import { AddClientAuthentication, OAuthClientProvider } from './auth.js'; +import type { OAuthClientInformation, OAuthClientMetadata, OAuthTokens } from '@modelcontextprotocol/sdk-core'; +import type { CryptoKey, JWK } from 'jose'; + +import type { AddClientAuthentication, OAuthClientProvider } from './auth.js'; /** * Helper to produce a private_key_jwt client authentication function. diff --git a/src/client/auth.ts b/packages/client/src/client/auth.ts similarity index 98% rename from src/client/auth.ts rename to packages/client/src/client/auth.ts index 4c82b5114..1bf9ca98e 100644 --- a/src/client/auth.ts +++ b/packages/client/src/client/auth.ts @@ -1,34 +1,33 @@ -import pkceChallenge from 'pkce-challenge'; -import { LATEST_PROTOCOL_VERSION } from '../types.js'; -import { - OAuthClientMetadata, +import type { + AuthorizationServerMetadata, + FetchLike, OAuthClientInformation, + OAuthClientInformationFull, OAuthClientInformationMixed, - OAuthTokens, + OAuthClientMetadata, OAuthMetadata, - OAuthClientInformationFull, OAuthProtectedResourceMetadata, - OAuthErrorResponseSchema, - AuthorizationServerMetadata, - OpenIdProviderDiscoveryMetadataSchema -} from '../shared/auth.js'; -import { - OAuthClientInformationFullSchema, - OAuthMetadataSchema, - OAuthProtectedResourceMetadataSchema, - OAuthTokensSchema -} from '../shared/auth.js'; -import { checkResourceAllowed, resourceUrlFromServerUrl } from '../shared/auth-utils.js'; + OAuthTokens +} from '@modelcontextprotocol/sdk-core'; import { + checkResourceAllowed, InvalidClientError, InvalidClientMetadataError, InvalidGrantError, + LATEST_PROTOCOL_VERSION, OAUTH_ERRORS, + OAuthClientInformationFullSchema, OAuthError, + OAuthErrorResponseSchema, + OAuthMetadataSchema, + OAuthProtectedResourceMetadataSchema, + OAuthTokensSchema, + OpenIdProviderDiscoveryMetadataSchema, + resourceUrlFromServerUrl, ServerError, UnauthorizedClientError -} from '../server/auth/errors.js'; -import { FetchLike } from '../shared/transport.js'; +} from '@modelcontextprotocol/sdk-core'; +import pkceChallenge from 'pkce-challenge'; /** * Function type for adding client authentication to token requests. @@ -574,7 +573,7 @@ export function extractWWWAuthenticateParams(res: Response): { resourceMetadataU } const [type, scheme] = authenticateHeader.split(' '); - if (type.toLowerCase() !== 'bearer' || !scheme) { + if (type?.toLowerCase() !== 'bearer' || !scheme) { return {}; } @@ -617,7 +616,10 @@ function extractFieldFromWwwAuth(response: Response, fieldName: string): string if (match) { // Pattern matches: field_name="value" or field_name=value (unquoted) - return match[1] || match[2]; + const result = match[1] || match[2]; + if (result) { + return result; + } } return null; @@ -634,13 +636,13 @@ export function extractResourceMetadataUrl(res: Response): URL | undefined { } const [type, scheme] = authenticateHeader.split(' '); - if (type.toLowerCase() !== 'bearer' || !scheme) { + if (type?.toLowerCase() !== 'bearer' || !scheme) { return undefined; } const regex = /resource_metadata="([^"]*)"/; const match = regex.exec(authenticateHeader); - if (!match) { + if (!match || !match[1]) { return undefined; } diff --git a/src/client/index.ts b/packages/client/src/client/client.ts similarity index 96% rename from src/client/index.ts rename to packages/client/src/client/client.ts index 28c0e6253..db19b4e23 100644 --- a/src/client/index.ts +++ b/packages/client/src/client/client.ts @@ -1,69 +1,75 @@ -import { mergeCapabilities, Protocol, type ProtocolOptions, type RequestOptions } from '../shared/protocol.js'; -import type { Transport } from '../shared/transport.js'; - +import type { + AnyObjectSchema, + CallToolRequest, + ClientCapabilities, + ClientNotification, + ClientRequest, + ClientResult, + CompatibilityCallToolResultSchema, + CompleteRequest, + GetPromptRequest, + Implementation, + JsonSchemaType, + JsonSchemaValidator, + jsonSchemaValidator, + ListChangedHandlers, + ListChangedOptions, + ListPromptsRequest, + ListResourcesRequest, + ListResourceTemplatesRequest, + ListToolsRequest, + LoggingLevel, + Notification, + ProtocolOptions, + ReadResourceRequest, + Request, + RequestHandlerExtra, + RequestOptions, + Result, + SchemaOutput, + ServerCapabilities, + SubscribeRequest, + Tool, + Transport, + UnsubscribeRequest, + ZodV3Internal, + ZodV4Internal +} from '@modelcontextprotocol/sdk-core'; import { - type CallToolRequest, + AjvJsonSchemaValidator, + assertClientRequestTaskCapability, + assertToolsCallTaskCapability, CallToolResultSchema, - type ClientCapabilities, - type ClientNotification, - type ClientRequest, - type ClientResult, - type CompatibilityCallToolResultSchema, - type CompleteRequest, CompleteResultSchema, + CreateMessageRequestSchema, + CreateMessageResultSchema, + CreateTaskResultSchema, + ElicitRequestSchema, + ElicitResultSchema, EmptyResultSchema, ErrorCode, - type GetPromptRequest, + getObjectShape, GetPromptResultSchema, - type Implementation, InitializeResultSchema, + isZ4Schema, LATEST_PROTOCOL_VERSION, - type ListPromptsRequest, + ListChangedOptionsBaseSchema, ListPromptsResultSchema, - type ListResourcesRequest, ListResourcesResultSchema, - type ListResourceTemplatesRequest, ListResourceTemplatesResultSchema, - type ListToolsRequest, ListToolsResultSchema, - type LoggingLevel, McpError, - type ReadResourceRequest, - ReadResourceResultSchema, - type ServerCapabilities, - SUPPORTED_PROTOCOL_VERSIONS, - type SubscribeRequest, - type Tool, - type UnsubscribeRequest, - ElicitResultSchema, - ElicitRequestSchema, - CreateTaskResultSchema, - CreateMessageRequestSchema, - CreateMessageResultSchema, - ToolListChangedNotificationSchema, + mergeCapabilities, PromptListChangedNotificationSchema, + Protocol, + ReadResourceResultSchema, ResourceListChangedNotificationSchema, - ListChangedOptions, - ListChangedOptionsBaseSchema, - type ListChangedHandlers, - type Request, - type Notification, - type Result -} from '../types.js'; -import { AjvJsonSchemaValidator } from '../validation/ajv-provider.js'; -import type { JsonSchemaType, JsonSchemaValidator, jsonSchemaValidator } from '../validation/types.js'; -import { - AnyObjectSchema, - SchemaOutput, - getObjectShape, - isZ4Schema, safeParse, - type ZodV3Internal, - type ZodV4Internal -} from '../server/zod-compat.js'; -import type { RequestHandlerExtra } from '../shared/protocol.js'; + SUPPORTED_PROTOCOL_VERSIONS, + ToolListChangedNotificationSchema +} from '@modelcontextprotocol/sdk-core'; + import { ExperimentalClientTasks } from '../experimental/tasks/client.js'; -import { assertToolsCallTaskCapability, assertClientRequestTaskCapability } from '../experimental/tasks/helpers.js'; /** * Elicitation default application helper. Applies defaults to the data based on the schema. @@ -79,7 +85,7 @@ function applyElicitationDefaults(schema: JsonSchemaType | undefined, data: unkn const obj = data as Record; const props = schema.properties as Record; for (const key of Object.keys(props)) { - const propSchema = props[key]; + const propSchema = props[key]!; // If missing or explicitly undefined, apply default if present if (obj[key] === undefined && Object.prototype.hasOwnProperty.call(propSchema, 'default')) { obj[key] = propSchema.default; diff --git a/src/client/middleware.ts b/packages/client/src/client/middleware.ts similarity index 98% rename from src/client/middleware.ts rename to packages/client/src/client/middleware.ts index c8f7fdd3d..e3d831f43 100644 --- a/src/client/middleware.ts +++ b/packages/client/src/client/middleware.ts @@ -1,5 +1,7 @@ -import { auth, extractWWWAuthenticateParams, OAuthClientProvider, UnauthorizedError } from './auth.js'; -import { FetchLike } from '../shared/transport.js'; +import type { FetchLike } from '@modelcontextprotocol/sdk-core'; + +import type { OAuthClientProvider } from './auth.js'; +import { auth, extractWWWAuthenticateParams, UnauthorizedError } from './auth.js'; /** * Middleware function that wraps and enhances fetch functionality. diff --git a/src/client/sse.ts b/packages/client/src/client/sse.ts similarity index 95% rename from src/client/sse.ts rename to packages/client/src/client/sse.ts index f0e91ff25..240a361e6 100644 --- a/src/client/sse.ts +++ b/packages/client/src/client/sse.ts @@ -1,7 +1,9 @@ -import { EventSource, type ErrorEvent, type EventSourceInit } from 'eventsource'; -import { Transport, FetchLike, createFetchWithInit, normalizeHeaders } from '../shared/transport.js'; -import { JSONRPCMessage, JSONRPCMessageSchema } from '../types.js'; -import { auth, AuthResult, extractWWWAuthenticateParams, OAuthClientProvider, UnauthorizedError } from './auth.js'; +import type { FetchLike, JSONRPCMessage, Transport } from '@modelcontextprotocol/sdk-core'; +import { createFetchWithInit, JSONRPCMessageSchema, normalizeHeaders } from '@modelcontextprotocol/sdk-core'; +import { type ErrorEvent, EventSource, type EventSourceInit } from 'eventsource'; + +import type { AuthResult, OAuthClientProvider } from './auth.js'; +import { auth, extractWWWAuthenticateParams, UnauthorizedError } from './auth.js'; export class SseError extends Error { constructor( @@ -114,7 +116,7 @@ export class SSEClientTransport implements Transport { } private async _commonHeaders(): Promise { - const headers: HeadersInit & Record = {}; + const headers: RequestInit['headers'] & Record = {}; if (this._authProvider) { const tokens = await this._authProvider.tokens(); if (tokens) { diff --git a/src/client/stdio.ts b/packages/client/src/client/stdio.ts similarity index 96% rename from src/client/stdio.ts rename to packages/client/src/client/stdio.ts index e488dcd24..ea4b41a98 100644 --- a/src/client/stdio.ts +++ b/packages/client/src/client/stdio.ts @@ -1,10 +1,11 @@ -import { ChildProcess, IOType } from 'node:child_process'; -import spawn from 'cross-spawn'; +import type { ChildProcess, IOType } from 'node:child_process'; import process from 'node:process'; -import { Stream, PassThrough } from 'node:stream'; -import { ReadBuffer, serializeMessage } from '../shared/stdio.js'; -import { Transport } from '../shared/transport.js'; -import { JSONRPCMessage } from '../types.js'; +import type { Stream } from 'node:stream'; +import { PassThrough } from 'node:stream'; + +import type { JSONRPCMessage, Transport } from '@modelcontextprotocol/sdk-core'; +import { ReadBuffer, serializeMessage } from '@modelcontextprotocol/sdk-core'; +import spawn from 'cross-spawn'; export type StdioServerParameters = { /** diff --git a/src/client/streamableHttp.ts b/packages/client/src/client/streamableHttp.ts similarity index 97% rename from src/client/streamableHttp.ts rename to packages/client/src/client/streamableHttp.ts index 736587973..100c110fa 100644 --- a/src/client/streamableHttp.ts +++ b/packages/client/src/client/streamableHttp.ts @@ -1,8 +1,19 @@ -import { Transport, FetchLike, createFetchWithInit, normalizeHeaders } from '../shared/transport.js'; -import { isInitializedNotification, isJSONRPCRequest, isJSONRPCResultResponse, JSONRPCMessage, JSONRPCMessageSchema } from '../types.js'; -import { auth, AuthResult, extractWWWAuthenticateParams, OAuthClientProvider, UnauthorizedError } from './auth.js'; +import type { ReadableWritablePair } from 'node:stream/web'; + +import type { FetchLike, JSONRPCMessage, Transport } from '@modelcontextprotocol/sdk-core'; +import { + createFetchWithInit, + isInitializedNotification, + isJSONRPCRequest, + isJSONRPCResultResponse, + JSONRPCMessageSchema, + normalizeHeaders +} from '@modelcontextprotocol/sdk-core'; import { EventSourceParserStream } from 'eventsource-parser/stream'; +import type { AuthResult, OAuthClientProvider } from './auth.js'; +import { auth, extractWWWAuthenticateParams, UnauthorizedError } from './auth.js'; + // Default reconnection options for StreamableHTTP connections const DEFAULT_STREAMABLE_HTTP_RECONNECTION_OPTIONS: StreamableHTTPReconnectionOptions = { initialReconnectionDelay: 1000, @@ -180,7 +191,7 @@ export class StreamableHTTPClientTransport implements Transport { } private async _commonHeaders(): Promise { - const headers: HeadersInit & Record = {}; + const headers: RequestInit['headers'] & Record = {}; if (this._authProvider) { const tokens = await this._authProvider.tokens(); if (tokens) { diff --git a/src/client/websocket.ts b/packages/client/src/client/websocket.ts similarity index 93% rename from src/client/websocket.ts rename to packages/client/src/client/websocket.ts index aed766caf..29de274b7 100644 --- a/src/client/websocket.ts +++ b/packages/client/src/client/websocket.ts @@ -1,5 +1,5 @@ -import { Transport } from '../shared/transport.js'; -import { JSONRPCMessage, JSONRPCMessageSchema } from '../types.js'; +import type { JSONRPCMessage, Transport } from '@modelcontextprotocol/sdk-core'; +import { JSONRPCMessageSchema } from '@modelcontextprotocol/sdk-core'; const SUBPROTOCOL = 'mcp'; diff --git a/packages/client/src/experimental/index.ts b/packages/client/src/experimental/index.ts new file mode 100644 index 000000000..926369f99 --- /dev/null +++ b/packages/client/src/experimental/index.ts @@ -0,0 +1,13 @@ +/** + * Experimental MCP SDK features. + * WARNING: These APIs are experimental and may change without notice. + * + * Import experimental features from this module: + * ```typescript + * import { TaskStore, InMemoryTaskStore } from '@modelcontextprotocol/sdk/experimental'; + * ``` + * + * @experimental + */ + +export * from './tasks/client.js'; diff --git a/src/experimental/tasks/client.ts b/packages/client/src/experimental/tasks/client.ts similarity index 94% rename from src/experimental/tasks/client.ts rename to packages/client/src/experimental/tasks/client.ts index f62941dc8..41f5989cb 100644 --- a/src/experimental/tasks/client.ts +++ b/packages/client/src/experimental/tasks/client.ts @@ -5,14 +5,24 @@ * @experimental */ -import type { Client } from '../../client/index.js'; -import type { RequestOptions } from '../../shared/protocol.js'; -import type { ResponseMessage } from '../../shared/responseMessage.js'; -import type { AnyObjectSchema, SchemaOutput } from '../../server/zod-compat.js'; -import type { CallToolRequest, ClientRequest, Notification, Request, Result } from '../../types.js'; -import { CallToolResultSchema, type CompatibilityCallToolResultSchema, McpError, ErrorCode } from '../../types.js'; +import type { + AnyObjectSchema, + CallToolRequest, + CancelTaskResult, + ClientRequest, + CompatibilityCallToolResultSchema, + GetTaskResult, + ListTasksResult, + Notification, + Request, + RequestOptions, + ResponseMessage, + Result, + SchemaOutput +} from '@modelcontextprotocol/sdk-core'; +import { CallToolResultSchema, ErrorCode, McpError } from '@modelcontextprotocol/sdk-core'; -import type { GetTaskResult, ListTasksResult, CancelTaskResult } from './types.js'; +import type { Client } from '../../client/client.js'; /** * Internal interface for accessing Client's private methods. diff --git a/packages/client/src/index.ts b/packages/client/src/index.ts new file mode 100644 index 000000000..6dea7f8a2 --- /dev/null +++ b/packages/client/src/index.ts @@ -0,0 +1,14 @@ +export * from './client/auth.js'; +export * from './client/auth-extensions.js'; +export * from './client/client.js'; +export * from './client/middleware.js'; +export * from './client/sse.js'; +export * from './client/stdio.js'; +export * from './client/streamableHttp.js'; +export * from './client/websocket.js'; + +// experimental exports +export * from './experimental/index.js'; + +// re-export shared types +export * from '@modelcontextprotocol/sdk-core'; diff --git a/test/client/auth-extensions.test.ts b/packages/client/test/client/auth-extensions.test.ts similarity index 99% rename from test/client/auth-extensions.test.ts rename to packages/client/test/client/auth-extensions.test.ts index a7217307d..0487a76be 100644 --- a/test/client/auth-extensions.test.ts +++ b/packages/client/test/client/auth-extensions.test.ts @@ -274,7 +274,7 @@ describe('createPrivateKeyJwtAuth', () => { const assertion = params.get('client_assertion')!; // Decode the payload to verify audience const [, payloadB64] = assertion.split('.'); - const payload = JSON.parse(Buffer.from(payloadB64, 'base64url').toString()); + const payload = JSON.parse(Buffer.from(payloadB64!, 'base64url').toString()); expect(payload.aud).toBe('https://issuer.example.com'); }); diff --git a/test/client/auth.test.ts b/packages/client/test/client/auth.test.ts similarity index 96% rename from test/client/auth.test.ts rename to packages/client/test/client/auth.test.ts index d6e7e8684..c1c815207 100644 --- a/test/client/auth.test.ts +++ b/packages/client/test/client/auth.test.ts @@ -1,4 +1,10 @@ -import { LATEST_PROTOCOL_VERSION } from '../../src/types.js'; +import { + LATEST_PROTOCOL_VERSION, + InvalidClientMetadataError, + ServerError, + AuthorizationServerMetadata, + OAuthTokens +} from '@modelcontextprotocol/sdk-core'; import { discoverOAuthMetadata, discoverAuthorizationServerMetadata, @@ -15,8 +21,6 @@ import { isHttpsUrl } from '../../src/client/auth.js'; import { createPrivateKeyJwtAuth } from '../../src/client/auth-extensions.js'; -import { InvalidClientMetadataError, ServerError } from '../../src/server/auth/errors.js'; -import { AuthorizationServerMetadata, OAuthTokens } from '../../src/shared/auth.js'; import { expect, vi, type Mock } from 'vitest'; // Mock pkce-challenge @@ -125,7 +129,7 @@ describe('OAuth Authorization', () => { expect(metadata).toEqual(validMetadata); const calls = mockFetch.mock.calls; expect(calls.length).toBe(1); - const [url] = calls[0]; + const [url] = calls[0]!; expect(url.toString()).toBe('https://resource.example.com/.well-known/oauth-protected-resource'); }); @@ -159,7 +163,7 @@ describe('OAuth Authorization', () => { expect(mockFetch).toHaveBeenCalledTimes(2); // Verify first call had MCP header - expect(mockFetch.mock.calls[0][1]?.headers).toHaveProperty('MCP-Protocol-Version'); + expect(mockFetch.mock.calls[0]![1]?.headers).toHaveProperty('MCP-Protocol-Version'); }); it('throws an error when all fetch attempts fail', async () => { @@ -230,7 +234,7 @@ describe('OAuth Authorization', () => { expect(metadata).toEqual(validMetadata); const calls = mockFetch.mock.calls; expect(calls.length).toBe(1); - const [url] = calls[0]; + const [url] = calls[0]!; expect(url.toString()).toBe('https://resource.example.com/.well-known/oauth-protected-resource/path/name'); }); @@ -245,7 +249,7 @@ describe('OAuth Authorization', () => { expect(metadata).toEqual(validMetadata); const calls = mockFetch.mock.calls; expect(calls.length).toBe(1); - const [url] = calls[0]; + const [url] = calls[0]!; expect(url.toString()).toBe('https://resource.example.com/.well-known/oauth-protected-resource/path?param=value'); }); @@ -272,14 +276,14 @@ describe('OAuth Authorization', () => { expect(calls.length).toBe(2); // First call should be path-aware - const [firstUrl, firstOptions] = calls[0]; + const [firstUrl, firstOptions] = calls[0]!; expect(firstUrl.toString()).toBe('https://resource.example.com/.well-known/oauth-protected-resource/path/name'); expect(firstOptions.headers).toEqual({ 'MCP-Protocol-Version': LATEST_PROTOCOL_VERSION }); // Second call should be root fallback - const [secondUrl, secondOptions] = calls[1]; + const [secondUrl, secondOptions] = calls[1]!; expect(secondUrl.toString()).toBe('https://resource.example.com/.well-known/oauth-protected-resource'); expect(secondOptions.headers).toEqual({ 'MCP-Protocol-Version': LATEST_PROTOCOL_VERSION @@ -335,7 +339,7 @@ describe('OAuth Authorization', () => { const calls = mockFetch.mock.calls; expect(calls.length).toBe(1); // Should not attempt fallback - const [url] = calls[0]; + const [url] = calls[0]!; expect(url.toString()).toBe('https://resource.example.com/.well-known/oauth-protected-resource'); }); @@ -353,7 +357,7 @@ describe('OAuth Authorization', () => { const calls = mockFetch.mock.calls; expect(calls.length).toBe(1); // Should not attempt fallback - const [url] = calls[0]; + const [url] = calls[0]!; expect(url.toString()).toBe('https://resource.example.com/.well-known/oauth-protected-resource'); }); @@ -381,7 +385,7 @@ describe('OAuth Authorization', () => { expect(calls.length).toBe(3); // Final call should be root fallback - const [lastUrl, lastOptions] = calls[2]; + const [lastUrl, lastOptions] = calls[2]!; expect(lastUrl.toString()).toBe('https://resource.example.com/.well-known/oauth-protected-resource'); expect(lastOptions.headers).toEqual({ 'MCP-Protocol-Version': LATEST_PROTOCOL_VERSION @@ -404,7 +408,7 @@ describe('OAuth Authorization', () => { const calls = mockFetch.mock.calls; expect(calls.length).toBe(1); // Should not attempt fallback when explicit URL is provided - const [url] = calls[0]; + const [url] = calls[0]!; expect(url.toString()).toBe('https://custom.example.com/metadata'); }); @@ -426,7 +430,7 @@ describe('OAuth Authorization', () => { expect(customFetch).toHaveBeenCalledTimes(1); expect(mockFetch).not.toHaveBeenCalled(); - const [url, options] = customFetch.mock.calls[0]; + const [url, options] = customFetch.mock.calls[0]!; expect(url.toString()).toBe('https://resource.example.com/.well-known/oauth-protected-resource'); expect(options.headers).toEqual({ 'MCP-Protocol-Version': LATEST_PROTOCOL_VERSION @@ -455,7 +459,7 @@ describe('OAuth Authorization', () => { expect(metadata).toEqual(validMetadata); const calls = mockFetch.mock.calls; expect(calls.length).toBe(1); - const [url, options] = calls[0]; + const [url, options] = calls[0]!; expect(url.toString()).toBe('https://auth.example.com/.well-known/oauth-authorization-server'); expect(options.headers).toEqual({ 'MCP-Protocol-Version': LATEST_PROTOCOL_VERSION @@ -473,7 +477,7 @@ describe('OAuth Authorization', () => { expect(metadata).toEqual(validMetadata); const calls = mockFetch.mock.calls; expect(calls.length).toBe(1); - const [url, options] = calls[0]; + const [url, options] = calls[0]!; expect(url.toString()).toBe('https://auth.example.com/.well-known/oauth-authorization-server/path/name'); expect(options.headers).toEqual({ 'MCP-Protocol-Version': LATEST_PROTOCOL_VERSION @@ -501,14 +505,14 @@ describe('OAuth Authorization', () => { expect(calls.length).toBe(2); // First call should be path-aware - const [firstUrl, firstOptions] = calls[0]; + const [firstUrl, firstOptions] = calls[0]!; expect(firstUrl.toString()).toBe('https://auth.example.com/.well-known/oauth-authorization-server/path/name'); expect(firstOptions.headers).toEqual({ 'MCP-Protocol-Version': LATEST_PROTOCOL_VERSION }); // Second call should be root fallback - const [secondUrl, secondOptions] = calls[1]; + const [secondUrl, secondOptions] = calls[1]!; expect(secondUrl.toString()).toBe('https://auth.example.com/.well-known/oauth-authorization-server'); expect(secondOptions.headers).toEqual({ 'MCP-Protocol-Version': LATEST_PROTOCOL_VERSION @@ -548,7 +552,7 @@ describe('OAuth Authorization', () => { const calls = mockFetch.mock.calls; expect(calls.length).toBe(1); // Should not attempt fallback - const [url] = calls[0]; + const [url] = calls[0]!; expect(url.toString()).toBe('https://auth.example.com/.well-known/oauth-authorization-server'); }); @@ -565,7 +569,7 @@ describe('OAuth Authorization', () => { const calls = mockFetch.mock.calls; expect(calls.length).toBe(1); // Should not attempt fallback - const [url] = calls[0]; + const [url] = calls[0]!; expect(url.toString()).toBe('https://auth.example.com/.well-known/oauth-authorization-server'); }); @@ -593,7 +597,7 @@ describe('OAuth Authorization', () => { expect(calls.length).toBe(3); // Final call should be root fallback - const [lastUrl, lastOptions] = calls[2]; + const [lastUrl, lastOptions] = calls[2]!; expect(lastUrl.toString()).toBe('https://auth.example.com/.well-known/oauth-authorization-server'); expect(lastOptions.headers).toEqual({ 'MCP-Protocol-Version': LATEST_PROTOCOL_VERSION @@ -630,7 +634,7 @@ describe('OAuth Authorization', () => { expect(mockFetch).toHaveBeenCalledTimes(2); // Verify first call had MCP header - expect(mockFetch.mock.calls[0][1]?.headers).toHaveProperty('MCP-Protocol-Version'); + expect(mockFetch.mock.calls[0]![1]?.headers).toHaveProperty('MCP-Protocol-Version'); }); it('throws an error when all fetch attempts fail', async () => { @@ -722,7 +726,7 @@ describe('OAuth Authorization', () => { expect(customFetch).toHaveBeenCalledTimes(1); expect(mockFetch).not.toHaveBeenCalled(); - const [url, options] = customFetch.mock.calls[0]; + const [url, options] = customFetch.mock.calls[0]!; expect(url.toString()).toBe('https://auth.example.com/.well-known/oauth-authorization-server'); expect(options.headers).toEqual({ 'MCP-Protocol-Version': LATEST_PROTOCOL_VERSION @@ -771,7 +775,7 @@ describe('OAuth Authorization', () => { const urls = buildDiscoveryUrls(new URL('https://auth.example.com/tenant1')); expect(urls).toHaveLength(3); - expect(urls[0].url.toString()).toBe('https://auth.example.com/.well-known/oauth-authorization-server/tenant1'); + expect(urls[0]!.url.toString()).toBe('https://auth.example.com/.well-known/oauth-authorization-server/tenant1'); }); }); @@ -817,8 +821,8 @@ describe('OAuth Authorization', () => { // Verify it tried the URLs in the correct order const calls = mockFetch.mock.calls; expect(calls.length).toBe(2); - expect(calls[0][0].toString()).toBe('https://auth.example.com/.well-known/oauth-authorization-server/tenant1'); - expect(calls[1][0].toString()).toBe('https://auth.example.com/.well-known/openid-configuration/tenant1'); + expect(calls[0]![0].toString()).toBe('https://auth.example.com/.well-known/oauth-authorization-server/tenant1'); + expect(calls[1]![0].toString()).toBe('https://auth.example.com/.well-known/openid-configuration/tenant1'); }); it('continues on 4xx errors', async () => { @@ -865,10 +869,10 @@ describe('OAuth Authorization', () => { expect(calls.length).toBe(2); // First call should have headers - expect(calls[0][1]?.headers).toHaveProperty('MCP-Protocol-Version'); + expect(calls[0]![1]?.headers).toHaveProperty('MCP-Protocol-Version'); // Second call should not have headers (CORS retry) - expect(calls[1][1]?.headers).toBeUndefined(); + expect(calls[1]![1]?.headers).toBeUndefined(); }); it('supports custom fetch function', async () => { @@ -896,7 +900,7 @@ describe('OAuth Authorization', () => { expect(metadata).toEqual(validOAuthMetadata); const calls = mockFetch.mock.calls; - const [, options] = calls[0]; + const [, options] = calls[0]!; expect(options.headers).toEqual({ 'MCP-Protocol-Version': '2025-01-01', Accept: 'application/json' @@ -1140,7 +1144,7 @@ describe('OAuth Authorization', () => { }) ); - const options = mockFetch.mock.calls[0][1]; + const options = mockFetch.mock.calls[0]![1]; expect(options.headers).toBeInstanceOf(Headers); expect(options.headers.get('Content-Type')).toBe('application/x-www-form-urlencoded'); expect(options.body).toBeInstanceOf(URLSearchParams); @@ -1180,7 +1184,7 @@ describe('OAuth Authorization', () => { }) ); - const options = mockFetch.mock.calls[0][1]; + const options = mockFetch.mock.calls[0]![1]; expect(options.headers).toBeInstanceOf(Headers); expect(options.headers.get('Content-Type')).toBe('application/x-www-form-urlencoded'); @@ -1229,10 +1233,10 @@ describe('OAuth Authorization', () => { }) ); - const headers = mockFetch.mock.calls[0][1].headers as Headers; + const headers = mockFetch.mock.calls[0]![1].headers as Headers; expect(headers.get('Content-Type')).toBe('application/x-www-form-urlencoded'); expect(headers.get('Authorization')).toBe('Basic Y2xpZW50MTIzOnNlY3JldDEyMw=='); - const body = mockFetch.mock.calls[0][1].body as URLSearchParams; + const body = mockFetch.mock.calls[0]![1].body as URLSearchParams; expect(body.get('grant_type')).toBe('authorization_code'); expect(body.get('code')).toBe('code123'); expect(body.get('code_verifier')).toBe('verifier123'); @@ -1297,7 +1301,7 @@ describe('OAuth Authorization', () => { expect(customFetch).toHaveBeenCalledTimes(1); expect(mockFetch).not.toHaveBeenCalled(); - const [url, options] = customFetch.mock.calls[0]; + const [url, options] = customFetch.mock.calls[0]!; expect(url.toString()).toBe('https://auth.example.com/token'); expect(options).toEqual( expect.objectContaining({ @@ -1366,9 +1370,9 @@ describe('OAuth Authorization', () => { }) ); - const headers = mockFetch.mock.calls[0][1].headers as Headers; + const headers = mockFetch.mock.calls[0]![1].headers as Headers; expect(headers.get('Content-Type')).toBe('application/x-www-form-urlencoded'); - const body = mockFetch.mock.calls[0][1].body as URLSearchParams; + const body = mockFetch.mock.calls[0]![1].body as URLSearchParams; expect(body.get('grant_type')).toBe('refresh_token'); expect(body.get('refresh_token')).toBe('refresh123'); expect(body.get('client_id')).toBe('client123'); @@ -1410,10 +1414,10 @@ describe('OAuth Authorization', () => { }) ); - const headers = mockFetch.mock.calls[0][1].headers as Headers; + const headers = mockFetch.mock.calls[0]![1].headers as Headers; expect(headers.get('Content-Type')).toBe('application/x-www-form-urlencoded'); expect(headers.get('Authorization')).toBe('Basic Y2xpZW50MTIzOnNlY3JldDEyMw=='); - const body = mockFetch.mock.calls[0][1].body as URLSearchParams; + const body = mockFetch.mock.calls[0]![1].body as URLSearchParams; expect(body.get('grant_type')).toBe('refresh_token'); expect(body.get('refresh_token')).toBe('refresh123'); expect(body.get('client_id')).toBeNull(); @@ -1740,10 +1744,10 @@ describe('OAuth Authorization', () => { expect(mockFetch).toHaveBeenCalledTimes(3); // First call should be to protected resource metadata - expect(mockFetch.mock.calls[0][0].toString()).toBe('https://resource.example.com/.well-known/oauth-protected-resource'); + expect(mockFetch.mock.calls[0]![0].toString()).toBe('https://resource.example.com/.well-known/oauth-protected-resource'); // Second call should be to oauth metadata at the root path - expect(mockFetch.mock.calls[1][0].toString()).toBe('https://resource.example.com/.well-known/oauth-authorization-server'); + expect(mockFetch.mock.calls[1]![0].toString()).toBe('https://resource.example.com/.well-known/oauth-authorization-server'); }); it('uses base URL (with root path) as authorization server when protected-resource-metadata discovery fails', async () => { @@ -1869,7 +1873,7 @@ describe('OAuth Authorization', () => { }) ); - const redirectCall = (mockProvider.redirectToAuthorization as Mock).mock.calls[0]; + const redirectCall = (mockProvider.redirectToAuthorization as Mock).mock.calls[0]!; const authUrl: URL = redirectCall[0]; expect(authUrl.searchParams.get('resource')).toBe('https://api.example.com/mcp-server'); }); @@ -2126,7 +2130,7 @@ describe('OAuth Authorization', () => { }) ); - const redirectCall = (mockProvider.redirectToAuthorization as Mock).mock.calls[0]; + const redirectCall = (mockProvider.redirectToAuthorization as Mock).mock.calls[0]!; const authUrl: URL = redirectCall[0]; // Should use the PRM's resource value, not the full requested URL expect(authUrl.searchParams.get('resource')).toBe('https://api.example.com/'); @@ -2184,7 +2188,7 @@ describe('OAuth Authorization', () => { }) ); - const redirectCall = (mockProvider.redirectToAuthorization as Mock).mock.calls[0]; + const redirectCall = (mockProvider.redirectToAuthorization as Mock).mock.calls[0]!; const authUrl: URL = redirectCall[0]; // Resource parameter should not be present when PRM is not available expect(authUrl.searchParams.has('resource')).toBe(false); @@ -2379,9 +2383,9 @@ describe('OAuth Authorization', () => { expect(result).toBe('REDIRECT'); // Verify the authorization URL includes the scopes from PRM - const redirectCall = (mockProvider.redirectToAuthorization as Mock).mock.calls[0]; + const redirectCall = (mockProvider.redirectToAuthorization as Mock).mock.calls[0]!; const authUrl: URL = redirectCall[0]; - expect(authUrl.searchParams.get('scope')).toBe('mcp:read mcp:write mcp:admin'); + expect(authUrl?.searchParams.get('scope')).toBe('mcp:read mcp:write mcp:admin'); }); it('prefers explicit scope parameter over scopes_supported from PRM', async () => { @@ -2444,7 +2448,7 @@ describe('OAuth Authorization', () => { expect(result).toBe('REDIRECT'); // Verify the authorization URL uses the explicit scope, not scopes_supported - const redirectCall = (mockProvider.redirectToAuthorization as Mock).mock.calls[0]; + const redirectCall = (mockProvider.redirectToAuthorization as Mock).mock.calls[0]!; const authUrl: URL = redirectCall[0]; expect(authUrl.searchParams.get('scope')).toBe('mcp:read'); }); @@ -2501,10 +2505,10 @@ describe('OAuth Authorization', () => { const calls = mockFetch.mock.calls; // First call should be to PRM - expect(calls[0][0].toString()).toBe('https://my.resource.com/.well-known/oauth-protected-resource/path/name'); + expect(calls[0]![0].toString()).toBe('https://my.resource.com/.well-known/oauth-protected-resource/path/name'); // Second call should be to AS metadata with the path from authorization server - expect(calls[1][0].toString()).toBe('https://auth.example.com/.well-known/oauth-authorization-server/oauth'); + expect(calls[1]![0].toString()).toBe('https://auth.example.com/.well-known/oauth-authorization-server/oauth'); }); it('supports overriding the fetch function used for requests', async () => { @@ -2565,10 +2569,10 @@ describe('OAuth Authorization', () => { expect(mockFetch).not.toHaveBeenCalled(); // Verify custom fetch was called for PRM discovery - expect(customFetch.mock.calls[0][0].toString()).toBe('https://resource.example.com/.well-known/oauth-protected-resource'); + expect(customFetch.mock.calls[0]![0].toString()).toBe('https://resource.example.com/.well-known/oauth-protected-resource'); // Verify custom fetch was called for AS metadata discovery - expect(customFetch.mock.calls[1][0].toString()).toBe('https://auth.example.com/.well-known/oauth-authorization-server'); + expect(customFetch.mock.calls[1]![0].toString()).toBe('https://auth.example.com/.well-known/oauth-authorization-server'); }); }); @@ -2627,7 +2631,7 @@ describe('OAuth Authorization', () => { }); expect(tokens).toEqual(validTokens); - const request = mockFetch.mock.calls[0][1]; + const request = mockFetch.mock.calls[0]![1]; // Check Authorization header const authHeader = request.headers.get('Authorization'); @@ -2655,7 +2659,7 @@ describe('OAuth Authorization', () => { }); expect(tokens).toEqual(validTokens); - const request = mockFetch.mock.calls[0][1]; + const request = mockFetch.mock.calls[0]![1]; // Check no Authorization header expect(request.headers.get('Authorization')).toBeNull(); @@ -2681,7 +2685,7 @@ describe('OAuth Authorization', () => { }); expect(tokens).toEqual(validTokens); - const request = mockFetch.mock.calls[0][1]; + const request = mockFetch.mock.calls[0]![1]; // Check Authorization header - should use Basic auth as it's the most secure const authHeader = request.headers.get('Authorization'); @@ -2716,7 +2720,7 @@ describe('OAuth Authorization', () => { }); expect(tokens).toEqual(validTokens); - const request = mockFetch.mock.calls[0][1]; + const request = mockFetch.mock.calls[0]![1]; // Check no Authorization header expect(request.headers.get('Authorization')).toBeNull(); @@ -2741,7 +2745,7 @@ describe('OAuth Authorization', () => { }); expect(tokens).toEqual(validTokens); - const request = mockFetch.mock.calls[0][1]; + const request = mockFetch.mock.calls[0]![1]; // Check headers expect(request.headers.get('Content-Type')).toBe('application/x-www-form-urlencoded'); @@ -2795,7 +2799,7 @@ describe('OAuth Authorization', () => { }); expect(tokens).toEqual(validTokens); - const request = mockFetch.mock.calls[0][1]; + const request = mockFetch.mock.calls[0]![1]; // Check Authorization header const authHeader = request.headers.get('Authorization'); @@ -2822,7 +2826,7 @@ describe('OAuth Authorization', () => { }); expect(tokens).toEqual(validTokens); - const request = mockFetch.mock.calls[0][1]; + const request = mockFetch.mock.calls[0]![1]; // Check no Authorization header expect(request.headers.get('Authorization')).toBeNull(); @@ -2836,7 +2840,7 @@ describe('OAuth Authorization', () => { describe('RequestInit headers passthrough', () => { it('custom headers from RequestInit are passed to auth discovery requests', async () => { - const { createFetchWithInit } = await import('../../src/shared/transport.js'); + const { createFetchWithInit } = await import('@modelcontextprotocol/sdk-core'); const customFetch = vi.fn().mockResolvedValue({ ok: true, @@ -2858,7 +2862,7 @@ describe('OAuth Authorization', () => { await discoverOAuthProtectedResourceMetadata('https://resource.example.com', undefined, wrappedFetch); expect(customFetch).toHaveBeenCalledTimes(1); - const [url, options] = customFetch.mock.calls[0]; + const [url, options] = customFetch.mock.calls[0]!; expect(url.toString()).toBe('https://resource.example.com/.well-known/oauth-protected-resource'); expect(options.headers).toMatchObject({ @@ -2869,7 +2873,7 @@ describe('OAuth Authorization', () => { }); it('auth-specific headers override base headers from RequestInit', async () => { - const { createFetchWithInit } = await import('../../src/shared/transport.js'); + const { createFetchWithInit } = await import('@modelcontextprotocol/sdk-core'); const customFetch = vi.fn().mockResolvedValue({ ok: true, @@ -2896,7 +2900,7 @@ describe('OAuth Authorization', () => { }); expect(customFetch).toHaveBeenCalled(); - const [, options] = customFetch.mock.calls[0]; + const [, options] = customFetch.mock.calls[0]!; // Auth-specific Accept header should override base Accept header expect(options.headers).toMatchObject({ @@ -2907,7 +2911,7 @@ describe('OAuth Authorization', () => { }); it('other RequestInit options are passed through', async () => { - const { createFetchWithInit } = await import('../../src/shared/transport.js'); + const { createFetchWithInit } = await import('@modelcontextprotocol/sdk-core'); const customFetch = vi.fn().mockResolvedValue({ ok: true, @@ -2931,7 +2935,7 @@ describe('OAuth Authorization', () => { await discoverOAuthProtectedResourceMetadata('https://resource.example.com', undefined, wrappedFetch); expect(customFetch).toHaveBeenCalledTimes(1); - const [, options] = customFetch.mock.calls[0]; + const [, options] = customFetch.mock.calls[0]!; // All RequestInit options should be preserved expect(options.credentials).toBe('include'); diff --git a/test/client/cross-spawn.test.ts b/packages/client/test/client/cross-spawn.test.ts similarity index 98% rename from test/client/cross-spawn.test.ts rename to packages/client/test/client/cross-spawn.test.ts index 26ae682fe..136330ecd 100644 --- a/test/client/cross-spawn.test.ts +++ b/packages/client/test/client/cross-spawn.test.ts @@ -1,6 +1,6 @@ import { StdioClientTransport, getDefaultEnvironment } from '../../src/client/stdio.js'; import spawn from 'cross-spawn'; -import { JSONRPCMessage } from '../../src/types.js'; +import { JSONRPCMessage } from '@modelcontextprotocol/sdk-core'; import { ChildProcess } from 'node:child_process'; import { Mock, MockedFunction } from 'vitest'; diff --git a/test/client/middleware.test.ts b/packages/client/test/client/middleware.test.ts similarity index 97% rename from test/client/middleware.test.ts rename to packages/client/test/client/middleware.test.ts index 06bda69c8..ab017b638 100644 --- a/test/client/middleware.test.ts +++ b/packages/client/test/client/middleware.test.ts @@ -1,6 +1,6 @@ import { withOAuth, withLogging, applyMiddlewares, createMiddleware } from '../../src/client/middleware.js'; import { OAuthClientProvider } from '../../src/client/auth.js'; -import { FetchLike } from '../../src/shared/transport.js'; +import type { FetchLike } from '@modelcontextprotocol/sdk-core'; import { MockInstance, Mocked, MockedFunction } from 'vitest'; vi.mock('../../src/client/auth.js', async () => { @@ -64,7 +64,7 @@ describe('withOAuth', () => { ); const callArgs = mockFetch.mock.calls[0]; - const headers = callArgs[1]?.headers as Headers; + const headers = callArgs![1]?.headers as Headers; expect(headers.get('Authorization')).toBe('Bearer test-token'); }); @@ -90,7 +90,7 @@ describe('withOAuth', () => { ); const callArgs = mockFetch.mock.calls[0]; - const headers = callArgs[1]?.headers as Headers; + const headers = callArgs![1]?.headers as Headers; expect(headers.get('Authorization')).toBe('Bearer test-token'); }); @@ -105,7 +105,7 @@ describe('withOAuth', () => { expect(mockFetch).toHaveBeenCalledTimes(1); const callArgs = mockFetch.mock.calls[0]; - const headers = callArgs[1]?.headers as Headers; + const headers = callArgs![1]?.headers as Headers; expect(headers.get('Authorization')).toBeNull(); }); @@ -152,7 +152,7 @@ describe('withOAuth', () => { // Verify the retry used the new token const retryCallArgs = mockFetch.mock.calls[1]; - const retryHeaders = retryCallArgs[1]?.headers as Headers; + const retryHeaders = retryCallArgs![1]?.headers as Headers; expect(retryHeaders.get('Authorization')).toBe('Bearer new-token'); }); @@ -200,7 +200,7 @@ describe('withOAuth', () => { // Verify the retry used the new token const retryCallArgs = mockFetch.mock.calls[1]; - const retryHeaders = retryCallArgs[1]?.headers as Headers; + const retryHeaders = retryCallArgs![1]?.headers as Headers; expect(retryHeaders.get('Authorization')).toBe('Bearer new-token'); }); @@ -290,7 +290,7 @@ describe('withOAuth', () => { ); const callArgs = mockFetch.mock.calls[0]; - const headers = callArgs[1]?.headers as Headers; + const headers = callArgs![1]?.headers as Headers; expect(headers.get('Content-Type')).toBe('application/json'); expect(headers.get('Authorization')).toBe('Bearer test-token'); }); @@ -492,7 +492,7 @@ describe('withLogging', () => { responseHeaders: undefined }); - const logCall = mockLogger.mock.calls[0][0]; + const logCall = mockLogger.mock.calls[0]![0]; expect(logCall.requestHeaders?.get('Authorization')).toBe('Bearer token'); expect(logCall.requestHeaders?.get('Content-Type')).toBe('application/json'); }); @@ -515,7 +515,7 @@ describe('withLogging', () => { await enhancedFetch('https://api.example.com/data'); - const logCall = mockLogger.mock.calls[0][0]; + const logCall = mockLogger.mock.calls[0]![0]; expect(logCall.responseHeaders?.get('Content-Type')).toBe('application/json'); expect(logCall.responseHeaders?.get('Cache-Control')).toBe('no-cache'); }); @@ -609,7 +609,7 @@ describe('withLogging', () => { await enhancedFetch('https://api.example.com/data'); - const logCall = mockLogger.mock.calls[0][0]; + const logCall = mockLogger.mock.calls[0]![0]; expect(logCall.duration).toBeGreaterThanOrEqual(90); // Allow some margin for timing }); }); @@ -654,7 +654,7 @@ describe('applyMiddleware', () => { ); const callArgs = mockFetch.mock.calls[0]; - const headers = callArgs[1]?.headers as Headers; + const headers = callArgs![1]?.headers as Headers; expect(headers.get('X-Middleware-1')).toBe('applied'); }); @@ -686,7 +686,7 @@ describe('applyMiddleware', () => { await composedFetch('https://api.example.com/data'); const callArgs = mockFetch.mock.calls[0]; - const headers = callArgs[1]?.headers as Headers; + const headers = callArgs![1]?.headers as Headers; expect(headers.get('X-Middleware-1')).toBe('applied'); expect(headers.get('X-Middleware-2')).toBe('applied'); expect(headers.get('X-Middleware-3')).toBe('applied'); @@ -711,7 +711,7 @@ describe('applyMiddleware', () => { // Should have both Authorization header and logging const callArgs = mockFetch.mock.calls[0]; - const headers = callArgs[1]?.headers as Headers; + const headers = callArgs![1]?.headers as Headers; expect(headers.get('Authorization')).toBe('Bearer test-token'); expect(mockLogger).toHaveBeenCalledWith({ method: 'GET', @@ -811,7 +811,7 @@ describe('Integration Tests', () => { ); const callArgs = mockFetch.mock.calls[0]; - const headers = callArgs[1]?.headers as Headers; + const headers = callArgs![1]?.headers as Headers; expect(headers.get('Authorization')).toBe('Bearer sse-token'); expect(headers.get('Content-Type')).toBe('application/json'); }); @@ -857,7 +857,7 @@ describe('Integration Tests', () => { }); const callArgs = mockFetch.mock.calls[0]; - const headers = callArgs[1]?.headers as Headers; + const headers = callArgs![1]?.headers as Headers; expect(headers.get('Authorization')).toBe('Bearer streamable-token'); expect(headers.get('Accept')).toBe('application/json, text/event-stream'); }); @@ -943,7 +943,7 @@ describe('createMiddleware', () => { ); const callArgs = mockFetch.mock.calls[0]; - const headers = callArgs[1]?.headers as Headers; + const headers = callArgs![1]?.headers as Headers; expect(headers.get('X-Custom-Header')).toBe('custom-value'); }); @@ -969,13 +969,13 @@ describe('createMiddleware', () => { // Test API route await enhancedFetch('https://example.com/api/users'); let callArgs = mockFetch.mock.calls[0]; - const headers = callArgs[1]?.headers as Headers; + const headers = callArgs![1]?.headers as Headers; expect(headers.get('X-API-Version')).toBe('v2'); // Test non-API route await enhancedFetch('https://example.com/public/page'); callArgs = mockFetch.mock.calls[1]; - const maybeHeaders = callArgs[1]?.headers as Headers | undefined; + const maybeHeaders = callArgs![1]?.headers as Headers | undefined; expect(maybeHeaders?.get('X-API-Version')).toBeUndefined(); }); @@ -1091,7 +1091,7 @@ describe('createMiddleware', () => { await enhancedFetch('https://api.example.com/data'); const callArgs = mockFetch.mock.calls[0]; - const headers = callArgs[1]?.headers as Headers; + const headers = callArgs![1]?.headers as Headers; expect(headers.get('Authorization')).toBe('Custom token'); }); diff --git a/test/client/sse.test.ts b/packages/client/test/client/sse.test.ts similarity index 99% rename from test/client/sse.test.ts rename to packages/client/test/client/sse.test.ts index 6574b60b8..5fc38e5b7 100644 --- a/test/client/sse.test.ts +++ b/packages/client/test/client/sse.test.ts @@ -1,9 +1,13 @@ import { createServer, ServerResponse, type IncomingMessage, type Server } from 'node:http'; -import { JSONRPCMessage } from '../../src/types.js'; +import { + JSONRPCMessage, + InvalidClientError, + InvalidGrantError, + UnauthorizedClientError, + OAuthTokens +} from '@modelcontextprotocol/sdk-core'; import { SSEClientTransport } from '../../src/client/sse.js'; import { OAuthClientProvider, UnauthorizedError } from '../../src/client/auth.js'; -import { OAuthTokens } from '../../src/shared/auth.js'; -import { InvalidClientError, InvalidGrantError, UnauthorizedClientError } from '../../src/server/auth/errors.js'; import { Mock, Mocked, MockedFunction, MockInstance } from 'vitest'; import { listenOnRandomPort } from '../helpers/http.js'; import { AddressInfo } from 'node:net'; @@ -169,7 +173,7 @@ describe('SSEClientTransport', () => { await new Promise(resolve => setTimeout(resolve, 50)); expect(errors).toHaveLength(1); - expect(errors[0].message).toMatch(/JSON/); + expect(errors[0]!.message).toMatch(/JSON/); }); it('handles messages via POST requests', async () => { @@ -310,7 +314,7 @@ describe('SSEClientTransport', () => { await transport.send(message); - const calledHeaders = (global.fetch as Mock).mock.calls[0][1].headers; + const calledHeaders = (global.fetch as Mock).mock.calls[0]![1].headers; expect(calledHeaders.get('Authorization')).toBe('Bearer test-token'); expect(calledHeaders.get('X-Custom-Header')).toBe('custom-value'); expect(calledHeaders.get('content-type')).toBe('application/json'); @@ -319,7 +323,7 @@ describe('SSEClientTransport', () => { await transport.send(message); - const updatedHeaders = (global.fetch as Mock).mock.calls[1][1].headers; + const updatedHeaders = (global.fetch as Mock).mock.calls[1]![1].headers; expect(updatedHeaders.get('X-Custom-Header')).toBe('updated-value'); } finally { global.fetch = originalFetch; @@ -353,7 +357,7 @@ describe('SSEClientTransport', () => { await transport.send(message); - const calledHeaders = (global.fetch as Mock).mock.calls[0][1].headers; + const calledHeaders = (global.fetch as Mock).mock.calls[0]![1].headers; expect(calledHeaders.get('Authorization')).toBe('Bearer test-token'); expect(calledHeaders.get('X-Custom-Header')).toBe('custom-value'); expect(calledHeaders.get('content-type')).toBe('application/json'); @@ -362,7 +366,7 @@ describe('SSEClientTransport', () => { await transport.send(message); - const updatedHeaders = (global.fetch as Mock).mock.calls[1][1].headers; + const updatedHeaders = (global.fetch as Mock).mock.calls[1]![1].headers; expect(updatedHeaders.get('X-Custom-Header')).toBe('updated-value'); } finally { global.fetch = originalFetch; @@ -387,7 +391,7 @@ describe('SSEClientTransport', () => { await transport.send({ jsonrpc: '2.0', id: '1', method: 'test', params: {} }); - const calledHeaders = (global.fetch as Mock).mock.calls[0][1].headers; + const calledHeaders = (global.fetch as Mock).mock.calls[0]![1].headers; expect(calledHeaders.get('Authorization')).toBe('Bearer test-token'); expect(calledHeaders.get('X-Custom-Header')).toBe('custom-value'); expect(calledHeaders.get('content-type')).toBe('application/json'); diff --git a/test/client/stdio.test.ts b/packages/client/test/client/stdio.test.ts similarity index 93% rename from test/client/stdio.test.ts rename to packages/client/test/client/stdio.test.ts index 52a871ee1..470939865 100644 --- a/test/client/stdio.test.ts +++ b/packages/client/test/client/stdio.test.ts @@ -1,4 +1,4 @@ -import { JSONRPCMessage } from '../../src/types.js'; +import { JSONRPCMessage } from '@modelcontextprotocol/sdk-core'; import { StdioClientTransport, StdioServerParameters } from '../../src/client/stdio.js'; // Configure default server parameters based on OS @@ -59,8 +59,8 @@ test('should read messages', async () => { }); await client.start(); - await client.send(messages[0]); - await client.send(messages[1]); + await client.send(messages[0]!); + await client.send(messages[1]!); await finished; expect(readMessages).toEqual(messages); diff --git a/test/client/streamableHttp.test.ts b/packages/client/test/client/streamableHttp.test.ts similarity index 98% rename from test/client/streamableHttp.test.ts rename to packages/client/test/client/streamableHttp.test.ts index 52c8f1074..84fa4358a 100644 --- a/test/client/streamableHttp.test.ts +++ b/packages/client/test/client/streamableHttp.test.ts @@ -1,7 +1,7 @@ import { StartSSEOptions, StreamableHTTPClientTransport, StreamableHTTPReconnectionOptions } from '../../src/client/streamableHttp.js'; import { OAuthClientProvider, UnauthorizedError } from '../../src/client/auth.js'; -import { JSONRPCMessage, JSONRPCRequest } from '../../src/types.js'; -import { InvalidClientError, InvalidGrantError, UnauthorizedClientError } from '../../src/server/auth/errors.js'; +import { JSONRPCMessage, JSONRPCRequest } from '@modelcontextprotocol/sdk-core'; +import { InvalidClientError, InvalidGrantError, UnauthorizedClientError } from '@modelcontextprotocol/sdk-core'; import { type Mock, type Mocked } from 'vitest'; describe('StreamableHTTPClientTransport', () => { @@ -114,7 +114,7 @@ describe('StreamableHTTPClientTransport', () => { // Check that second request included session ID header const calls = (global.fetch as Mock).mock.calls; - const lastCall = calls[calls.length - 1]; + const lastCall = calls[calls.length - 1]!; expect(lastCall[1].headers).toBeDefined(); expect(lastCall[1].headers.get('mcp-session-id')).toBe('test-session-id'); }); @@ -151,7 +151,7 @@ describe('StreamableHTTPClientTransport', () => { // Verify the DELETE request was sent with the session ID const calls = (global.fetch as Mock).mock.calls; - const lastCall = calls[calls.length - 1]; + const lastCall = calls[calls.length - 1]!; expect(lastCall[1].method).toBe('DELETE'); expect(lastCall[1].headers.get('mcp-session-id')).toBe('test-session-id'); @@ -412,7 +412,7 @@ describe('StreamableHTTPClientTransport', () => { // Verify fetch was called with the lastEventId header expect(fetchSpy).toHaveBeenCalled(); - const fetchCall = fetchSpy.mock.calls[0]; + const fetchCall = fetchSpy.mock.calls[0]!; const headers = fetchCall[1].headers; expect(headers.get('last-event-id')).toBe('test-event-id'); }); @@ -772,8 +772,8 @@ describe('StreamableHTTPClientTransport', () => { ); // THE KEY ASSERTION: A second fetch call proves reconnection was attempted. expect(fetchMock).toHaveBeenCalledTimes(2); - expect(fetchMock.mock.calls[0][1]?.method).toBe('GET'); - expect(fetchMock.mock.calls[1][1]?.method).toBe('GET'); + expect(fetchMock.mock.calls[0]![1]?.method).toBe('GET'); + expect(fetchMock.mock.calls[1]![1]?.method).toBe('GET'); }); it('should NOT reconnect a POST-initiated stream that fails', async () => { @@ -822,7 +822,7 @@ describe('StreamableHTTPClientTransport', () => { // ASSERT // THE KEY ASSERTION: Fetch was only called ONCE. No reconnection was attempted. expect(fetchMock).toHaveBeenCalledTimes(1); - expect(fetchMock.mock.calls[0][1]?.method).toBe('POST'); + expect(fetchMock.mock.calls[0]![1]?.method).toBe('POST'); }); it('should reconnect a POST-initiated stream after receiving a priming event', async () => { @@ -938,7 +938,7 @@ describe('StreamableHTTPClientTransport', () => { // THE KEY ASSERTION: Fetch was called ONCE only - no reconnection! // The response was received, so no need to reconnect. expect(fetchMock).toHaveBeenCalledTimes(1); - expect(fetchMock.mock.calls[0][1]?.method).toBe('POST'); + expect(fetchMock.mock.calls[0]![1]?.method).toBe('POST'); }); it('should not attempt reconnection after close() is called', async () => { @@ -989,7 +989,7 @@ describe('StreamableHTTPClientTransport', () => { // ASSERT // Only 1 call: the initial POST. No reconnection attempts after close(). expect(fetchMock).toHaveBeenCalledTimes(1); - expect(fetchMock.mock.calls[0][1]?.method).toBe('POST'); + expect(fetchMock.mock.calls[0]![1]?.method).toBe('POST'); }); it('should not throw JSON parse error on priming events with empty data', async () => { @@ -1487,11 +1487,11 @@ describe('StreamableHTTPClientTransport', () => { // Should have attempted reconnection expect(fetchMock).toHaveBeenCalledTimes(2); - expect(fetchMock.mock.calls[0][1]?.method).toBe('GET'); - expect(fetchMock.mock.calls[1][1]?.method).toBe('GET'); + expect(fetchMock.mock.calls[0]![1]?.method).toBe('GET'); + expect(fetchMock.mock.calls[1]![1]?.method).toBe('GET'); // Second call should include Last-Event-ID - const secondCallHeaders = fetchMock.mock.calls[1][1]?.headers; + const secondCallHeaders = fetchMock.mock.calls[1]![1]?.headers; expect(secondCallHeaders?.get('last-event-id')).toBe('evt-1'); }); }); diff --git a/test/helpers/http.ts b/packages/client/test/helpers/http.ts similarity index 100% rename from test/helpers/http.ts rename to packages/client/test/helpers/http.ts diff --git a/packages/client/test/helpers/mcp.ts b/packages/client/test/helpers/mcp.ts new file mode 100644 index 000000000..e56ca6b56 --- /dev/null +++ b/packages/client/test/helpers/mcp.ts @@ -0,0 +1,71 @@ +import { InMemoryTransport } from '@modelcontextprotocol/sdk-server'; +import { Client } from '@modelcontextprotocol/sdk-client'; +import { Server } from '@modelcontextprotocol/sdk-server'; +import { InMemoryTaskStore, InMemoryTaskMessageQueue } from '@modelcontextprotocol/sdk-server'; +import type { ClientCapabilities, ServerCapabilities } from '@modelcontextprotocol/sdk-server'; + +export interface InMemoryTaskEnvironment { + client: Client; + server: Server; + taskStore: InMemoryTaskStore; + clientTransport: InMemoryTransport; + serverTransport: InMemoryTransport; +} + +export async function createInMemoryTaskEnvironment(options?: { + clientCapabilities?: ClientCapabilities; + serverCapabilities?: ServerCapabilities; +}): Promise { + const taskStore = new InMemoryTaskStore(); + const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair(); + + const client = new Client( + { + name: 'test-client', + version: '1.0.0' + }, + { + capabilities: options?.clientCapabilities ?? { + tasks: { + list: {}, + requests: { + tools: { + call: {} + } + } + } + } + } + ); + + const server = new Server( + { + name: 'test-server', + version: '1.0.0' + }, + { + capabilities: options?.serverCapabilities ?? { + tasks: { + list: {}, + requests: { + tools: { + call: {} + } + } + } + }, + taskStore, + taskMessageQueue: new InMemoryTaskMessageQueue() + } + ); + + await Promise.all([client.connect(clientTransport), server.connect(serverTransport)]); + + return { + client, + server, + taskStore, + clientTransport, + serverTransport + }; +} diff --git a/test/helpers/oauth.ts b/packages/client/test/helpers/oauth.ts similarity index 95% rename from test/helpers/oauth.ts rename to packages/client/test/helpers/oauth.ts index c08350eff..b5e504f68 100644 --- a/test/helpers/oauth.ts +++ b/packages/client/test/helpers/oauth.ts @@ -1,4 +1,5 @@ -import type { FetchLike } from '../../src/shared/transport.js'; +import type { FetchLike } from '@modelcontextprotocol/sdk-core'; +import { vi } from 'vitest'; export interface MockOAuthFetchOptions { resourceServerUrl: string; @@ -79,7 +80,7 @@ export function createMockOAuthFetch(options: MockOAuthFetchOptions): FetchLike /** * Helper to install a vi.fn-based global.fetch mock for tests that rely on global fetch. */ -export function mockGlobalFetch() { +export function mockGlobalFetch(): (...args: any[]) => any { const mockFetch = vi.fn(); // eslint-disable-next-line @typescript-eslint/no-explicit-any (globalThis as any).fetch = mockFetch; diff --git a/packages/client/tsconfig.build.json b/packages/client/tsconfig.build.json new file mode 100644 index 000000000..eabb8d8ff --- /dev/null +++ b/packages/client/tsconfig.build.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "./dist", + "rootDir": "./src" + }, + "include": ["./"], + "exclude": ["dist", "node_modules", "test"] +} diff --git a/packages/client/tsconfig.json b/packages/client/tsconfig.json new file mode 100644 index 000000000..862c7a523 --- /dev/null +++ b/packages/client/tsconfig.json @@ -0,0 +1,15 @@ +{ + "extends": "@modelcontextprotocol/tsconfig", + "include": ["./"], + "exclude": ["node_modules", "dist"], + "compilerOptions": { + "baseUrl": ".", + "paths": { + "*": ["./*"], + "@modelcontextprotocol/sdk-core": ["node_modules/@modelcontextprotocol/sdk-core/src/index.ts"], + "@modelcontextprotocol/sdk-client": ["node_modules/@modelcontextprotocol/sdk-client/src/index.ts"], + "@modelcontextprotocol/vitest-config": ["node_modules/@modelcontextprotocol/vitest-config/tsconfig.json"], + "@modelcontextprotocol/eslint-config": ["node_modules/@modelcontextprotocol/eslint-config/tsconfig.json"] + } + } +} diff --git a/packages/client/vitest.config.js b/packages/client/vitest.config.js new file mode 100644 index 000000000..2012fa59e --- /dev/null +++ b/packages/client/vitest.config.js @@ -0,0 +1,8 @@ +import baseConfig from '@modelcontextprotocol/vitest-config'; +import { mergeConfig } from 'vitest/config'; + +export default mergeConfig(baseConfig, { + test: { + setupFiles: ['./vitest.setup.js'] + } +}); diff --git a/vitest.setup.ts b/packages/client/vitest.setup.js similarity index 70% rename from vitest.setup.ts rename to packages/client/vitest.setup.js index 820dcbd89..d6e9c6678 100644 --- a/vitest.setup.ts +++ b/packages/client/vitest.setup.js @@ -3,6 +3,5 @@ import { webcrypto } from 'node:crypto'; // Polyfill globalThis.crypto for environments (e.g. Node 18) where it is not defined. // This is necessary for the tests to run in Node 18, specifically for the jose library, which relies on the globalThis.crypto object. if (typeof globalThis.crypto === 'undefined') { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (globalThis as any).crypto = webcrypto as unknown as Crypto; + globalThis.crypto = webcrypto; } diff --git a/packages/core/eslint.config.mjs b/packages/core/eslint.config.mjs new file mode 100644 index 000000000..951c9f3a9 --- /dev/null +++ b/packages/core/eslint.config.mjs @@ -0,0 +1,5 @@ +// @ts-check + +import baseConfig from '@modelcontextprotocol/eslint-config'; + +export default baseConfig; diff --git a/packages/core/package.json b/packages/core/package.json new file mode 100644 index 000000000..9c153acdc --- /dev/null +++ b/packages/core/package.json @@ -0,0 +1,111 @@ +{ + "name": "@modelcontextprotocol/sdk-core", + "private": true, + "version": "2.0.0-alpha.0", + "description": "Model Context Protocol implementation for TypeScript", + "license": "MIT", + "author": "Anthropic, PBC (https://anthropic.com)", + "homepage": "https://modelcontextprotocol.io", + "bugs": "https://github.com/modelcontextprotocol/typescript-sdk/issues", + "type": "module", + "repository": { + "type": "git", + "url": "git+https://github.com/modelcontextprotocol/typescript-sdk.git" + }, + "engines": { + "node": ">=18" + }, + "keywords": [ + "modelcontextprotocol", + "mcp" + ], + "exports": { + ".": { + "import": "./dist/index.js" + }, + "./types": { + "import": "./dist/exports/types/index.js" + }, + "./test-helpers": { + "import": "./dist/exports/test-helpers/index.js" + } + }, + "typesVersions": { + "*": { + "*": [ + "./dist/*" + ] + } + }, + "files": [ + "dist" + ], + "scripts": { + "fetch:spec-types": "tsx scripts/fetch-spec-types.ts", + "typecheck": "tsc -p tsconfig.build.json --noEmit", + "examples:simple-server:w": "tsx --watch src/examples/server/simpleStreamableHttp.ts --oauth", + "lint": "eslint src/ && prettier --check .", + "lint:fix": "eslint src/ --fix && prettier --write .", + "check": "npm run typecheck && npm run lint", + "test": "vitest run", + "test:watch": "vitest", + "start": "npm run server", + "server": "tsx watch --clear-screen=false scripts/cli.ts server", + "client": "tsx scripts/cli.ts client" + }, + "dependencies": { + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1", + "content-type": "^1.0.5", + "cors": "^2.8.5", + "cross-spawn": "^7.0.5", + "eventsource": "^3.0.2", + "eventsource-parser": "^3.0.0", + "express": "^5.0.1", + "express-rate-limit": "^7.5.0", + "jose": "^6.1.1", + "json-schema-typed": "^8.0.2", + "pkce-challenge": "^5.0.0", + "raw-body": "^3.0.0", + "zod": "^3.25 || ^4.0", + "zod-to-json-schema": "^3.25.0" + }, + "peerDependencies": { + "@cfworker/json-schema": "^4.1.1", + "zod": "^3.25 || ^4.0" + }, + "peerDependenciesMeta": { + "@cfworker/json-schema": { + "optional": true + }, + "zod": { + "optional": false + } + }, + "devDependencies": { + "@modelcontextprotocol/tsconfig": "workspace:^", + "@modelcontextprotocol/vitest-config": "workspace:^", + "@modelcontextprotocol/eslint-config": "workspace:^", + "@cfworker/json-schema": "^4.1.1", + "@eslint/js": "^9.39.1", + "@types/content-type": "^1.1.8", + "@types/cors": "^2.8.17", + "@types/cross-spawn": "^6.0.6", + "@types/eventsource": "^1.1.15", + "@types/express": "^5.0.0", + "@types/express-serve-static-core": "^5.1.0", + "@types/supertest": "^6.0.2", + "@types/ws": "^8.5.12", + "@typescript/native-preview": "^7.0.0-dev.20251103.1", + "eslint": "^9.8.0", + "eslint-config-prettier": "^10.1.8", + "eslint-plugin-n": "^17.23.1", + "prettier": "3.6.2", + "supertest": "^7.0.0", + "tsx": "^4.16.5", + "typescript": "^5.5.4", + "typescript-eslint": "^8.48.1", + "vitest": "^4.0.8", + "ws": "^8.18.0" + } +} diff --git a/src/server/auth/errors.ts b/packages/core/src/auth/errors.ts similarity index 84% rename from src/server/auth/errors.ts rename to packages/core/src/auth/errors.ts index dff413e38..d145b6296 100644 --- a/src/server/auth/errors.ts +++ b/packages/core/src/auth/errors.ts @@ -1,4 +1,4 @@ -import { OAuthErrorResponse } from '../../shared/auth.js'; +import type { OAuthErrorResponse } from '../shared/auth.js'; /** * Base class for all OAuth errors @@ -41,7 +41,7 @@ export class OAuthError extends Error { * or is otherwise malformed. */ export class InvalidRequestError extends OAuthError { - static errorCode = 'invalid_request'; + static override errorCode = 'invalid_request'; } /** @@ -49,7 +49,7 @@ export class InvalidRequestError extends OAuthError { * authentication included, or unsupported authentication method). */ export class InvalidClientError extends OAuthError { - static errorCode = 'invalid_client'; + static override errorCode = 'invalid_client'; } /** @@ -58,7 +58,7 @@ export class InvalidClientError extends OAuthError { * authorization request, or was issued to another client. */ export class InvalidGrantError extends OAuthError { - static errorCode = 'invalid_grant'; + static override errorCode = 'invalid_grant'; } /** @@ -66,7 +66,7 @@ export class InvalidGrantError extends OAuthError { * this authorization grant type. */ export class UnauthorizedClientError extends OAuthError { - static errorCode = 'unauthorized_client'; + static override errorCode = 'unauthorized_client'; } /** @@ -74,7 +74,7 @@ export class UnauthorizedClientError extends OAuthError { * by the authorization server. */ export class UnsupportedGrantTypeError extends OAuthError { - static errorCode = 'unsupported_grant_type'; + static override errorCode = 'unsupported_grant_type'; } /** @@ -82,14 +82,14 @@ export class UnsupportedGrantTypeError extends OAuthError { * exceeds the scope granted by the resource owner. */ export class InvalidScopeError extends OAuthError { - static errorCode = 'invalid_scope'; + static override errorCode = 'invalid_scope'; } /** * Access denied error - The resource owner or authorization server denied the request. */ export class AccessDeniedError extends OAuthError { - static errorCode = 'access_denied'; + static override errorCode = 'access_denied'; } /** @@ -97,7 +97,7 @@ export class AccessDeniedError extends OAuthError { * that prevented it from fulfilling the request. */ export class ServerError extends OAuthError { - static errorCode = 'server_error'; + static override errorCode = 'server_error'; } /** @@ -105,7 +105,7 @@ export class ServerError extends OAuthError { * handle the request due to a temporary overloading or maintenance of the server. */ export class TemporarilyUnavailableError extends OAuthError { - static errorCode = 'temporarily_unavailable'; + static override errorCode = 'temporarily_unavailable'; } /** @@ -113,7 +113,7 @@ export class TemporarilyUnavailableError extends OAuthError { * obtaining an authorization code using this method. */ export class UnsupportedResponseTypeError extends OAuthError { - static errorCode = 'unsupported_response_type'; + static override errorCode = 'unsupported_response_type'; } /** @@ -121,7 +121,7 @@ export class UnsupportedResponseTypeError extends OAuthError { * the requested token type. */ export class UnsupportedTokenTypeError extends OAuthError { - static errorCode = 'unsupported_token_type'; + static override errorCode = 'unsupported_token_type'; } /** @@ -129,7 +129,7 @@ export class UnsupportedTokenTypeError extends OAuthError { * or invalid for other reasons. */ export class InvalidTokenError extends OAuthError { - static errorCode = 'invalid_token'; + static override errorCode = 'invalid_token'; } /** @@ -137,7 +137,7 @@ export class InvalidTokenError extends OAuthError { * (Custom, non-standard error) */ export class MethodNotAllowedError extends OAuthError { - static errorCode = 'method_not_allowed'; + static override errorCode = 'method_not_allowed'; } /** @@ -145,7 +145,7 @@ export class MethodNotAllowedError extends OAuthError { * (Custom, non-standard error based on RFC 6585) */ export class TooManyRequestsError extends OAuthError { - static errorCode = 'too_many_requests'; + static override errorCode = 'too_many_requests'; } /** @@ -153,14 +153,14 @@ export class TooManyRequestsError extends OAuthError { * (Custom error for dynamic client registration - RFC 7591) */ export class InvalidClientMetadataError extends OAuthError { - static errorCode = 'invalid_client_metadata'; + static override errorCode = 'invalid_client_metadata'; } /** * Insufficient scope error - The request requires higher privileges than provided by the access token. */ export class InsufficientScopeError extends OAuthError { - static errorCode = 'insufficient_scope'; + static override errorCode = 'insufficient_scope'; } /** @@ -168,7 +168,7 @@ export class InsufficientScopeError extends OAuthError { * (Custom error for resource indicators - RFC 8707) */ export class InvalidTargetError extends OAuthError { - static errorCode = 'invalid_target'; + static override errorCode = 'invalid_target'; } /** @@ -183,7 +183,7 @@ export class CustomOAuthError extends OAuthError { super(message, errorUri); } - get errorCode(): string { + override get errorCode(): string { return this.customErrorCode; } } diff --git a/packages/core/src/experimental/index.ts b/packages/core/src/experimental/index.ts new file mode 100644 index 000000000..1a641c25d --- /dev/null +++ b/packages/core/src/experimental/index.ts @@ -0,0 +1,3 @@ +export * from './tasks/helpers.js'; +export * from './tasks/interfaces.js'; +export * from './tasks/stores/in-memory.js'; diff --git a/src/experimental/tasks/helpers.ts b/packages/core/src/experimental/tasks/helpers.ts similarity index 100% rename from src/experimental/tasks/helpers.ts rename to packages/core/src/experimental/tasks/helpers.ts diff --git a/src/experimental/tasks/interfaces.ts b/packages/core/src/experimental/tasks/interfaces.ts similarity index 83% rename from src/experimental/tasks/interfaces.ts rename to packages/core/src/experimental/tasks/interfaces.ts index 88e53028b..c1901d70a 100644 --- a/src/experimental/tasks/interfaces.ts +++ b/packages/core/src/experimental/tasks/interfaces.ts @@ -3,24 +3,20 @@ * WARNING: These APIs are experimental and may change without notice. */ -import { - Task, - RequestId, - Result, - JSONRPCRequest, +import type { RequestHandlerExtra, RequestTaskStore } from '../../shared/protocol.js'; +import type { + JSONRPCErrorResponse, JSONRPCNotification, + JSONRPCRequest, JSONRPCResultResponse, - JSONRPCErrorResponse, - ServerRequest, + Request, + RequestId, + Result, ServerNotification, - CallToolResult, - GetTaskResult, - ToolExecution, - Request -} from '../../types.js'; -import { CreateTaskResult } from './types.js'; -import type { RequestHandlerExtra, RequestTaskStore } from '../../shared/protocol.js'; -import type { ZodRawShapeCompat, AnySchema, ShapeOutput } from '../../server/zod-compat.js'; + ServerRequest, + Task, + ToolExecution +} from '../../types/types.js'; // ============================================================================ // Task Handler Types (for registerToolTask) @@ -43,48 +39,6 @@ export interface TaskRequestHandlerExtra extends RequestHandlerExtra, - Args extends undefined | ZodRawShapeCompat | AnySchema = undefined -> = Args extends ZodRawShapeCompat - ? (args: ShapeOutput, extra: ExtraT) => SendResultT | Promise - : Args extends AnySchema - ? (args: unknown, extra: ExtraT) => SendResultT | Promise - : (extra: ExtraT) => SendResultT | Promise; - -/** - * Handler for creating a task. - * @experimental - */ -export type CreateTaskRequestHandler< - SendResultT extends Result, - Args extends undefined | ZodRawShapeCompat | AnySchema = undefined -> = BaseToolCallback; - -/** - * Handler for task operations (get, getResult). - * @experimental - */ -export type TaskRequestHandler< - SendResultT extends Result, - Args extends undefined | ZodRawShapeCompat | AnySchema = undefined -> = BaseToolCallback; - -/** - * Interface for task-based tool handlers. - * @experimental - */ -export interface ToolTaskHandler { - createTask: CreateTaskRequestHandler; - getTask: TaskRequestHandler; - getTaskResult: TaskRequestHandler; -} - /** * Task-specific execution configuration. * taskSupport cannot be 'forbidden' for task-based tools. diff --git a/src/experimental/tasks/stores/in-memory.ts b/packages/core/src/experimental/tasks/stores/in-memory.ts similarity index 97% rename from src/experimental/tasks/stores/in-memory.ts rename to packages/core/src/experimental/tasks/stores/in-memory.ts index aff3ad910..42ddf5bf4 100644 --- a/src/experimental/tasks/stores/in-memory.ts +++ b/packages/core/src/experimental/tasks/stores/in-memory.ts @@ -5,10 +5,12 @@ * @experimental */ -import { Task, RequestId, Result, Request } from '../../../types.js'; -import { TaskStore, isTerminal, TaskMessageQueue, QueuedMessage, CreateTaskOptions } from '../interfaces.js'; import { randomBytes } from 'node:crypto'; +import type { Request, RequestId, Result, Task } from '../../../types/types.js'; +import type { CreateTaskOptions, QueuedMessage, TaskMessageQueue, TaskStore } from '../interfaces.js'; +import { isTerminal } from '../interfaces.js'; + interface StoredTask { task: Task; request: Request; diff --git a/packages/core/src/exports/types/index.ts b/packages/core/src/exports/types/index.ts new file mode 100644 index 000000000..47806ee8b --- /dev/null +++ b/packages/core/src/exports/types/index.ts @@ -0,0 +1 @@ +export type * from '../../types/types.js'; diff --git a/src/validation/index.ts b/packages/core/src/index.ts similarity index 54% rename from src/validation/index.ts rename to packages/core/src/index.ts index a6df86d6a..f4eaeabfc 100644 --- a/src/validation/index.ts +++ b/packages/core/src/index.ts @@ -1,3 +1,22 @@ +export * from './auth/errors.js'; +export * from './shared/auth.js'; +export * from './shared/auth-utils.js'; +export * from './shared/metadataUtils.js'; +export * from './shared/protocol.js'; +export * from './shared/responseMessage.js'; +export * from './shared/stdio.js'; +export * from './shared/toolNameValidation.js'; +export * from './shared/transport.js'; +export * from './shared/uriTemplate.js'; +export * from './types/types.js'; +export * from './util/inMemory.js'; +export * from './util/zod-compat.js'; +export * from './util/zod-json-schema-compat.js'; + +// experimental exports +export * from './experimental/index.js'; +export * from './validation/ajv-provider.js'; +export * from './validation/cfworker-provider.js'; /** * JSON Schema validation * @@ -27,4 +46,4 @@ */ // Core types only - implementations are exported via separate entry points -export type { JsonSchemaType, JsonSchemaValidator, JsonSchemaValidatorResult, jsonSchemaValidator } from './types.js'; +export type { JsonSchemaType, JsonSchemaValidator, jsonSchemaValidator, JsonSchemaValidatorResult } from './validation/types.js'; diff --git a/src/shared/auth-utils.ts b/packages/core/src/shared/auth-utils.ts similarity index 100% rename from src/shared/auth-utils.ts rename to packages/core/src/shared/auth-utils.ts diff --git a/src/shared/auth.ts b/packages/core/src/shared/auth.ts similarity index 100% rename from src/shared/auth.ts rename to packages/core/src/shared/auth.ts diff --git a/src/shared/metadataUtils.ts b/packages/core/src/shared/metadataUtils.ts similarity index 94% rename from src/shared/metadataUtils.ts rename to packages/core/src/shared/metadataUtils.ts index 18f84a4c9..6cede430b 100644 --- a/src/shared/metadataUtils.ts +++ b/packages/core/src/shared/metadataUtils.ts @@ -1,4 +1,4 @@ -import { BaseMetadata } from '../types.js'; +import type { BaseMetadata } from '../types/types.js'; /** * Utilities for working with BaseMetadata objects. diff --git a/src/shared/protocol.ts b/packages/core/src/shared/protocol.ts similarity index 98% rename from src/shared/protocol.ts rename to packages/core/src/shared/protocol.ts index aa242a647..9c65015d1 100644 --- a/src/shared/protocol.ts +++ b/packages/core/src/shared/protocol.ts @@ -1,55 +1,59 @@ -import { AnySchema, AnyObjectSchema, SchemaOutput, safeParse } from '../server/zod-compat.js'; +import type { CreateTaskOptions, QueuedMessage, TaskMessageQueue, TaskStore } from '../experimental/tasks/interfaces.js'; +import { isTerminal } from '../experimental/tasks/interfaces.js'; +import type { + AuthInfo, + CancelledNotification, + ClientCapabilities, + GetTaskPayloadRequest, + GetTaskRequest, + GetTaskResult, + JSONRPCErrorResponse, + JSONRPCNotification, + JSONRPCRequest, + JSONRPCResponse, + JSONRPCResultResponse, + MessageExtraInfo, + Notification, + Progress, + ProgressNotification, + RelatedTaskMetadata, + Request, + RequestId, + RequestInfo, + RequestMeta, + Result, + ServerCapabilities, + Task, + TaskCreationParams, + TaskStatusNotification +} from '../types/types.js'; import { CancelledNotificationSchema, - ClientCapabilities, + CancelTaskRequestSchema, + CancelTaskResultSchema, CreateTaskResultSchema, ErrorCode, - GetTaskRequest, + GetTaskPayloadRequestSchema, GetTaskRequestSchema, GetTaskResultSchema, - GetTaskPayloadRequest, - GetTaskPayloadRequestSchema, - ListTasksRequestSchema, - ListTasksResultSchema, - CancelTaskRequestSchema, - CancelTaskResultSchema, isJSONRPCErrorResponse, + isJSONRPCNotification, isJSONRPCRequest, isJSONRPCResultResponse, - isJSONRPCNotification, - JSONRPCErrorResponse, - JSONRPCNotification, - JSONRPCRequest, - JSONRPCResponse, + isTaskAugmentedRequestParams, + ListTasksRequestSchema, + ListTasksResultSchema, McpError, PingRequestSchema, - Progress, - ProgressNotification, ProgressNotificationSchema, RELATED_TASK_META_KEY, - RequestId, - Result, - ServerCapabilities, - RequestMeta, - MessageExtraInfo, - RequestInfo, - GetTaskResult, - TaskCreationParams, - RelatedTaskMetadata, - CancelledNotification, - Task, - TaskStatusNotification, - TaskStatusNotificationSchema, - Request, - Notification, - JSONRPCResultResponse, - isTaskAugmentedRequestParams -} from '../types.js'; -import { Transport, TransportSendOptions } from './transport.js'; -import { AuthInfo } from '../server/auth/types.js'; -import { isTerminal, TaskStore, TaskMessageQueue, QueuedMessage, CreateTaskOptions } from '../experimental/tasks/interfaces.js'; -import { getMethodLiteral, parseWithCompat } from '../server/zod-json-schema-compat.js'; -import { ResponseMessage } from './responseMessage.js'; + TaskStatusNotificationSchema +} from '../types/types.js'; +import type { AnyObjectSchema, AnySchema, SchemaOutput } from '../util/zod-compat.js'; +import { safeParse } from '../util/zod-compat.js'; +import { getMethodLiteral, parseWithCompat } from '../util/zod-json-schema-compat.js'; +import type { ResponseMessage } from './responseMessage.js'; +import type { Transport, TransportSendOptions } from './transport.js'; /** * Callback for progress notifications. diff --git a/src/shared/responseMessage.ts b/packages/core/src/shared/responseMessage.ts similarity index 96% rename from src/shared/responseMessage.ts rename to packages/core/src/shared/responseMessage.ts index 6fefcf1f6..8a0dcc2c2 100644 --- a/src/shared/responseMessage.ts +++ b/packages/core/src/shared/responseMessage.ts @@ -1,4 +1,4 @@ -import { Result, Task, McpError } from '../types.js'; +import type { McpError, Result, Task } from '../types/types.js'; /** * Base message type diff --git a/src/shared/stdio.ts b/packages/core/src/shared/stdio.ts similarity index 89% rename from src/shared/stdio.ts rename to packages/core/src/shared/stdio.ts index fe14612bd..49c658b96 100644 --- a/src/shared/stdio.ts +++ b/packages/core/src/shared/stdio.ts @@ -1,4 +1,5 @@ -import { JSONRPCMessage, JSONRPCMessageSchema } from '../types.js'; +import type { JSONRPCMessage } from '../types/types.js'; +import { JSONRPCMessageSchema } from '../types/types.js'; /** * Buffers a continuous stdio stream into discrete JSON-RPC messages. diff --git a/src/shared/toolNameValidation.ts b/packages/core/src/shared/toolNameValidation.ts similarity index 100% rename from src/shared/toolNameValidation.ts rename to packages/core/src/shared/toolNameValidation.ts diff --git a/src/shared/transport.ts b/packages/core/src/shared/transport.ts similarity index 95% rename from src/shared/transport.ts rename to packages/core/src/shared/transport.ts index f9b21bed3..87608f124 100644 --- a/src/shared/transport.ts +++ b/packages/core/src/shared/transport.ts @@ -1,4 +1,4 @@ -import { JSONRPCMessage, MessageExtraInfo, RequestId } from '../types.js'; +import type { JSONRPCMessage, MessageExtraInfo, RequestId } from '../types/types.js'; export type FetchLike = (url: string | URL, init?: RequestInit) => Promise; @@ -6,7 +6,7 @@ export type FetchLike = (url: string | URL, init?: RequestInit) => Promise for manipulation. * Handles Headers objects, arrays of tuples, and plain objects. */ -export function normalizeHeaders(headers: HeadersInit | undefined): Record { +export function normalizeHeaders(headers: RequestInit['headers'] | undefined): Record { if (!headers) return {}; if (headers instanceof Headers) { diff --git a/src/shared/uriTemplate.ts b/packages/core/src/shared/uriTemplate.ts similarity index 98% rename from src/shared/uriTemplate.ts rename to packages/core/src/shared/uriTemplate.ts index 1dd57f56f..631b65cb0 100644 --- a/src/shared/uriTemplate.ts +++ b/packages/core/src/shared/uriTemplate.ts @@ -65,7 +65,7 @@ export class UriTemplate { const operator = this.getOperator(expr); const exploded = expr.includes('*'); const names = this.getNames(expr); - const name = names[0]; + const name = names[0]!; // Validate variable name length for (const name of names) { @@ -210,7 +210,7 @@ export class UriTemplate { if (part.operator === '?' || part.operator === '&') { for (let i = 0; i < part.names.length; i++) { - const name = part.names[i]; + const name = part.names[i]!; const prefix = i === 0 ? '\\' + part.operator : '&'; patterns.push({ pattern: prefix + this.escapeRegExp(name) + '=([^&]+)', @@ -271,8 +271,8 @@ export class UriTemplate { const result: Variables = {}; for (let i = 0; i < names.length; i++) { - const { name, exploded } = names[i]; - const value = match[i + 1]; + const { name, exploded } = names[i]!; + const value = match[i + 1]!; const cleanName = name.replace('*', ''); if (exploded && value.includes(',')) { diff --git a/packages/core/src/types/spec.types.ts b/packages/core/src/types/spec.types.ts new file mode 100644 index 000000000..aa298e63c --- /dev/null +++ b/packages/core/src/types/spec.types.ts @@ -0,0 +1,2552 @@ +/** + * This file is automatically generated from the Model Context Protocol specification. + * + * Source: https://github.com/modelcontextprotocol/modelcontextprotocol + * Pulled from: https://raw.githubusercontent.com/modelcontextprotocol/modelcontextprotocol/main/schema/draft/schema.ts + * Last updated from commit: 35fa160caf287a9c48696e3ae452c0645c713669 + * + * DO NOT EDIT THIS FILE MANUALLY. Changes will be overwritten by automated updates. + * To update this file, run: npm run fetch:spec-types + */ /* JSON-RPC types */ + +/** + * Refers to any valid JSON-RPC object that can be decoded off the wire, or encoded to be sent. + * + * @category JSON-RPC + */ +export type JSONRPCMessage = JSONRPCRequest | JSONRPCNotification | JSONRPCResponse; + +/** @internal */ +export const LATEST_PROTOCOL_VERSION = 'DRAFT-2026-v1'; +/** @internal */ +export const JSONRPC_VERSION = '2.0'; + +/** + * A progress token, used to associate progress notifications with the original request. + * + * @category Common Types + */ +export type ProgressToken = string | number; + +/** + * An opaque token used to represent a cursor for pagination. + * + * @category Common Types + */ +export type Cursor = string; + +/** + * Common params for any task-augmented request. + * + * @internal + */ +export interface TaskAugmentedRequestParams extends RequestParams { + /** + * If specified, the caller is requesting task-augmented execution for this request. + * The request will return a CreateTaskResult immediately, and the actual result can be + * retrieved later via tasks/result. + * + * Task augmentation is subject to capability negotiation - receivers MUST declare support + * for task augmentation of specific request types in their capabilities. + */ + task?: TaskMetadata; +} +/** + * Common params for any request. + * + * @internal + */ +export interface RequestParams { + /** + * See [General fields: `_meta`](/specification/draft/basic/index#meta) for notes on `_meta` usage. + */ + _meta?: { + /** + * If specified, the caller is requesting out-of-band progress notifications for this request (as represented by notifications/progress). The value of this parameter is an opaque token that will be attached to any subsequent notifications. The receiver is not obligated to provide these notifications. + */ + progressToken?: ProgressToken; + [key: string]: unknown; + }; +} + +/** @internal */ +export interface Request { + method: string; + // Allow unofficial extensions of `Request.params` without impacting `RequestParams`. + // eslint-disable-next-line @typescript-eslint/no-explicit-any + params?: { [key: string]: any }; +} + +/** @internal */ +export interface NotificationParams { + /** + * See [General fields: `_meta`](/specification/draft/basic/index#meta) for notes on `_meta` usage. + */ + _meta?: { [key: string]: unknown }; +} + +/** @internal */ +export interface Notification { + method: string; + // Allow unofficial extensions of `Notification.params` without impacting `NotificationParams`. + // eslint-disable-next-line @typescript-eslint/no-explicit-any + params?: { [key: string]: any }; +} + +/** + * @category Common Types + */ +export interface Result { + /** + * See [General fields: `_meta`](/specification/draft/basic/index#meta) for notes on `_meta` usage. + */ + _meta?: { [key: string]: unknown }; + [key: string]: unknown; +} + +/** + * @category Common Types + */ +export interface Error { + /** + * The error type that occurred. + */ + code: number; + /** + * A short description of the error. The message SHOULD be limited to a concise single sentence. + */ + message: string; + /** + * Additional information about the error. The value of this member is defined by the sender (e.g. detailed error information, nested errors etc.). + */ + data?: unknown; +} + +/** + * A uniquely identifying ID for a request in JSON-RPC. + * + * @category Common Types + */ +export type RequestId = string | number; + +/** + * A request that expects a response. + * + * @category JSON-RPC + */ +export interface JSONRPCRequest extends Request { + jsonrpc: typeof JSONRPC_VERSION; + id: RequestId; +} + +/** + * A notification which does not expect a response. + * + * @category JSON-RPC + */ +export interface JSONRPCNotification extends Notification { + jsonrpc: typeof JSONRPC_VERSION; +} + +/** + * A successful (non-error) response to a request. + * + * @category JSON-RPC + */ +export interface JSONRPCResultResponse { + jsonrpc: typeof JSONRPC_VERSION; + id: RequestId; + result: Result; +} + +/** + * A response to a request that indicates an error occurred. + * + * @category JSON-RPC + */ +export interface JSONRPCErrorResponse { + jsonrpc: typeof JSONRPC_VERSION; + id?: RequestId; + error: Error; +} + +/** + * A response to a request, containing either the result or error. + */ +export type JSONRPCResponse = JSONRPCResultResponse | JSONRPCErrorResponse; + +// Standard JSON-RPC error codes +export const PARSE_ERROR = -32700; +export const INVALID_REQUEST = -32600; +export const METHOD_NOT_FOUND = -32601; +export const INVALID_PARAMS = -32602; +export const INTERNAL_ERROR = -32603; + +// Implementation-specific JSON-RPC error codes [-32000, -32099] +/** @internal */ +export const URL_ELICITATION_REQUIRED = -32042; + +/** + * An error response that indicates that the server requires the client to provide additional information via an elicitation request. + * + * @internal + */ +export interface URLElicitationRequiredError extends Omit { + error: Error & { + code: typeof URL_ELICITATION_REQUIRED; + data: { + elicitations: ElicitRequestURLParams[]; + [key: string]: unknown; + }; + }; +} + +/* Empty result */ +/** + * A response that indicates success but carries no data. + * + * @category Common Types + */ +export type EmptyResult = Result; + +/* Cancellation */ +/** + * Parameters for a `notifications/cancelled` notification. + * + * @category `notifications/cancelled` + */ +export interface CancelledNotificationParams extends NotificationParams { + /** + * The ID of the request to cancel. + * + * This MUST correspond to the ID of a request previously issued in the same direction. + * This MUST be provided for cancelling non-task requests. + * This MUST NOT be used for cancelling tasks (use the `tasks/cancel` request instead). + */ + requestId?: RequestId; + + /** + * An optional string describing the reason for the cancellation. This MAY be logged or presented to the user. + */ + reason?: string; +} + +/** + * This notification can be sent by either side to indicate that it is cancelling a previously-issued request. + * + * The request SHOULD still be in-flight, but due to communication latency, it is always possible that this notification MAY arrive after the request has already finished. + * + * This notification indicates that the result will be unused, so any associated processing SHOULD cease. + * + * A client MUST NOT attempt to cancel its `initialize` request. + * + * For task cancellation, use the `tasks/cancel` request instead of this notification. + * + * @category `notifications/cancelled` + */ +export interface CancelledNotification extends JSONRPCNotification { + method: 'notifications/cancelled'; + params: CancelledNotificationParams; +} + +/* Initialization */ +/** + * Parameters for an `initialize` request. + * + * @category `initialize` + */ +export interface InitializeRequestParams extends RequestParams { + /** + * The latest version of the Model Context Protocol that the client supports. The client MAY decide to support older versions as well. + */ + protocolVersion: string; + capabilities: ClientCapabilities; + clientInfo: Implementation; +} + +/** + * This request is sent from the client to the server when it first connects, asking it to begin initialization. + * + * @category `initialize` + */ +export interface InitializeRequest extends JSONRPCRequest { + method: 'initialize'; + params: InitializeRequestParams; +} + +/** + * After receiving an initialize request from the client, the server sends this response. + * + * @category `initialize` + */ +export interface InitializeResult extends Result { + /** + * The version of the Model Context Protocol that the server wants to use. This may not match the version that the client requested. If the client cannot support this version, it MUST disconnect. + */ + protocolVersion: string; + capabilities: ServerCapabilities; + serverInfo: Implementation; + + /** + * Instructions describing how to use the server and its features. + * + * This can be used by clients to improve the LLM's understanding of available tools, resources, etc. It can be thought of like a "hint" to the model. For example, this information MAY be added to the system prompt. + */ + instructions?: string; +} + +/** + * This notification is sent from the client to the server after initialization has finished. + * + * @category `notifications/initialized` + */ +export interface InitializedNotification extends JSONRPCNotification { + method: 'notifications/initialized'; + params?: NotificationParams; +} + +/** + * Capabilities a client may support. Known capabilities are defined here, in this schema, but this is not a closed set: any client can define its own, additional capabilities. + * + * @category `initialize` + */ +export interface ClientCapabilities { + /** + * Experimental, non-standard capabilities that the client supports. + */ + experimental?: { [key: string]: object }; + /** + * Present if the client supports listing roots. + */ + roots?: { + /** + * Whether the client supports notifications for changes to the roots list. + */ + listChanged?: boolean; + }; + /** + * Present if the client supports sampling from an LLM. + */ + sampling?: { + /** + * Whether the client supports context inclusion via includeContext parameter. + * If not declared, servers SHOULD only use `includeContext: "none"` (or omit it). + */ + context?: object; + /** + * Whether the client supports tool use via tools and toolChoice parameters. + */ + tools?: object; + }; + /** + * Present if the client supports elicitation from the server. + */ + elicitation?: { form?: object; url?: object }; + + /** + * Present if the client supports task-augmented requests. + */ + tasks?: { + /** + * Whether this client supports tasks/list. + */ + list?: object; + /** + * Whether this client supports tasks/cancel. + */ + cancel?: object; + /** + * Specifies which request types can be augmented with tasks. + */ + requests?: { + /** + * Task support for sampling-related requests. + */ + sampling?: { + /** + * Whether the client supports task-augmented sampling/createMessage requests. + */ + createMessage?: object; + }; + /** + * Task support for elicitation-related requests. + */ + elicitation?: { + /** + * Whether the client supports task-augmented elicitation/create requests. + */ + create?: object; + }; + }; + }; +} + +/** + * Capabilities that a server may support. Known capabilities are defined here, in this schema, but this is not a closed set: any server can define its own, additional capabilities. + * + * @category `initialize` + */ +export interface ServerCapabilities { + /** + * Experimental, non-standard capabilities that the server supports. + */ + experimental?: { [key: string]: object }; + /** + * Present if the server supports sending log messages to the client. + */ + logging?: object; + /** + * Present if the server supports argument autocompletion suggestions. + */ + completions?: object; + /** + * Present if the server offers any prompt templates. + */ + prompts?: { + /** + * Whether this server supports notifications for changes to the prompt list. + */ + listChanged?: boolean; + }; + /** + * Present if the server offers any resources to read. + */ + resources?: { + /** + * Whether this server supports subscribing to resource updates. + */ + subscribe?: boolean; + /** + * Whether this server supports notifications for changes to the resource list. + */ + listChanged?: boolean; + }; + /** + * Present if the server offers any tools to call. + */ + tools?: { + /** + * Whether this server supports notifications for changes to the tool list. + */ + listChanged?: boolean; + }; + /** + * Present if the server supports task-augmented requests. + */ + tasks?: { + /** + * Whether this server supports tasks/list. + */ + list?: object; + /** + * Whether this server supports tasks/cancel. + */ + cancel?: object; + /** + * Specifies which request types can be augmented with tasks. + */ + requests?: { + /** + * Task support for tool-related requests. + */ + tools?: { + /** + * Whether the server supports task-augmented tools/call requests. + */ + call?: object; + }; + }; + }; +} + +/** + * An optionally-sized icon that can be displayed in a user interface. + * + * @category Common Types + */ +export interface Icon { + /** + * A standard URI pointing to an icon resource. May be an HTTP/HTTPS URL or a + * `data:` URI with Base64-encoded image data. + * + * Consumers SHOULD takes steps to ensure URLs serving icons are from the + * same domain as the client/server or a trusted domain. + * + * Consumers SHOULD take appropriate precautions when consuming SVGs as they can contain + * executable JavaScript. + * + * @format uri + */ + src: string; + + /** + * Optional MIME type override if the source MIME type is missing or generic. + * For example: `"image/png"`, `"image/jpeg"`, or `"image/svg+xml"`. + */ + mimeType?: string; + + /** + * Optional array of strings that specify sizes at which the icon can be used. + * Each string should be in WxH format (e.g., `"48x48"`, `"96x96"`) or `"any"` for scalable formats like SVG. + * + * If not provided, the client should assume that the icon can be used at any size. + */ + sizes?: string[]; + + /** + * Optional specifier for the theme this icon is designed for. `light` indicates + * the icon is designed to be used with a light background, and `dark` indicates + * the icon is designed to be used with a dark background. + * + * If not provided, the client should assume the icon can be used with any theme. + */ + theme?: 'light' | 'dark'; +} + +/** + * Base interface to add `icons` property. + * + * @internal + */ +export interface Icons { + /** + * Optional set of sized icons that the client can display in a user interface. + * + * Clients that support rendering icons MUST support at least the following MIME types: + * - `image/png` - PNG images (safe, universal compatibility) + * - `image/jpeg` (and `image/jpg`) - JPEG images (safe, universal compatibility) + * + * Clients that support rendering icons SHOULD also support: + * - `image/svg+xml` - SVG images (scalable but requires security precautions) + * - `image/webp` - WebP images (modern, efficient format) + */ + icons?: Icon[]; +} + +/** + * Base interface for metadata with name (identifier) and title (display name) properties. + * + * @internal + */ +export interface BaseMetadata { + /** + * Intended for programmatic or logical use, but used as a display name in past specs or fallback (if title isn't present). + */ + name: string; + + /** + * Intended for UI and end-user contexts — optimized to be human-readable and easily understood, + * even by those unfamiliar with domain-specific terminology. + * + * If not provided, the name should be used for display (except for Tool, + * where `annotations.title` should be given precedence over using `name`, + * if present). + */ + title?: string; +} + +/** + * Describes the MCP implementation. + * + * @category `initialize` + */ +export interface Implementation extends BaseMetadata, Icons { + version: string; + + /** + * An optional human-readable description of what this implementation does. + * + * This can be used by clients or servers to provide context about their purpose + * and capabilities. For example, a server might describe the types of resources + * or tools it provides, while a client might describe its intended use case. + */ + description?: string; + + /** + * An optional URL of the website for this implementation. + * + * @format uri + */ + websiteUrl?: string; +} + +/* Ping */ +/** + * A ping, issued by either the server or the client, to check that the other party is still alive. The receiver must promptly respond, or else may be disconnected. + * + * @category `ping` + */ +export interface PingRequest extends JSONRPCRequest { + method: 'ping'; + params?: RequestParams; +} + +/* Progress notifications */ + +/** + * Parameters for a `notifications/progress` notification. + * + * @category `notifications/progress` + */ +export interface ProgressNotificationParams extends NotificationParams { + /** + * The progress token which was given in the initial request, used to associate this notification with the request that is proceeding. + */ + progressToken: ProgressToken; + /** + * The progress thus far. This should increase every time progress is made, even if the total is unknown. + * + * @TJS-type number + */ + progress: number; + /** + * Total number of items to process (or total progress required), if known. + * + * @TJS-type number + */ + total?: number; + /** + * An optional message describing the current progress. + */ + message?: string; +} + +/** + * An out-of-band notification used to inform the receiver of a progress update for a long-running request. + * + * @category `notifications/progress` + */ +export interface ProgressNotification extends JSONRPCNotification { + method: 'notifications/progress'; + params: ProgressNotificationParams; +} + +/* Pagination */ +/** + * Common parameters for paginated requests. + * + * @internal + */ +export interface PaginatedRequestParams extends RequestParams { + /** + * An opaque token representing the current pagination position. + * If provided, the server should return results starting after this cursor. + */ + cursor?: Cursor; +} + +/** @internal */ +export interface PaginatedRequest extends JSONRPCRequest { + params?: PaginatedRequestParams; +} + +/** @internal */ +export interface PaginatedResult extends Result { + /** + * An opaque token representing the pagination position after the last returned result. + * If present, there may be more results available. + */ + nextCursor?: Cursor; +} + +/* Resources */ +/** + * Sent from the client to request a list of resources the server has. + * + * @category `resources/list` + */ +export interface ListResourcesRequest extends PaginatedRequest { + method: 'resources/list'; +} + +/** + * The server's response to a resources/list request from the client. + * + * @category `resources/list` + */ +export interface ListResourcesResult extends PaginatedResult { + resources: Resource[]; +} + +/** + * Sent from the client to request a list of resource templates the server has. + * + * @category `resources/templates/list` + */ +export interface ListResourceTemplatesRequest extends PaginatedRequest { + method: 'resources/templates/list'; +} + +/** + * The server's response to a resources/templates/list request from the client. + * + * @category `resources/templates/list` + */ +export interface ListResourceTemplatesResult extends PaginatedResult { + resourceTemplates: ResourceTemplate[]; +} + +/** + * Common parameters when working with resources. + * + * @internal + */ +export interface ResourceRequestParams extends RequestParams { + /** + * The URI of the resource. The URI can use any protocol; it is up to the server how to interpret it. + * + * @format uri + */ + uri: string; +} + +/** + * Parameters for a `resources/read` request. + * + * @category `resources/read` + */ +// eslint-disable-next-line @typescript-eslint/no-empty-object-type +export interface ReadResourceRequestParams extends ResourceRequestParams {} + +/** + * Sent from the client to the server, to read a specific resource URI. + * + * @category `resources/read` + */ +export interface ReadResourceRequest extends JSONRPCRequest { + method: 'resources/read'; + params: ReadResourceRequestParams; +} + +/** + * The server's response to a resources/read request from the client. + * + * @category `resources/read` + */ +export interface ReadResourceResult extends Result { + contents: (TextResourceContents | BlobResourceContents)[]; +} + +/** + * An optional notification from the server to the client, informing it that the list of resources it can read from has changed. This may be issued by servers without any previous subscription from the client. + * + * @category `notifications/resources/list_changed` + */ +export interface ResourceListChangedNotification extends JSONRPCNotification { + method: 'notifications/resources/list_changed'; + params?: NotificationParams; +} + +/** + * Parameters for a `resources/subscribe` request. + * + * @category `resources/subscribe` + */ +// eslint-disable-next-line @typescript-eslint/no-empty-object-type +export interface SubscribeRequestParams extends ResourceRequestParams {} + +/** + * Sent from the client to request resources/updated notifications from the server whenever a particular resource changes. + * + * @category `resources/subscribe` + */ +export interface SubscribeRequest extends JSONRPCRequest { + method: 'resources/subscribe'; + params: SubscribeRequestParams; +} + +/** + * Parameters for a `resources/unsubscribe` request. + * + * @category `resources/unsubscribe` + */ +// eslint-disable-next-line @typescript-eslint/no-empty-object-type +export interface UnsubscribeRequestParams extends ResourceRequestParams {} + +/** + * Sent from the client to request cancellation of resources/updated notifications from the server. This should follow a previous resources/subscribe request. + * + * @category `resources/unsubscribe` + */ +export interface UnsubscribeRequest extends JSONRPCRequest { + method: 'resources/unsubscribe'; + params: UnsubscribeRequestParams; +} + +/** + * Parameters for a `notifications/resources/updated` notification. + * + * @category `notifications/resources/updated` + */ +export interface ResourceUpdatedNotificationParams extends NotificationParams { + /** + * The URI of the resource that has been updated. This might be a sub-resource of the one that the client actually subscribed to. + * + * @format uri + */ + uri: string; +} + +/** + * A notification from the server to the client, informing it that a resource has changed and may need to be read again. This should only be sent if the client previously sent a resources/subscribe request. + * + * @category `notifications/resources/updated` + */ +export interface ResourceUpdatedNotification extends JSONRPCNotification { + method: 'notifications/resources/updated'; + params: ResourceUpdatedNotificationParams; +} + +/** + * A known resource that the server is capable of reading. + * + * @category `resources/list` + */ +export interface Resource extends BaseMetadata, Icons { + /** + * The URI of this resource. + * + * @format uri + */ + uri: string; + + /** + * A description of what this resource represents. + * + * This can be used by clients to improve the LLM's understanding of available resources. It can be thought of like a "hint" to the model. + */ + description?: string; + + /** + * The MIME type of this resource, if known. + */ + mimeType?: string; + + /** + * Optional annotations for the client. + */ + annotations?: Annotations; + + /** + * The size of the raw resource content, in bytes (i.e., before base64 encoding or any tokenization), if known. + * + * This can be used by Hosts to display file sizes and estimate context window usage. + */ + size?: number; + + /** + * See [General fields: `_meta`](/specification/draft/basic/index#meta) for notes on `_meta` usage. + */ + _meta?: { [key: string]: unknown }; +} + +/** + * A template description for resources available on the server. + * + * @category `resources/templates/list` + */ +export interface ResourceTemplate extends BaseMetadata, Icons { + /** + * A URI template (according to RFC 6570) that can be used to construct resource URIs. + * + * @format uri-template + */ + uriTemplate: string; + + /** + * A description of what this template is for. + * + * This can be used by clients to improve the LLM's understanding of available resources. It can be thought of like a "hint" to the model. + */ + description?: string; + + /** + * The MIME type for all resources that match this template. This should only be included if all resources matching this template have the same type. + */ + mimeType?: string; + + /** + * Optional annotations for the client. + */ + annotations?: Annotations; + + /** + * See [General fields: `_meta`](/specification/draft/basic/index#meta) for notes on `_meta` usage. + */ + _meta?: { [key: string]: unknown }; +} + +/** + * The contents of a specific resource or sub-resource. + * + * @internal + */ +export interface ResourceContents { + /** + * The URI of this resource. + * + * @format uri + */ + uri: string; + /** + * The MIME type of this resource, if known. + */ + mimeType?: string; + + /** + * See [General fields: `_meta`](/specification/draft/basic/index#meta) for notes on `_meta` usage. + */ + _meta?: { [key: string]: unknown }; +} + +/** + * @category Content + */ +export interface TextResourceContents extends ResourceContents { + /** + * The text of the item. This must only be set if the item can actually be represented as text (not binary data). + */ + text: string; +} + +/** + * @category Content + */ +export interface BlobResourceContents extends ResourceContents { + /** + * A base64-encoded string representing the binary data of the item. + * + * @format byte + */ + blob: string; +} + +/* Prompts */ +/** + * Sent from the client to request a list of prompts and prompt templates the server has. + * + * @category `prompts/list` + */ +export interface ListPromptsRequest extends PaginatedRequest { + method: 'prompts/list'; +} + +/** + * The server's response to a prompts/list request from the client. + * + * @category `prompts/list` + */ +export interface ListPromptsResult extends PaginatedResult { + prompts: Prompt[]; +} + +/** + * Parameters for a `prompts/get` request. + * + * @category `prompts/get` + */ +export interface GetPromptRequestParams extends RequestParams { + /** + * The name of the prompt or prompt template. + */ + name: string; + /** + * Arguments to use for templating the prompt. + */ + arguments?: { [key: string]: string }; +} + +/** + * Used by the client to get a prompt provided by the server. + * + * @category `prompts/get` + */ +export interface GetPromptRequest extends JSONRPCRequest { + method: 'prompts/get'; + params: GetPromptRequestParams; +} + +/** + * The server's response to a prompts/get request from the client. + * + * @category `prompts/get` + */ +export interface GetPromptResult extends Result { + /** + * An optional description for the prompt. + */ + description?: string; + messages: PromptMessage[]; +} + +/** + * A prompt or prompt template that the server offers. + * + * @category `prompts/list` + */ +export interface Prompt extends BaseMetadata, Icons { + /** + * An optional description of what this prompt provides + */ + description?: string; + + /** + * A list of arguments to use for templating the prompt. + */ + arguments?: PromptArgument[]; + + /** + * See [General fields: `_meta`](/specification/draft/basic/index#meta) for notes on `_meta` usage. + */ + _meta?: { [key: string]: unknown }; +} + +/** + * Describes an argument that a prompt can accept. + * + * @category `prompts/list` + */ +export interface PromptArgument extends BaseMetadata { + /** + * A human-readable description of the argument. + */ + description?: string; + /** + * Whether this argument must be provided. + */ + required?: boolean; +} + +/** + * The sender or recipient of messages and data in a conversation. + * + * @category Common Types + */ +export type Role = 'user' | 'assistant'; + +/** + * Describes a message returned as part of a prompt. + * + * This is similar to `SamplingMessage`, but also supports the embedding of + * resources from the MCP server. + * + * @category `prompts/get` + */ +export interface PromptMessage { + role: Role; + content: ContentBlock; +} + +/** + * A resource that the server is capable of reading, included in a prompt or tool call result. + * + * Note: resource links returned by tools are not guaranteed to appear in the results of `resources/list` requests. + * + * @category Content + */ +export interface ResourceLink extends Resource { + type: 'resource_link'; +} + +/** + * The contents of a resource, embedded into a prompt or tool call result. + * + * It is up to the client how best to render embedded resources for the benefit + * of the LLM and/or the user. + * + * @category Content + */ +export interface EmbeddedResource { + type: 'resource'; + resource: TextResourceContents | BlobResourceContents; + + /** + * Optional annotations for the client. + */ + annotations?: Annotations; + + /** + * See [General fields: `_meta`](/specification/draft/basic/index#meta) for notes on `_meta` usage. + */ + _meta?: { [key: string]: unknown }; +} +/** + * An optional notification from the server to the client, informing it that the list of prompts it offers has changed. This may be issued by servers without any previous subscription from the client. + * + * @category `notifications/prompts/list_changed` + */ +export interface PromptListChangedNotification extends JSONRPCNotification { + method: 'notifications/prompts/list_changed'; + params?: NotificationParams; +} + +/* Tools */ +/** + * Sent from the client to request a list of tools the server has. + * + * @category `tools/list` + */ +export interface ListToolsRequest extends PaginatedRequest { + method: 'tools/list'; +} + +/** + * The server's response to a tools/list request from the client. + * + * @category `tools/list` + */ +export interface ListToolsResult extends PaginatedResult { + tools: Tool[]; +} + +/** + * The server's response to a tool call. + * + * @category `tools/call` + */ +export interface CallToolResult extends Result { + /** + * A list of content objects that represent the unstructured result of the tool call. + */ + content: ContentBlock[]; + + /** + * An optional JSON object that represents the structured result of the tool call. + */ + structuredContent?: { [key: string]: unknown }; + + /** + * Whether the tool call ended in an error. + * + * If not set, this is assumed to be false (the call was successful). + * + * Any errors that originate from the tool SHOULD be reported inside the result + * object, with `isError` set to true, _not_ as an MCP protocol-level error + * response. Otherwise, the LLM would not be able to see that an error occurred + * and self-correct. + * + * However, any errors in _finding_ the tool, an error indicating that the + * server does not support tool calls, or any other exceptional conditions, + * should be reported as an MCP error response. + */ + isError?: boolean; +} + +/** + * Parameters for a `tools/call` request. + * + * @category `tools/call` + */ +export interface CallToolRequestParams extends TaskAugmentedRequestParams { + /** + * The name of the tool. + */ + name: string; + /** + * Arguments to use for the tool call. + */ + arguments?: { [key: string]: unknown }; +} + +/** + * Used by the client to invoke a tool provided by the server. + * + * @category `tools/call` + */ +export interface CallToolRequest extends JSONRPCRequest { + method: 'tools/call'; + params: CallToolRequestParams; +} + +/** + * An optional notification from the server to the client, informing it that the list of tools it offers has changed. This may be issued by servers without any previous subscription from the client. + * + * @category `notifications/tools/list_changed` + */ +export interface ToolListChangedNotification extends JSONRPCNotification { + method: 'notifications/tools/list_changed'; + params?: NotificationParams; +} + +/** + * Additional properties describing a Tool to clients. + * + * NOTE: all properties in ToolAnnotations are **hints**. + * They are not guaranteed to provide a faithful description of + * tool behavior (including descriptive properties like `title`). + * + * Clients should never make tool use decisions based on ToolAnnotations + * received from untrusted servers. + * + * @category `tools/list` + */ +export interface ToolAnnotations { + /** + * A human-readable title for the tool. + */ + title?: string; + + /** + * If true, the tool does not modify its environment. + * + * Default: false + */ + readOnlyHint?: boolean; + + /** + * If true, the tool may perform destructive updates to its environment. + * If false, the tool performs only additive updates. + * + * (This property is meaningful only when `readOnlyHint == false`) + * + * Default: true + */ + destructiveHint?: boolean; + + /** + * If true, calling the tool repeatedly with the same arguments + * will have no additional effect on its environment. + * + * (This property is meaningful only when `readOnlyHint == false`) + * + * Default: false + */ + idempotentHint?: boolean; + + /** + * If true, this tool may interact with an "open world" of external + * entities. If false, the tool's domain of interaction is closed. + * For example, the world of a web search tool is open, whereas that + * of a memory tool is not. + * + * Default: true + */ + openWorldHint?: boolean; +} + +/** + * Execution-related properties for a tool. + * + * @category `tools/list` + */ +export interface ToolExecution { + /** + * Indicates whether this tool supports task-augmented execution. + * This allows clients to handle long-running operations through polling + * the task system. + * + * - "forbidden": Tool does not support task-augmented execution (default when absent) + * - "optional": Tool may support task-augmented execution + * - "required": Tool requires task-augmented execution + * + * Default: "forbidden" + */ + taskSupport?: 'forbidden' | 'optional' | 'required'; +} + +/** + * Definition for a tool the client can call. + * + * @category `tools/list` + */ +export interface Tool extends BaseMetadata, Icons { + /** + * A human-readable description of the tool. + * + * This can be used by clients to improve the LLM's understanding of available tools. It can be thought of like a "hint" to the model. + */ + description?: string; + + /** + * A JSON Schema object defining the expected parameters for the tool. + */ + inputSchema: { + $schema?: string; + type: 'object'; + properties?: { [key: string]: object }; + required?: string[]; + }; + + /** + * Execution-related properties for this tool. + */ + execution?: ToolExecution; + + /** + * An optional JSON Schema object defining the structure of the tool's output returned in + * the structuredContent field of a CallToolResult. + * + * Defaults to JSON Schema 2020-12 when no explicit $schema is provided. + * Currently restricted to type: "object" at the root level. + */ + outputSchema?: { + $schema?: string; + type: 'object'; + properties?: { [key: string]: object }; + required?: string[]; + }; + + /** + * Optional additional tool information. + * + * Display name precedence order is: title, annotations.title, then name. + */ + annotations?: ToolAnnotations; + + /** + * See [General fields: `_meta`](/specification/draft/basic/index#meta) for notes on `_meta` usage. + */ + _meta?: { [key: string]: unknown }; +} + +/* Tasks */ + +/** + * The status of a task. + * + * @category `tasks` + */ +export type TaskStatus = + | 'working' // The request is currently being processed + | 'input_required' // The task is waiting for input (e.g., elicitation or sampling) + | 'completed' // The request completed successfully and results are available + | 'failed' // The associated request did not complete successfully. For tool calls specifically, this includes cases where the tool call result has `isError` set to true. + | 'cancelled'; // The request was cancelled before completion + +/** + * Metadata for augmenting a request with task execution. + * Include this in the `task` field of the request parameters. + * + * @category `tasks` + */ +export interface TaskMetadata { + /** + * Requested duration in milliseconds to retain task from creation. + */ + ttl?: number; +} + +/** + * Metadata for associating messages with a task. + * Include this in the `_meta` field under the key `io.modelcontextprotocol/related-task`. + * + * @category `tasks` + */ +export interface RelatedTaskMetadata { + /** + * The task identifier this message is associated with. + */ + taskId: string; +} + +/** + * Data associated with a task. + * + * @category `tasks` + */ +export interface Task { + /** + * The task identifier. + */ + taskId: string; + + /** + * Current task state. + */ + status: TaskStatus; + + /** + * Optional human-readable message describing the current task state. + * This can provide context for any status, including: + * - Reasons for "cancelled" status + * - Summaries for "completed" status + * - Diagnostic information for "failed" status (e.g., error details, what went wrong) + */ + statusMessage?: string; + + /** + * ISO 8601 timestamp when the task was created. + */ + createdAt: string; + + /** + * ISO 8601 timestamp when the task was last updated. + */ + lastUpdatedAt: string; + + /** + * Actual retention duration from creation in milliseconds, null for unlimited. + */ + ttl: number | null; + + /** + * Suggested polling interval in milliseconds. + */ + pollInterval?: number; +} + +/** + * A response to a task-augmented request. + * + * @category `tasks` + */ +export interface CreateTaskResult extends Result { + task: Task; +} + +/** + * A request to retrieve the state of a task. + * + * @category `tasks/get` + */ +export interface GetTaskRequest extends JSONRPCRequest { + method: 'tasks/get'; + params: { + /** + * The task identifier to query. + */ + taskId: string; + }; +} + +/** + * The response to a tasks/get request. + * + * @category `tasks/get` + */ +export type GetTaskResult = Result & Task; + +/** + * A request to retrieve the result of a completed task. + * + * @category `tasks/result` + */ +export interface GetTaskPayloadRequest extends JSONRPCRequest { + method: 'tasks/result'; + params: { + /** + * The task identifier to retrieve results for. + */ + taskId: string; + }; +} + +/** + * The response to a tasks/result request. + * The structure matches the result type of the original request. + * For example, a tools/call task would return the CallToolResult structure. + * + * @category `tasks/result` + */ +export interface GetTaskPayloadResult extends Result { + [key: string]: unknown; +} + +/** + * A request to cancel a task. + * + * @category `tasks/cancel` + */ +export interface CancelTaskRequest extends JSONRPCRequest { + method: 'tasks/cancel'; + params: { + /** + * The task identifier to cancel. + */ + taskId: string; + }; +} + +/** + * The response to a tasks/cancel request. + * + * @category `tasks/cancel` + */ +export type CancelTaskResult = Result & Task; + +/** + * A request to retrieve a list of tasks. + * + * @category `tasks/list` + */ +export interface ListTasksRequest extends PaginatedRequest { + method: 'tasks/list'; +} + +/** + * The response to a tasks/list request. + * + * @category `tasks/list` + */ +export interface ListTasksResult extends PaginatedResult { + tasks: Task[]; +} + +/** + * Parameters for a `notifications/tasks/status` notification. + * + * @category `notifications/tasks/status` + */ +export type TaskStatusNotificationParams = NotificationParams & Task; + +/** + * An optional notification from the receiver to the requestor, informing them that a task's status has changed. Receivers are not required to send these notifications. + * + * @category `notifications/tasks/status` + */ +export interface TaskStatusNotification extends JSONRPCNotification { + method: 'notifications/tasks/status'; + params: TaskStatusNotificationParams; +} + +/* Logging */ + +/** + * Parameters for a `logging/setLevel` request. + * + * @category `logging/setLevel` + */ +export interface SetLevelRequestParams extends RequestParams { + /** + * The level of logging that the client wants to receive from the server. The server should send all logs at this level and higher (i.e., more severe) to the client as notifications/message. + */ + level: LoggingLevel; +} + +/** + * A request from the client to the server, to enable or adjust logging. + * + * @category `logging/setLevel` + */ +export interface SetLevelRequest extends JSONRPCRequest { + method: 'logging/setLevel'; + params: SetLevelRequestParams; +} + +/** + * Parameters for a `notifications/message` notification. + * + * @category `notifications/message` + */ +export interface LoggingMessageNotificationParams extends NotificationParams { + /** + * The severity of this log message. + */ + level: LoggingLevel; + /** + * An optional name of the logger issuing this message. + */ + logger?: string; + /** + * The data to be logged, such as a string message or an object. Any JSON serializable type is allowed here. + */ + data: unknown; +} + +/** + * JSONRPCNotification of a log message passed from server to client. If no logging/setLevel request has been sent from the client, the server MAY decide which messages to send automatically. + * + * @category `notifications/message` + */ +export interface LoggingMessageNotification extends JSONRPCNotification { + method: 'notifications/message'; + params: LoggingMessageNotificationParams; +} + +/** + * The severity of a log message. + * + * These map to syslog message severities, as specified in RFC-5424: + * https://datatracker.ietf.org/doc/html/rfc5424#section-6.2.1 + * + * @category Common Types + */ +export type LoggingLevel = 'debug' | 'info' | 'notice' | 'warning' | 'error' | 'critical' | 'alert' | 'emergency'; + +/* Sampling */ +/** + * Parameters for a `sampling/createMessage` request. + * + * @category `sampling/createMessage` + */ +export interface CreateMessageRequestParams extends TaskAugmentedRequestParams { + messages: SamplingMessage[]; + /** + * The server's preferences for which model to select. The client MAY ignore these preferences. + */ + modelPreferences?: ModelPreferences; + /** + * An optional system prompt the server wants to use for sampling. The client MAY modify or omit this prompt. + */ + systemPrompt?: string; + /** + * A request to include context from one or more MCP servers (including the caller), to be attached to the prompt. + * The client MAY ignore this request. + * + * Default is "none". Values "thisServer" and "allServers" are soft-deprecated. Servers SHOULD only use these values if the client + * declares ClientCapabilities.sampling.context. These values may be removed in future spec releases. + */ + includeContext?: 'none' | 'thisServer' | 'allServers'; + /** + * @TJS-type number + */ + temperature?: number; + /** + * The requested maximum number of tokens to sample (to prevent runaway completions). + * + * The client MAY choose to sample fewer tokens than the requested maximum. + */ + maxTokens: number; + stopSequences?: string[]; + /** + * Optional metadata to pass through to the LLM provider. The format of this metadata is provider-specific. + */ + metadata?: object; + /** + * Tools that the model may use during generation. + * The client MUST return an error if this field is provided but ClientCapabilities.sampling.tools is not declared. + */ + tools?: Tool[]; + /** + * Controls how the model uses tools. + * The client MUST return an error if this field is provided but ClientCapabilities.sampling.tools is not declared. + * Default is `{ mode: "auto" }`. + */ + toolChoice?: ToolChoice; +} + +/** + * Controls tool selection behavior for sampling requests. + * + * @category `sampling/createMessage` + */ +export interface ToolChoice { + /** + * Controls the tool use ability of the model: + * - "auto": Model decides whether to use tools (default) + * - "required": Model MUST use at least one tool before completing + * - "none": Model MUST NOT use any tools + */ + mode?: 'auto' | 'required' | 'none'; +} + +/** + * A request from the server to sample an LLM via the client. The client has full discretion over which model to select. The client should also inform the user before beginning sampling, to allow them to inspect the request (human in the loop) and decide whether to approve it. + * + * @category `sampling/createMessage` + */ +export interface CreateMessageRequest extends JSONRPCRequest { + method: 'sampling/createMessage'; + params: CreateMessageRequestParams; +} + +/** + * The client's response to a sampling/createMessage request from the server. + * The client should inform the user before returning the sampled message, to allow them + * to inspect the response (human in the loop) and decide whether to allow the server to see it. + * + * @category `sampling/createMessage` + */ +export interface CreateMessageResult extends Result, SamplingMessage { + /** + * The name of the model that generated the message. + */ + model: string; + + /** + * The reason why sampling stopped, if known. + * + * Standard values: + * - "endTurn": Natural end of the assistant's turn + * - "stopSequence": A stop sequence was encountered + * - "maxTokens": Maximum token limit was reached + * - "toolUse": The model wants to use one or more tools + * + * This field is an open string to allow for provider-specific stop reasons. + */ + stopReason?: 'endTurn' | 'stopSequence' | 'maxTokens' | 'toolUse' | string; +} + +/** + * Describes a message issued to or received from an LLM API. + * + * @category `sampling/createMessage` + */ +export interface SamplingMessage { + role: Role; + content: SamplingMessageContentBlock | SamplingMessageContentBlock[]; + /** + * See [General fields: `_meta`](/specification/draft/basic/index#meta) for notes on `_meta` usage. + */ + _meta?: { [key: string]: unknown }; +} +export type SamplingMessageContentBlock = TextContent | ImageContent | AudioContent | ToolUseContent | ToolResultContent; + +/** + * Optional annotations for the client. The client can use annotations to inform how objects are used or displayed + * + * @category Common Types + */ +export interface Annotations { + /** + * Describes who the intended audience of this object or data is. + * + * It can include multiple entries to indicate content useful for multiple audiences (e.g., `["user", "assistant"]`). + */ + audience?: Role[]; + + /** + * Describes how important this data is for operating the server. + * + * A value of 1 means "most important," and indicates that the data is + * effectively required, while 0 means "least important," and indicates that + * the data is entirely optional. + * + * @TJS-type number + * @minimum 0 + * @maximum 1 + */ + priority?: number; + + /** + * The moment the resource was last modified, as an ISO 8601 formatted string. + * + * Should be an ISO 8601 formatted string (e.g., "2025-01-12T15:00:58Z"). + * + * Examples: last activity timestamp in an open file, timestamp when the resource + * was attached, etc. + */ + lastModified?: string; +} + +/** + * @category Content + */ +export type ContentBlock = TextContent | ImageContent | AudioContent | ResourceLink | EmbeddedResource; + +/** + * Text provided to or from an LLM. + * + * @category Content + */ +export interface TextContent { + type: 'text'; + + /** + * The text content of the message. + */ + text: string; + + /** + * Optional annotations for the client. + */ + annotations?: Annotations; + + /** + * See [General fields: `_meta`](/specification/draft/basic/index#meta) for notes on `_meta` usage. + */ + _meta?: { [key: string]: unknown }; +} + +/** + * An image provided to or from an LLM. + * + * @category Content + */ +export interface ImageContent { + type: 'image'; + + /** + * The base64-encoded image data. + * + * @format byte + */ + data: string; + + /** + * The MIME type of the image. Different providers may support different image types. + */ + mimeType: string; + + /** + * Optional annotations for the client. + */ + annotations?: Annotations; + + /** + * See [General fields: `_meta`](/specification/draft/basic/index#meta) for notes on `_meta` usage. + */ + _meta?: { [key: string]: unknown }; +} + +/** + * Audio provided to or from an LLM. + * + * @category Content + */ +export interface AudioContent { + type: 'audio'; + + /** + * The base64-encoded audio data. + * + * @format byte + */ + data: string; + + /** + * The MIME type of the audio. Different providers may support different audio types. + */ + mimeType: string; + + /** + * Optional annotations for the client. + */ + annotations?: Annotations; + + /** + * See [General fields: `_meta`](/specification/draft/basic/index#meta) for notes on `_meta` usage. + */ + _meta?: { [key: string]: unknown }; +} + +/** + * A request from the assistant to call a tool. + * + * @category `sampling/createMessage` + */ +export interface ToolUseContent { + type: 'tool_use'; + + /** + * A unique identifier for this tool use. + * + * This ID is used to match tool results to their corresponding tool uses. + */ + id: string; + + /** + * The name of the tool to call. + */ + name: string; + + /** + * The arguments to pass to the tool, conforming to the tool's input schema. + */ + input: { [key: string]: unknown }; + + /** + * Optional metadata about the tool use. Clients SHOULD preserve this field when + * including tool uses in subsequent sampling requests to enable caching optimizations. + * + * See [General fields: `_meta`](/specification/draft/basic/index#meta) for notes on `_meta` usage. + */ + _meta?: { [key: string]: unknown }; +} + +/** + * The result of a tool use, provided by the user back to the assistant. + * + * @category `sampling/createMessage` + */ +export interface ToolResultContent { + type: 'tool_result'; + + /** + * The ID of the tool use this result corresponds to. + * + * This MUST match the ID from a previous ToolUseContent. + */ + toolUseId: string; + + /** + * The unstructured result content of the tool use. + * + * This has the same format as CallToolResult.content and can include text, images, + * audio, resource links, and embedded resources. + */ + content: ContentBlock[]; + + /** + * An optional structured result object. + * + * If the tool defined an outputSchema, this SHOULD conform to that schema. + */ + structuredContent?: { [key: string]: unknown }; + + /** + * Whether the tool use resulted in an error. + * + * If true, the content typically describes the error that occurred. + * Default: false + */ + isError?: boolean; + + /** + * Optional metadata about the tool result. Clients SHOULD preserve this field when + * including tool results in subsequent sampling requests to enable caching optimizations. + * + * See [General fields: `_meta`](/specification/draft/basic/index#meta) for notes on `_meta` usage. + */ + _meta?: { [key: string]: unknown }; +} + +/** + * The server's preferences for model selection, requested of the client during sampling. + * + * Because LLMs can vary along multiple dimensions, choosing the "best" model is + * rarely straightforward. Different models excel in different areas—some are + * faster but less capable, others are more capable but more expensive, and so + * on. This interface allows servers to express their priorities across multiple + * dimensions to help clients make an appropriate selection for their use case. + * + * These preferences are always advisory. The client MAY ignore them. It is also + * up to the client to decide how to interpret these preferences and how to + * balance them against other considerations. + * + * @category `sampling/createMessage` + */ +export interface ModelPreferences { + /** + * Optional hints to use for model selection. + * + * If multiple hints are specified, the client MUST evaluate them in order + * (such that the first match is taken). + * + * The client SHOULD prioritize these hints over the numeric priorities, but + * MAY still use the priorities to select from ambiguous matches. + */ + hints?: ModelHint[]; + + /** + * How much to prioritize cost when selecting a model. A value of 0 means cost + * is not important, while a value of 1 means cost is the most important + * factor. + * + * @TJS-type number + * @minimum 0 + * @maximum 1 + */ + costPriority?: number; + + /** + * How much to prioritize sampling speed (latency) when selecting a model. A + * value of 0 means speed is not important, while a value of 1 means speed is + * the most important factor. + * + * @TJS-type number + * @minimum 0 + * @maximum 1 + */ + speedPriority?: number; + + /** + * How much to prioritize intelligence and capabilities when selecting a + * model. A value of 0 means intelligence is not important, while a value of 1 + * means intelligence is the most important factor. + * + * @TJS-type number + * @minimum 0 + * @maximum 1 + */ + intelligencePriority?: number; +} + +/** + * Hints to use for model selection. + * + * Keys not declared here are currently left unspecified by the spec and are up + * to the client to interpret. + * + * @category `sampling/createMessage` + */ +export interface ModelHint { + /** + * A hint for a model name. + * + * The client SHOULD treat this as a substring of a model name; for example: + * - `claude-3-5-sonnet` should match `claude-3-5-sonnet-20241022` + * - `sonnet` should match `claude-3-5-sonnet-20241022`, `claude-3-sonnet-20240229`, etc. + * - `claude` should match any Claude model + * + * The client MAY also map the string to a different provider's model name or a different model family, as long as it fills a similar niche; for example: + * - `gemini-1.5-flash` could match `claude-3-haiku-20240307` + */ + name?: string; +} + +/* Autocomplete */ +/** + * Parameters for a `completion/complete` request. + * + * @category `completion/complete` + */ +export interface CompleteRequestParams extends RequestParams { + ref: PromptReference | ResourceTemplateReference; + /** + * The argument's information + */ + argument: { + /** + * The name of the argument + */ + name: string; + /** + * The value of the argument to use for completion matching. + */ + value: string; + }; + + /** + * Additional, optional context for completions + */ + context?: { + /** + * Previously-resolved variables in a URI template or prompt. + */ + arguments?: { [key: string]: string }; + }; +} + +/** + * A request from the client to the server, to ask for completion options. + * + * @category `completion/complete` + */ +export interface CompleteRequest extends JSONRPCRequest { + method: 'completion/complete'; + params: CompleteRequestParams; +} + +/** + * The server's response to a completion/complete request + * + * @category `completion/complete` + */ +export interface CompleteResult extends Result { + completion: { + /** + * An array of completion values. Must not exceed 100 items. + */ + values: string[]; + /** + * The total number of completion options available. This can exceed the number of values actually sent in the response. + */ + total?: number; + /** + * Indicates whether there are additional completion options beyond those provided in the current response, even if the exact total is unknown. + */ + hasMore?: boolean; + }; +} + +/** + * A reference to a resource or resource template definition. + * + * @category `completion/complete` + */ +export interface ResourceTemplateReference { + type: 'ref/resource'; + /** + * The URI or URI template of the resource. + * + * @format uri-template + */ + uri: string; +} + +/** + * Identifies a prompt. + * + * @category `completion/complete` + */ +export interface PromptReference extends BaseMetadata { + type: 'ref/prompt'; +} + +/* Roots */ +/** + * Sent from the server to request a list of root URIs from the client. Roots allow + * servers to ask for specific directories or files to operate on. A common example + * for roots is providing a set of repositories or directories a server should operate + * on. + * + * This request is typically used when the server needs to understand the file system + * structure or access specific locations that the client has permission to read from. + * + * @category `roots/list` + */ +export interface ListRootsRequest extends JSONRPCRequest { + method: 'roots/list'; + params?: RequestParams; +} + +/** + * The client's response to a roots/list request from the server. + * This result contains an array of Root objects, each representing a root directory + * or file that the server can operate on. + * + * @category `roots/list` + */ +export interface ListRootsResult extends Result { + roots: Root[]; +} + +/** + * Represents a root directory or file that the server can operate on. + * + * @category `roots/list` + */ +export interface Root { + /** + * The URI identifying the root. This *must* start with file:// for now. + * This restriction may be relaxed in future versions of the protocol to allow + * other URI schemes. + * + * @format uri + */ + uri: string; + /** + * An optional name for the root. This can be used to provide a human-readable + * identifier for the root, which may be useful for display purposes or for + * referencing the root in other parts of the application. + */ + name?: string; + + /** + * See [General fields: `_meta`](/specification/draft/basic/index#meta) for notes on `_meta` usage. + */ + _meta?: { [key: string]: unknown }; +} + +/** + * A notification from the client to the server, informing it that the list of roots has changed. + * This notification should be sent whenever the client adds, removes, or modifies any root. + * The server should then request an updated list of roots using the ListRootsRequest. + * + * @category `notifications/roots/list_changed` + */ +export interface RootsListChangedNotification extends JSONRPCNotification { + method: 'notifications/roots/list_changed'; + params?: NotificationParams; +} + +/** + * The parameters for a request to elicit non-sensitive information from the user via a form in the client. + * + * @category `elicitation/create` + */ +export interface ElicitRequestFormParams extends TaskAugmentedRequestParams { + /** + * The elicitation mode. + */ + mode?: 'form'; + + /** + * The message to present to the user describing what information is being requested. + */ + message: string; + + /** + * A restricted subset of JSON Schema. + * Only top-level properties are allowed, without nesting. + */ + requestedSchema: { + $schema?: string; + type: 'object'; + properties: { + [key: string]: PrimitiveSchemaDefinition; + }; + required?: string[]; + }; +} + +/** + * The parameters for a request to elicit information from the user via a URL in the client. + * + * @category `elicitation/create` + */ +export interface ElicitRequestURLParams extends TaskAugmentedRequestParams { + /** + * The elicitation mode. + */ + mode: 'url'; + + /** + * The message to present to the user explaining why the interaction is needed. + */ + message: string; + + /** + * The ID of the elicitation, which must be unique within the context of the server. + * The client MUST treat this ID as an opaque value. + */ + elicitationId: string; + + /** + * The URL that the user should navigate to. + * + * @format uri + */ + url: string; +} + +/** + * The parameters for a request to elicit additional information from the user via the client. + * + * @category `elicitation/create` + */ +export type ElicitRequestParams = ElicitRequestFormParams | ElicitRequestURLParams; + +/** + * A request from the server to elicit additional information from the user via the client. + * + * @category `elicitation/create` + */ +export interface ElicitRequest extends JSONRPCRequest { + method: 'elicitation/create'; + params: ElicitRequestParams; +} + +/** + * Restricted schema definitions that only allow primitive types + * without nested objects or arrays. + * + * @category `elicitation/create` + */ +export type PrimitiveSchemaDefinition = StringSchema | NumberSchema | BooleanSchema | EnumSchema; + +/** + * @category `elicitation/create` + */ +export interface StringSchema { + type: 'string'; + title?: string; + description?: string; + minLength?: number; + maxLength?: number; + format?: 'email' | 'uri' | 'date' | 'date-time'; + default?: string; +} + +/** + * @category `elicitation/create` + */ +export interface NumberSchema { + type: 'number' | 'integer'; + title?: string; + description?: string; + minimum?: number; + maximum?: number; + default?: number; +} + +/** + * @category `elicitation/create` + */ +export interface BooleanSchema { + type: 'boolean'; + title?: string; + description?: string; + default?: boolean; +} + +/** + * Schema for single-selection enumeration without display titles for options. + * + * @category `elicitation/create` + */ +export interface UntitledSingleSelectEnumSchema { + type: 'string'; + /** + * Optional title for the enum field. + */ + title?: string; + /** + * Optional description for the enum field. + */ + description?: string; + /** + * Array of enum values to choose from. + */ + enum: string[]; + /** + * Optional default value. + */ + default?: string; +} + +/** + * Schema for single-selection enumeration with display titles for each option. + * + * @category `elicitation/create` + */ +export interface TitledSingleSelectEnumSchema { + type: 'string'; + /** + * Optional title for the enum field. + */ + title?: string; + /** + * Optional description for the enum field. + */ + description?: string; + /** + * Array of enum options with values and display labels. + */ + oneOf: Array<{ + /** + * The enum value. + */ + const: string; + /** + * Display label for this option. + */ + title: string; + }>; + /** + * Optional default value. + */ + default?: string; +} + +/** + * @category `elicitation/create` + */ +// Combined single selection enumeration +export type SingleSelectEnumSchema = UntitledSingleSelectEnumSchema | TitledSingleSelectEnumSchema; + +/** + * Schema for multiple-selection enumeration without display titles for options. + * + * @category `elicitation/create` + */ +export interface UntitledMultiSelectEnumSchema { + type: 'array'; + /** + * Optional title for the enum field. + */ + title?: string; + /** + * Optional description for the enum field. + */ + description?: string; + /** + * Minimum number of items to select. + */ + minItems?: number; + /** + * Maximum number of items to select. + */ + maxItems?: number; + /** + * Schema for the array items. + */ + items: { + type: 'string'; + /** + * Array of enum values to choose from. + */ + enum: string[]; + }; + /** + * Optional default value. + */ + default?: string[]; +} + +/** + * Schema for multiple-selection enumeration with display titles for each option. + * + * @category `elicitation/create` + */ +export interface TitledMultiSelectEnumSchema { + type: 'array'; + /** + * Optional title for the enum field. + */ + title?: string; + /** + * Optional description for the enum field. + */ + description?: string; + /** + * Minimum number of items to select. + */ + minItems?: number; + /** + * Maximum number of items to select. + */ + maxItems?: number; + /** + * Schema for array items with enum options and display labels. + */ + items: { + /** + * Array of enum options with values and display labels. + */ + anyOf: Array<{ + /** + * The constant enum value. + */ + const: string; + /** + * Display title for this option. + */ + title: string; + }>; + }; + /** + * Optional default value. + */ + default?: string[]; +} + +/** + * @category `elicitation/create` + */ +// Combined multiple selection enumeration +export type MultiSelectEnumSchema = UntitledMultiSelectEnumSchema | TitledMultiSelectEnumSchema; + +/** + * Use TitledSingleSelectEnumSchema instead. + * This interface will be removed in a future version. + * + * @category `elicitation/create` + */ +export interface LegacyTitledEnumSchema { + type: 'string'; + title?: string; + description?: string; + enum: string[]; + /** + * (Legacy) Display names for enum values. + * Non-standard according to JSON schema 2020-12. + */ + enumNames?: string[]; + default?: string; +} + +/** + * @category `elicitation/create` + */ +// Union type for all enum schemas +export type EnumSchema = SingleSelectEnumSchema | MultiSelectEnumSchema | LegacyTitledEnumSchema; + +/** + * The client's response to an elicitation request. + * + * @category `elicitation/create` + */ +export interface ElicitResult extends Result { + /** + * The user action in response to the elicitation. + * - "accept": User submitted the form/confirmed the action + * - "decline": User explicitly decline the action + * - "cancel": User dismissed without making an explicit choice + */ + action: 'accept' | 'decline' | 'cancel'; + + /** + * The submitted form data, only present when action is "accept" and mode was "form". + * Contains values matching the requested schema. + * Omitted for out-of-band mode responses. + */ + content?: { [key: string]: string | number | boolean | string[] }; +} + +/** + * An optional notification from the server to the client, informing it of a completion of a out-of-band elicitation request. + * + * @category `notifications/elicitation/complete` + */ +export interface ElicitationCompleteNotification extends JSONRPCNotification { + method: 'notifications/elicitation/complete'; + params: { + /** + * The ID of the elicitation that completed. + */ + elicitationId: string; + }; +} + +/* Client messages */ +/** @internal */ +export type ClientRequest = + | PingRequest + | InitializeRequest + | CompleteRequest + | SetLevelRequest + | GetPromptRequest + | ListPromptsRequest + | ListResourcesRequest + | ListResourceTemplatesRequest + | ReadResourceRequest + | SubscribeRequest + | UnsubscribeRequest + | CallToolRequest + | ListToolsRequest + | GetTaskRequest + | GetTaskPayloadRequest + | ListTasksRequest + | CancelTaskRequest; + +/** @internal */ +export type ClientNotification = + | CancelledNotification + | ProgressNotification + | InitializedNotification + | RootsListChangedNotification + | TaskStatusNotification; + +/** @internal */ +export type ClientResult = + | EmptyResult + | CreateMessageResult + | ListRootsResult + | ElicitResult + | GetTaskResult + | GetTaskPayloadResult + | ListTasksResult + | CancelTaskResult; + +/* Server messages */ +/** @internal */ +export type ServerRequest = + | PingRequest + | CreateMessageRequest + | ListRootsRequest + | ElicitRequest + | GetTaskRequest + | GetTaskPayloadRequest + | ListTasksRequest + | CancelTaskRequest; + +/** @internal */ +export type ServerNotification = + | CancelledNotification + | ProgressNotification + | LoggingMessageNotification + | ResourceUpdatedNotification + | ResourceListChangedNotification + | ToolListChangedNotification + | PromptListChangedNotification + | ElicitationCompleteNotification + | TaskStatusNotification; + +/** @internal */ +export type ServerResult = + | EmptyResult + | InitializeResult + | CompleteResult + | GetPromptResult + | ListPromptsResult + | ListResourceTemplatesResult + | ListResourcesResult + | ReadResourceResult + | CallToolResult + | ListToolsResult + | GetTaskResult + | GetTaskPayloadResult + | ListTasksResult + | CancelTaskResult; diff --git a/src/types.ts b/packages/core/src/types/types.ts similarity index 98% rename from src/types.ts rename to packages/core/src/types/types.ts index dc0c22353..cc086edd4 100644 --- a/src/types.ts +++ b/packages/core/src/types/types.ts @@ -1,5 +1,4 @@ import * as z from 'zod/v4'; -import { AuthInfo } from './server/auth/types.js'; export const LATEST_PROTOCOL_VERSION = '2025-11-25'; export const DEFAULT_NEGOTIATED_PROTOCOL_VERSION = '2025-03-26'; @@ -10,6 +9,43 @@ export const RELATED_TASK_META_KEY = 'io.modelcontextprotocol/related-task'; /* JSON-RPC types */ export const JSONRPC_VERSION = '2.0'; +/** + * Information about a validated access token, provided to request handlers. + */ +export interface AuthInfo { + /** + * The access token. + */ + token: string; + + /** + * The client ID associated with this token. + */ + clientId: string; + + /** + * Scopes associated with this token. + */ + scopes: string[]; + + /** + * When the token expires (in seconds since epoch). + */ + expiresAt?: number; + + /** + * The RFC 8707 resource server identifier for which this token is valid. + * If set, this MUST match the MCP server's resource identifier (minus hash fragment). + */ + resource?: URL; + + /** + * Additional data associated with the token. + * This field should be used for any additional data that needs to be attached to the auth info. + */ + extra?: Record; +} + /** * Utility types */ @@ -2421,7 +2457,8 @@ export type ResourceContents = Infer; export type TextResourceContents = Infer; export type BlobResourceContents = Infer; export type Resource = Infer; -export type ResourceTemplate = Infer; +// TODO: Overlaps with exported `ResourceTemplate` class from `server`. +export type ResourceTemplateType = Infer; export type ListResourcesRequest = Infer; export type ListResourcesResult = Infer; export type ListResourceTemplatesRequest = Infer; diff --git a/src/inMemory.ts b/packages/core/src/util/inMemory.ts similarity index 93% rename from src/inMemory.ts rename to packages/core/src/util/inMemory.ts index 26062624d..3f832b06b 100644 --- a/src/inMemory.ts +++ b/packages/core/src/util/inMemory.ts @@ -1,6 +1,5 @@ -import { Transport } from './shared/transport.js'; -import { JSONRPCMessage, RequestId } from './types.js'; -import { AuthInfo } from './server/auth/types.js'; +import type { Transport } from '../shared/transport.js'; +import type { AuthInfo, JSONRPCMessage, RequestId } from '../types/types.js'; interface QueuedMessage { message: JSONRPCMessage; diff --git a/src/server/zod-compat.ts b/packages/core/src/util/zod-compat.ts similarity index 99% rename from src/server/zod-compat.ts rename to packages/core/src/util/zod-compat.ts index 04ee5361f..b2275090a 100644 --- a/src/server/zod-compat.ts +++ b/packages/core/src/util/zod-compat.ts @@ -4,9 +4,8 @@ // ---------------------------------------------------- import type * as z3 from 'zod/v3'; -import type * as z4 from 'zod/v4/core'; - import * as z3rt from 'zod/v3'; +import type * as z4 from 'zod/v4/core'; import * as z4mini from 'zod/v4-mini'; // --- Unified schema types --- diff --git a/src/server/zod-json-schema-compat.ts b/packages/core/src/util/zod-json-schema-compat.ts similarity index 93% rename from src/server/zod-json-schema-compat.ts rename to packages/core/src/util/zod-json-schema-compat.ts index cde66b177..cbb8b15e9 100644 --- a/src/server/zod-json-schema-compat.ts +++ b/packages/core/src/util/zod-json-schema-compat.ts @@ -6,12 +6,12 @@ import type * as z3 from 'zod/v3'; import type * as z4c from 'zod/v4/core'; - import * as z4mini from 'zod/v4-mini'; - -import { AnySchema, AnyObjectSchema, getObjectShape, safeParse, isZ4Schema, getLiteralValue } from './zod-compat.js'; import { zodToJsonSchema } from 'zod-to-json-schema'; +import type { AnyObjectSchema, AnySchema } from './zod-compat.js'; +import { getLiteralValue, getObjectShape, isZ4Schema, safeParse } from './zod-compat.js'; + type JsonSchema = Record; // Options accepted by call sites; we map them appropriately diff --git a/src/validation/ajv-provider.ts b/packages/core/src/validation/ajv-provider.ts similarity index 96% rename from src/validation/ajv-provider.ts rename to packages/core/src/validation/ajv-provider.ts index 115a98521..4a9d57214 100644 --- a/src/validation/ajv-provider.ts +++ b/packages/core/src/validation/ajv-provider.ts @@ -4,7 +4,8 @@ import { Ajv } from 'ajv'; import _addFormats from 'ajv-formats'; -import type { JsonSchemaType, JsonSchemaValidator, JsonSchemaValidatorResult, jsonSchemaValidator } from './types.js'; + +import type { JsonSchemaType, JsonSchemaValidator, jsonSchemaValidator, JsonSchemaValidatorResult } from './types.js'; function createDefaultAjvInstance(): Ajv { const ajv = new Ajv({ diff --git a/src/validation/cfworker-provider.ts b/packages/core/src/validation/cfworker-provider.ts similarity index 95% rename from src/validation/cfworker-provider.ts rename to packages/core/src/validation/cfworker-provider.ts index 7e6329d9d..460408d62 100644 --- a/src/validation/cfworker-provider.ts +++ b/packages/core/src/validation/cfworker-provider.ts @@ -7,7 +7,8 @@ */ import { Validator } from '@cfworker/json-schema'; -import type { JsonSchemaType, JsonSchemaValidator, JsonSchemaValidatorResult, jsonSchemaValidator } from './types.js'; + +import type { JsonSchemaType, JsonSchemaValidator, jsonSchemaValidator, JsonSchemaValidatorResult } from './types.js'; /** * JSON Schema draft version supported by @cfworker/json-schema diff --git a/src/validation/types.ts b/packages/core/src/validation/types.ts similarity index 100% rename from src/validation/types.ts rename to packages/core/src/validation/types.ts diff --git a/test/inMemory.test.ts b/packages/core/test/inMemory.test.ts similarity index 95% rename from test/inMemory.test.ts rename to packages/core/test/inMemory.test.ts index f42420067..1c73139d9 100644 --- a/test/inMemory.test.ts +++ b/packages/core/test/inMemory.test.ts @@ -1,6 +1,6 @@ -import { InMemoryTransport } from '../src/inMemory.js'; -import { JSONRPCMessage } from '../src/types.js'; -import { AuthInfo } from '../src/server/auth/types.js'; +import { InMemoryTransport } from '../src/util/inMemory.js'; +import { JSONRPCMessage } from '../src/types/types.js'; +import { AuthInfo } from '../src/types/types.js'; describe('InMemoryTransport', () => { let clientTransport: InMemoryTransport; diff --git a/test/shared/auth-utils.test.ts b/packages/core/test/shared/auth-utils.test.ts similarity index 100% rename from test/shared/auth-utils.test.ts rename to packages/core/test/shared/auth-utils.test.ts diff --git a/test/shared/auth.test.ts b/packages/core/test/shared/auth.test.ts similarity index 100% rename from test/shared/auth.test.ts rename to packages/core/test/shared/auth.test.ts diff --git a/test/shared/protocol-transport-handling.test.ts b/packages/core/test/shared/protocol-transport-handling.test.ts similarity index 99% rename from test/shared/protocol-transport-handling.test.ts rename to packages/core/test/shared/protocol-transport-handling.test.ts index 60eff5c2e..67e749fdf 100644 --- a/test/shared/protocol-transport-handling.test.ts +++ b/packages/core/test/shared/protocol-transport-handling.test.ts @@ -1,7 +1,7 @@ import { describe, expect, test, beforeEach } from 'vitest'; import { Protocol } from '../../src/shared/protocol.js'; import { Transport } from '../../src/shared/transport.js'; -import { Request, Notification, Result, JSONRPCMessage } from '../../src/types.js'; +import { Request, Notification, Result, JSONRPCMessage } from '../../src/types/types.js'; import * as z from 'zod/v4'; // Mock Transport class diff --git a/test/shared/protocol.test.ts b/packages/core/test/shared/protocol.test.ts similarity index 98% rename from test/shared/protocol.test.ts rename to packages/core/test/shared/protocol.test.ts index 886dcbb21..d87900723 100644 --- a/test/shared/protocol.test.ts +++ b/packages/core/test/shared/protocol.test.ts @@ -13,12 +13,12 @@ import { type Request, type Notification, type Result -} from '../../src/types.js'; +} from '../../src/types/types.js'; import { Protocol, mergeCapabilities } from '../../src/shared/protocol.js'; import { Transport, TransportSendOptions } from '../../src/shared/transport.js'; import { TaskStore, TaskMessageQueue, QueuedMessage, QueuedNotification, QueuedRequest } from '../../src/experimental/tasks/interfaces.js'; import { MockInstance, vi } from 'vitest'; -import { JSONRPCResultResponse, JSONRPCRequest, JSONRPCErrorResponse } from '../../src/types.js'; +import { JSONRPCResultResponse, JSONRPCRequest, JSONRPCErrorResponse } from '../../src/types/types.js'; import { ErrorMessage, ResponseMessage, toArrayAsync } from '../../src/shared/responseMessage.js'; import { InMemoryTaskMessageQueue } from '../../src/experimental/tasks/stores/in-memory.js'; @@ -712,7 +712,7 @@ describe('protocol tests', () => { expect(sendSpy).toHaveBeenCalledTimes(1); // The final sent object might not even have the `params` key, which is fine. // We can check that it was called and that the params are "falsy". - const sentNotification = sendSpy.mock.calls[0][0]; + const sentNotification = sendSpy.mock.calls[0]![0]; expect(sentNotification.method).toBe('test/debounced'); expect(sentNotification.params).toBeUndefined(); }); @@ -1337,7 +1337,7 @@ describe('Task-based execution', () => { await listedTasks.waitForLatch(); expect(mockTaskStore.listTasks).toHaveBeenCalledWith(undefined, undefined); - const sentMessage = sendSpy.mock.calls[0][0]; + const sentMessage = sendSpy.mock.calls[0]![0]; expect(sentMessage.jsonrpc).toBe('2.0'); expect(sentMessage.id).toBe(3); expect(sentMessage.result.tasks).toEqual([ @@ -1400,7 +1400,7 @@ describe('Task-based execution', () => { await listedTasks.waitForLatch(); expect(mockTaskStore.listTasks).toHaveBeenCalledWith('task-2', undefined); - const sentMessage = sendSpy.mock.calls[0][0]; + const sentMessage = sendSpy.mock.calls[0]![0]; expect(sentMessage.jsonrpc).toBe('2.0'); expect(sentMessage.id).toBe(2); expect(sentMessage.result.tasks).toEqual([ @@ -1444,7 +1444,7 @@ describe('Task-based execution', () => { await listedTasks.waitForLatch(); expect(mockTaskStore.listTasks).toHaveBeenCalledWith(undefined, undefined); - const sentMessage = sendSpy.mock.calls[0][0]; + const sentMessage = sendSpy.mock.calls[0]![0]; expect(sentMessage.jsonrpc).toBe('2.0'); expect(sentMessage.id).toBe(3); expect(sentMessage.result.tasks).toEqual([]); @@ -1479,7 +1479,7 @@ describe('Task-based execution', () => { await new Promise(resolve => setTimeout(resolve, 10)); expect(mockTaskStore.listTasks).toHaveBeenCalledWith('bad-cursor', undefined); - const sentMessage = sendSpy.mock.calls[0][0]; + const sentMessage = sendSpy.mock.calls[0]![0]; expect(sentMessage.jsonrpc).toBe('2.0'); expect(sentMessage.id).toBe(4); expect(sentMessage.error).toBeDefined(); @@ -1497,7 +1497,7 @@ describe('Task-based execution', () => { setTimeout(() => { transport.onmessage?.({ jsonrpc: '2.0', - id: sendSpy.mock.calls[0][0].id, + id: sendSpy.mock.calls[0]![0].id, result: { tasks: [ { @@ -1525,7 +1525,7 @@ describe('Task-based execution', () => { expect.any(Object) ); expect(result.tasks).toHaveLength(1); - expect(result.tasks[0].taskId).toBe('task-1'); + expect(result.tasks[0]?.taskId).toBe('task-1'); }); it('should call listTasks with cursor from client side', async () => { @@ -1537,7 +1537,7 @@ describe('Task-based execution', () => { setTimeout(() => { transport.onmessage?.({ jsonrpc: '2.0', - id: sendSpy.mock.calls[0][0].id, + id: sendSpy.mock.calls[0]![0].id, result: { tasks: [ { @@ -1567,7 +1567,7 @@ describe('Task-based execution', () => { expect.any(Object) ); expect(result.tasks).toHaveLength(1); - expect(result.tasks[0].taskId).toBe('task-11'); + expect(result.tasks[0]?.taskId).toBe('task-11'); expect(result.nextCursor).toBe('task-11'); }); }); @@ -1620,7 +1620,7 @@ describe('Task-based execution', () => { 'Client cancelled task execution.', undefined ); - const sentMessage = sendSpy.mock.calls[0][0] as unknown as JSONRPCResultResponse; + const sentMessage = sendSpy.mock.calls[0]![0] as unknown as JSONRPCResultResponse; expect(sentMessage.jsonrpc).toBe('2.0'); expect(sentMessage.id).toBe(5); expect(sentMessage.result._meta).toBeDefined(); @@ -1658,7 +1658,7 @@ describe('Task-based execution', () => { taskDeleted.releaseLatch(); expect(mockTaskStore.getTask).toHaveBeenCalledWith('non-existent', undefined); - const sentMessage = sendSpy.mock.calls[0][0] as unknown as JSONRPCErrorResponse; + const sentMessage = sendSpy.mock.calls[0]![0] as unknown as JSONRPCErrorResponse; expect(sentMessage.jsonrpc).toBe('2.0'); expect(sentMessage.id).toBe(6); expect(sentMessage.error).toBeDefined(); @@ -1706,7 +1706,7 @@ describe('Task-based execution', () => { expect(mockTaskStore.getTask).toHaveBeenCalledWith(completedTask.taskId, undefined); expect(mockTaskStore.updateTaskStatus).not.toHaveBeenCalled(); - const sentMessage = sendSpy.mock.calls[0][0] as unknown as JSONRPCErrorResponse; + const sentMessage = sendSpy.mock.calls[0]![0] as unknown as JSONRPCErrorResponse; expect(sentMessage.jsonrpc).toBe('2.0'); expect(sentMessage.id).toBe(7); expect(sentMessage.error).toBeDefined(); @@ -1723,7 +1723,7 @@ describe('Task-based execution', () => { setTimeout(() => { transport.onmessage?.({ jsonrpc: '2.0', - id: sendSpy.mock.calls[0][0].id, + id: sendSpy.mock.calls[0]![0].id, result: { _meta: {}, taskId: 'task-to-delete', @@ -1798,7 +1798,7 @@ describe('Task-based execution', () => { // This is done by the RequestTaskStore wrapper to get the updated task for the notification const getTaskCalls = mockTaskStore.getTask.mock.calls; const lastGetTaskCall = getTaskCalls[getTaskCalls.length - 1]; - expect(lastGetTaskCall[0]).toBe(task.taskId); + expect(lastGetTaskCall?.[0]).toBe(task.taskId); }); }); @@ -1848,7 +1848,7 @@ describe('Task-based execution', () => { ); // Verify _meta is not present or doesn't contain RELATED_TASK_META_KEY - const response = sendSpy.mock.calls[0][0] as { result?: { _meta?: Record } }; + const response = sendSpy.mock.calls[0]![0] as { result?: { _meta?: Record } }; expect(response.result?._meta?.[RELATED_TASK_META_KEY]).toBeUndefined(); }); @@ -1885,7 +1885,7 @@ describe('Task-based execution', () => { await new Promise(resolve => setTimeout(resolve, 50)); // Verify response does NOT include related-task metadata - const response = sendSpy.mock.calls[0][0] as { result?: { _meta?: Record } }; + const response = sendSpy.mock.calls[0]![0] as { result?: { _meta?: Record } }; expect(response.result?._meta).toEqual({}); }); @@ -1924,7 +1924,7 @@ describe('Task-based execution', () => { await new Promise(resolve => setTimeout(resolve, 50)); // Verify response does NOT include related-task metadata - const response = sendSpy.mock.calls[0][0] as { result?: { _meta?: Record } }; + const response = sendSpy.mock.calls[0]![0] as { result?: { _meta?: Record } }; expect(response.result?._meta).toEqual({}); }); @@ -2414,7 +2414,7 @@ describe('Progress notification support for tasks', () => { await new Promise(resolve => setTimeout(resolve, 10)); // Get the message ID from the sent request - const sentRequest = sendSpy.mock.calls[0][0] as { id: number; params: { _meta: { progressToken: number } } }; + const sentRequest = sendSpy.mock.calls[0]![0] as { id: number; params: { _meta: { progressToken: number } } }; const messageId = sentRequest.id; const progressToken = sentRequest.params._meta.progressToken; @@ -2523,7 +2523,7 @@ describe('Progress notification support for tasks', () => { // Wait a bit for the request to be sent await new Promise(resolve => setTimeout(resolve, 10)); - const sentRequest = sendSpy.mock.calls[0][0] as { id: number; params: { _meta: { progressToken: number } } }; + const sentRequest = sendSpy.mock.calls[0]![0] as { id: number; params: { _meta: { progressToken: number } } }; const messageId = sentRequest.id; const progressToken = sentRequest.params._meta.progressToken; @@ -2633,7 +2633,7 @@ describe('Progress notification support for tasks', () => { onprogress: progressCallback }); - const sentRequest = sendSpy.mock.calls[0][0] as { id: number; params: { _meta: { progressToken: number } } }; + const sentRequest = sendSpy.mock.calls[0]![0] as { id: number; params: { _meta: { progressToken: number } } }; const messageId = sentRequest.id; const progressToken = sentRequest.params._meta.progressToken; @@ -2731,7 +2731,7 @@ describe('Progress notification support for tasks', () => { onprogress: progressCallback }); - const sentRequest = sendSpy.mock.calls[0][0] as { id: number; params: { _meta: { progressToken: number } } }; + const sentRequest = sendSpy.mock.calls[0]![0] as { id: number; params: { _meta: { progressToken: number } } }; const messageId = sentRequest.id; const progressToken = sentRequest.params._meta.progressToken; @@ -2826,7 +2826,7 @@ describe('Progress notification support for tasks', () => { onprogress: progressCallback }); - const sentRequest = sendSpy.mock.calls[0][0] as { id: number; params: { _meta: { progressToken: number } } }; + const sentRequest = sendSpy.mock.calls[0]![0] as { id: number; params: { _meta: { progressToken: number } } }; const messageId = sentRequest.id; const progressToken = sentRequest.params._meta.progressToken; @@ -2899,7 +2899,7 @@ describe('Progress notification support for tasks', () => { onprogress: onProgressMock }); - const sentMessage = sendSpy.mock.calls[0][0]; + const sentMessage = sendSpy.mock.calls[0]![0]; expect(sentMessage.params._meta.progressToken).toBeDefined(); }); @@ -2924,7 +2924,7 @@ describe('Progress notification support for tasks', () => { onprogress: onProgressMock }); - const sentMessage = sendSpy.mock.calls[0][0]; + const sentMessage = sendSpy.mock.calls[0]![0]; const progressToken = sentMessage.params._meta.progressToken; // Simulate progress notification @@ -2974,7 +2974,7 @@ describe('Progress notification support for tasks', () => { onprogress: onProgressMock }); - const sentMessage = sendSpy.mock.calls[0][0]; + const sentMessage = sendSpy.mock.calls[0]![0]; const progressToken = sentMessage.params._meta.progressToken; // Simulate CreateTaskResult response @@ -3877,7 +3877,7 @@ describe('Message Interception', () => { expect(queue).toBeDefined(); // Clean up the pending request - const requestId = (sendSpy.mock.calls[0][0] as JSONRPCResultResponse).id; + const requestId = (sendSpy.mock.calls[0]![0] as JSONRPCResultResponse).id; transport.onmessage?.({ jsonrpc: '2.0', id: requestId, @@ -4487,7 +4487,7 @@ describe('requestStream() method', () => { // Should yield exactly one result message expect(messages).toHaveLength(1); - expect(messages[0].type).toBe('result'); + expect(messages[0]?.type).toBe('result'); expect(messages[0]).toHaveProperty('result'); }); @@ -4530,10 +4530,10 @@ describe('requestStream() method', () => { // Should yield exactly one error message expect(messages).toHaveLength(1); - expect(messages[0].type).toBe('error'); + expect(messages[0]?.type).toBe('error'); expect(messages[0]).toHaveProperty('error'); - if (messages[0].type === 'error') { - expect(messages[0].error.message).toContain('Test error'); + if (messages[0]?.type === 'error') { + expect(messages[0]?.error?.message).toContain('Test error'); } }); @@ -4568,9 +4568,9 @@ describe('requestStream() method', () => { // Should yield error message about cancellation expect(messages).toHaveLength(1); - expect(messages[0].type).toBe('error'); - if (messages[0].type === 'error') { - expect(messages[0].error.message).toContain('cancelled'); + expect(messages[0]?.type).toBe('error'); + if (messages[0]?.type === 'error') { + expect(messages[0]?.error?.message).toContain('cancelled'); } }); @@ -4610,7 +4610,7 @@ describe('requestStream() method', () => { // Verify error is terminal and last message expect(messages.length).toBeGreaterThan(0); const lastMessage = messages[messages.length - 1]; - assertErrorResponse(lastMessage); + assertErrorResponse(lastMessage!); expect(lastMessage.error).toBeDefined(); expect(lastMessage.error.message).toContain('Server error'); }); @@ -4647,7 +4647,7 @@ describe('requestStream() method', () => { // Verify error is terminal and last message expect(messages.length).toBeGreaterThan(0); const lastMessage = messages[messages.length - 1]; - assertErrorResponse(lastMessage); + assertErrorResponse(lastMessage!); expect(lastMessage.error).toBeDefined(); expect(lastMessage.error.code).toBe(ErrorCode.RequestTimeout); } finally { @@ -4683,7 +4683,7 @@ describe('requestStream() method', () => { // Verify error is terminal and last message expect(messages.length).toBeGreaterThan(0); const lastMessage = messages[messages.length - 1]; - assertErrorResponse(lastMessage); + assertErrorResponse(lastMessage!); expect(lastMessage.error).toBeDefined(); expect(lastMessage.error.message).toContain('cancelled'); }); @@ -4722,7 +4722,7 @@ describe('requestStream() method', () => { // Verify only one message (the error) was yielded expect(messages).toHaveLength(1); - expect(messages[0].type).toBe('error'); + expect(messages[0]?.type).toBe('error'); // Try to send another message (should be ignored) transport.onmessage?.({ @@ -4796,7 +4796,7 @@ describe('requestStream() method', () => { // Verify error is terminal and last message expect(messages.length).toBeGreaterThan(0); const lastMessage = messages[messages.length - 1]; - assertErrorResponse(lastMessage); + assertErrorResponse(lastMessage!); expect(lastMessage.error).toBeDefined(); }); @@ -4824,7 +4824,7 @@ describe('requestStream() method', () => { // Verify error is terminal and last message expect(messages.length).toBeGreaterThan(0); const lastMessage = messages[messages.length - 1]; - assertErrorResponse(lastMessage); + assertErrorResponse(lastMessage!); expect(lastMessage.error).toBeDefined(); }); @@ -4863,12 +4863,12 @@ describe('requestStream() method', () => { // Verify error is the last message expect(messages.length).toBeGreaterThan(0); const lastMessage = messages[messages.length - 1]; - expect(lastMessage.type).toBe('error'); + expect(lastMessage?.type).toBe('error'); // Verify all messages before the last are not terminal for (let i = 0; i < messages.length - 1; i++) { - expect(messages[i].type).not.toBe('error'); - expect(messages[i].type).not.toBe('result'); + expect(messages[i]?.type).not.toBe('error'); + expect(messages[i]?.type).not.toBe('result'); } }); }); @@ -5052,7 +5052,7 @@ describe('Error handling for missing resolvers', () => { expect(resolverMock).toHaveBeenCalledWith(expect.any(McpError)); // Verify the error has the correct properties - const calledError = resolverMock.mock.calls[0][0]; + const calledError = resolverMock.mock.calls[0]![0]; expect(calledError.code).toBe(ErrorCode.InternalError); expect(calledError.message).toContain('Task cancelled or completed'); @@ -5112,7 +5112,7 @@ describe('Error handling for missing resolvers', () => { expect(resolverMock).toHaveBeenCalledWith(expect.any(McpError)); // Verify the error has the correct properties - const calledError = resolverMock.mock.calls[0][0]; + const calledError = resolverMock.mock.calls[0]![0]; expect(calledError.code).toBe(ErrorCode.InternalError); expect(calledError.message).toContain('Task cancelled or completed'); @@ -5266,7 +5266,7 @@ describe('Error handling for missing resolvers', () => { // Verify resolver was called with McpError expect(resolverMock).toHaveBeenCalledWith(expect.any(McpError)); - const calledError = resolverMock.mock.calls[0][0]; + const calledError = resolverMock.mock.calls[0]![0]; expect(calledError.code).toBe(ErrorCode.InvalidRequest); expect(calledError.message).toContain('Invalid request parameters'); @@ -5361,7 +5361,7 @@ describe('Error handling for missing resolvers', () => { // Verify resolver was called with McpError including data expect(resolverMock).toHaveBeenCalledWith(expect.any(McpError)); - const calledError = resolverMock.mock.calls[0][0]; + const calledError = resolverMock.mock.calls[0]![0]; expect(calledError.code).toBe(ErrorCode.InvalidParams); expect(calledError.message).toContain('Validation failed'); expect(calledError.data).toEqual({ field: 'userName', reason: 'required' }); @@ -5482,7 +5482,7 @@ describe('Error handling for missing resolvers', () => { expect(resolver3).toHaveBeenCalledWith(expect.objectContaining({ id: 3 })); // Verify error has correct properties - const error = resolver2.mock.calls[0][0]; + const error = resolver2.mock.calls[0]![0]; expect(error.code).toBe(ErrorCode.InvalidRequest); expect(error.message).toContain('Request failed'); diff --git a/test/shared/stdio.test.ts b/packages/core/test/shared/stdio.test.ts similarity index 94% rename from test/shared/stdio.test.ts rename to packages/core/test/shared/stdio.test.ts index e8cbb5245..a01f770db 100644 --- a/test/shared/stdio.test.ts +++ b/packages/core/test/shared/stdio.test.ts @@ -1,4 +1,4 @@ -import { JSONRPCMessage } from '../../src/types.js'; +import { JSONRPCMessage } from '../../src/types/types.js'; import { ReadBuffer } from '../../src/shared/stdio.js'; const testMessage: JSONRPCMessage = { diff --git a/test/shared/toolNameValidation.test.ts b/packages/core/test/shared/toolNameValidation.test.ts similarity index 100% rename from test/shared/toolNameValidation.test.ts rename to packages/core/test/shared/toolNameValidation.test.ts diff --git a/test/shared/uriTemplate.test.ts b/packages/core/test/shared/uriTemplate.test.ts similarity index 100% rename from test/shared/uriTemplate.test.ts rename to packages/core/test/shared/uriTemplate.test.ts diff --git a/test/spec.types.test.ts b/packages/core/test/spec.types.test.ts similarity index 98% rename from test/spec.types.test.ts rename to packages/core/test/spec.types.test.ts index 1fff0f0ff..731db66b8 100644 --- a/test/spec.types.test.ts +++ b/packages/core/test/spec.types.test.ts @@ -5,9 +5,10 @@ * - Runtime checks to verify each Spec type has a static check * (note: a few don't have SDK types, see MISSING_SDK_TYPES below) */ -import * as SDKTypes from '../src/types.js'; -import * as SpecTypes from '../src/spec.types.js'; +import * as SDKTypes from '../src/types/types.js'; +import * as SpecTypes from '../src/types/spec.types.js'; import fs from 'node:fs'; +import path from 'node:path'; /* eslint-disable @typescript-eslint/no-unused-vars */ /* eslint-disable @typescript-eslint/no-unsafe-function-type */ @@ -417,7 +418,7 @@ const sdkTypeChecks = { sdk = spec; spec = sdk; }, - ResourceTemplate: (sdk: SDKTypes.ResourceTemplate, spec: SpecTypes.ResourceTemplate) => { + ResourceTemplate: (sdk: SDKTypes.ResourceTemplateType, spec: SpecTypes.ResourceTemplate) => { sdk = spec; spec = sdk; }, @@ -690,8 +691,8 @@ const sdkTypeChecks = { }; // This file is .gitignore'd, and fetched by `npm run fetch:spec-types` (called by `npm run test`) -const SPEC_TYPES_FILE = 'src/spec.types.ts'; -const SDK_TYPES_FILE = 'src/types.ts'; +const SPEC_TYPES_FILE = path.resolve(__dirname, '../src/types/spec.types.ts'); +const SDK_TYPES_FILE = path.resolve(__dirname, '../src/types/types.ts'); const MISSING_SDK_TYPES = [ // These are inlined in the SDK: @@ -700,7 +701,8 @@ const MISSING_SDK_TYPES = [ ]; function extractExportedTypes(source: string): string[] { - return [...source.matchAll(/export\s+(?:interface|class|type)\s+(\w+)\b/g)].map(m => m[1]); + const matches = [...source.matchAll(/export\s+(?:interface|class|type)\s+(\w+)\b/g)]; + return matches.map(m => m[1]!); } describe('Spec Types', () => { diff --git a/test/types.capabilities.test.ts b/packages/core/test/types.capabilities.test.ts similarity index 99% rename from test/types.capabilities.test.ts rename to packages/core/test/types.capabilities.test.ts index 6d7c39dc7..ed414d2db 100644 --- a/test/types.capabilities.test.ts +++ b/packages/core/test/types.capabilities.test.ts @@ -1,4 +1,4 @@ -import { ClientCapabilitiesSchema, InitializeRequestParamsSchema } from '../src/types.js'; +import { ClientCapabilitiesSchema, InitializeRequestParamsSchema } from '../src/types/types.js'; describe('ClientCapabilitiesSchema backwards compatibility', () => { describe('ElicitationCapabilitySchema preprocessing', () => { diff --git a/test/types.test.ts b/packages/core/test/types.test.ts similarity index 98% rename from test/types.test.ts rename to packages/core/test/types.test.ts index 78e5bf5a7..d843a247a 100644 --- a/test/types.test.ts +++ b/packages/core/test/types.test.ts @@ -15,7 +15,7 @@ import { CreateMessageResultSchema, CreateMessageResultWithToolsSchema, ClientCapabilitiesSchema -} from '../src/types.js'; +} from '../src/types/types.js'; describe('Types', () => { test('should have correct latest protocol version', () => { @@ -273,9 +273,9 @@ describe('Types', () => { expect(result.success).toBe(true); if (result.success) { expect(result.data.content).toHaveLength(3); - expect(result.data.content[0].type).toBe('text'); - expect(result.data.content[1].type).toBe('resource_link'); - expect(result.data.content[2].type).toBe('resource_link'); + expect(result.data.content[0]?.type).toBe('text'); + expect(result.data.content[1]?.type).toBe('resource_link'); + expect(result.data.content[2]?.type).toBe('resource_link'); } }); @@ -899,8 +899,8 @@ describe('Types', () => { expect(Array.isArray(content)).toBe(true); if (Array.isArray(content)) { expect(content).toHaveLength(2); - expect(content[0].type).toBe('text'); - expect(content[1].type).toBe('tool_use'); + expect(content[0]?.type).toBe('text'); + expect(content[1]?.type).toBe('tool_use'); } } diff --git a/test/validation/validation.test.ts b/packages/core/test/validation/validation.test.ts similarity index 100% rename from test/validation/validation.test.ts rename to packages/core/test/validation/validation.test.ts diff --git a/packages/core/tsconfig.build.json b/packages/core/tsconfig.build.json new file mode 100644 index 000000000..eabb8d8ff --- /dev/null +++ b/packages/core/tsconfig.build.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "./dist", + "rootDir": "./src" + }, + "include": ["./"], + "exclude": ["dist", "node_modules", "test"] +} diff --git a/packages/core/tsconfig.json b/packages/core/tsconfig.json new file mode 100644 index 000000000..c23f7547e --- /dev/null +++ b/packages/core/tsconfig.json @@ -0,0 +1,15 @@ +{ + "extends": "@modelcontextprotocol/tsconfig", + "include": ["./"], + "exclude": ["node_modules", "dist"], + "compilerOptions": { + "baseUrl": ".", + "paths": { + "*": ["./*"], + "@modelcontextprotocol/sdk-client": ["node_modules/@modelcontextprotocol/sdk-client/src/index.ts"], + "@modelcontextprotocol/sdk-server": ["node_modules/@modelcontextprotocol/sdk-server/src/index.ts"], + "@modelcontextprotocol/eslint-config": ["node_modules/@modelcontextprotocol/eslint-config/tsconfig.json"], + "@modelcontextprotocol/vitest-config": ["node_modules/@modelcontextprotocol/vitest-config/tsconfig.json"] + } + } +} diff --git a/packages/core/vitest.config.js b/packages/core/vitest.config.js new file mode 100644 index 000000000..496fca320 --- /dev/null +++ b/packages/core/vitest.config.js @@ -0,0 +1,3 @@ +import baseConfig from '@modelcontextprotocol/vitest-config'; + +export default baseConfig; diff --git a/src/examples/README.md b/packages/examples/client/README.md similarity index 100% rename from src/examples/README.md rename to packages/examples/client/README.md diff --git a/packages/examples/client/eslint.config.mjs b/packages/examples/client/eslint.config.mjs new file mode 100644 index 000000000..83b79879f --- /dev/null +++ b/packages/examples/client/eslint.config.mjs @@ -0,0 +1,14 @@ +// @ts-check + +import baseConfig from '@modelcontextprotocol/eslint-config'; + +export default [ + ...baseConfig, + { + files: ['src/**/*.{ts,tsx,js,jsx,mts,cts}'], + rules: { + // Allow console statements in examples only + 'no-console': 'off' + } + } +]; diff --git a/packages/examples/client/package.json b/packages/examples/client/package.json new file mode 100644 index 000000000..e46e2aff8 --- /dev/null +++ b/packages/examples/client/package.json @@ -0,0 +1,41 @@ +{ + "name": "@modelcontextprotocol/sdk-examples-client", + "private": true, + "version": "2.0.0-alpha.0", + "description": "Model Context Protocol implementation for TypeScript", + "license": "MIT", + "author": "Anthropic, PBC (https://anthropic.com)", + "homepage": "https://modelcontextprotocol.io", + "bugs": "https://github.com/modelcontextprotocol/typescript-sdk/issues", + "type": "module", + "repository": { + "type": "git", + "url": "git+https://github.com/modelcontextprotocol/typescript-sdk.git" + }, + "engines": { + "node": ">=18" + }, + "keywords": [ + "modelcontextprotocol", + "mcp" + ], + "scripts": { + "typecheck": "tsc -p tsconfig.build.json --noEmit", + "prepack": "npm run build:esm && npm run build:cjs", + "lint": "eslint src/ && prettier --check .", + "lint:fix": "eslint src/ --fix && prettier --write .", + "check": "npm run typecheck && npm run lint", + "start": "npm run server", + "server": "tsx watch --clear-screen=false scripts/cli.ts server", + "client": "tsx scripts/cli.ts client" + }, + "dependencies": { + "@modelcontextprotocol/sdk-client": "workspace:^" + }, + "devDependencies": { + "@modelcontextprotocol/sdk-examples-shared": "workspace:^", + "@modelcontextprotocol/tsconfig": "workspace:^", + "@modelcontextprotocol/eslint-config": "workspace:^", + "@modelcontextprotocol/vitest-config": "workspace:^" + } +} diff --git a/src/examples/client/elicitationUrlExample.ts b/packages/examples/client/src/elicitationUrlExample.ts similarity index 98% rename from src/examples/client/elicitationUrlExample.ts rename to packages/examples/client/src/elicitationUrlExample.ts index b57927e3f..2d235a224 100644 --- a/src/examples/client/elicitationUrlExample.ts +++ b/packages/examples/client/src/elicitationUrlExample.ts @@ -5,30 +5,34 @@ // URL elicitation allows servers to prompt the end-user to open a URL in their browser // to collect sensitive information. -import { Client } from '../../client/index.js'; -import { StreamableHTTPClientTransport } from '../../client/streamableHttp.js'; +import { exec } from 'node:child_process'; +import { createServer } from 'node:http'; import { createInterface } from 'node:readline'; -import { - ListToolsRequest, - ListToolsResultSchema, + +import type { CallToolRequest, - CallToolResultSchema, - ElicitRequestSchema, ElicitRequest, - ElicitResult, - ResourceLink, ElicitRequestURLParams, - McpError, + ElicitResult, + ListToolsRequest, + OAuthClientMetadata, + ResourceLink +} from '@modelcontextprotocol/sdk-client'; +import { + CallToolResultSchema, + Client, + ElicitationCompleteNotificationSchema, + ElicitRequestSchema, ErrorCode, - UrlElicitationRequiredError, - ElicitationCompleteNotificationSchema -} from '../../types.js'; -import { getDisplayName } from '../../shared/metadataUtils.js'; -import { OAuthClientMetadata } from '../../shared/auth.js'; -import { exec } from 'node:child_process'; + getDisplayName, + ListToolsResultSchema, + McpError, + StreamableHTTPClientTransport, + UnauthorizedError, + UrlElicitationRequiredError +} from '@modelcontextprotocol/sdk-client'; + import { InMemoryOAuthClientProvider } from './simpleOAuthClientProvider.js'; -import { UnauthorizedError } from '../../client/auth.js'; -import { createServer } from 'node:http'; // Set up OAuth (required for this example) const OAUTH_CALLBACK_PORT = 8090; // Use different port than auth server (3001) @@ -171,7 +175,7 @@ async function commandLoop(): Promise { if (args.length < 2) { console.log('Usage: call-tool [args]'); } else { - const toolName = args[1]; + const toolName = args[1]!; let toolArgs = {}; if (args.length > 2) { try { diff --git a/src/examples/client/multipleClientsParallel.ts b/packages/examples/client/src/multipleClientsParallel.ts similarity index 95% rename from src/examples/client/multipleClientsParallel.ts rename to packages/examples/client/src/multipleClientsParallel.ts index 492235cdd..46ea7a5c0 100644 --- a/src/examples/client/multipleClientsParallel.ts +++ b/packages/examples/client/src/multipleClientsParallel.ts @@ -1,6 +1,10 @@ -import { Client } from '../../client/index.js'; -import { StreamableHTTPClientTransport } from '../../client/streamableHttp.js'; -import { CallToolRequest, CallToolResultSchema, LoggingMessageNotificationSchema, CallToolResult } from '../../types.js'; +import type { CallToolRequest, CallToolResult } from '@modelcontextprotocol/sdk-client'; +import { + CallToolResultSchema, + Client, + LoggingMessageNotificationSchema, + StreamableHTTPClientTransport +} from '@modelcontextprotocol/sdk-client'; /** * Multiple Clients MCP Example diff --git a/src/examples/client/parallelToolCallsClient.ts b/packages/examples/client/src/parallelToolCallsClient.ts similarity index 97% rename from src/examples/client/parallelToolCallsClient.ts rename to packages/examples/client/src/parallelToolCallsClient.ts index 2ad249de7..01a42a041 100644 --- a/src/examples/client/parallelToolCallsClient.ts +++ b/packages/examples/client/src/parallelToolCallsClient.ts @@ -1,12 +1,11 @@ -import { Client } from '../../client/index.js'; -import { StreamableHTTPClientTransport } from '../../client/streamableHttp.js'; +import type { CallToolResult, ListToolsRequest } from '@modelcontextprotocol/sdk-client'; import { - ListToolsRequest, - ListToolsResultSchema, CallToolResultSchema, + Client, + ListToolsResultSchema, LoggingMessageNotificationSchema, - CallToolResult -} from '../../types.js'; + StreamableHTTPClientTransport +} from '@modelcontextprotocol/sdk-client'; /** * Parallel Tool Calls MCP Client diff --git a/src/examples/client/simpleClientCredentials.ts b/packages/examples/client/src/simpleClientCredentials.ts similarity index 89% rename from src/examples/client/simpleClientCredentials.ts rename to packages/examples/client/src/simpleClientCredentials.ts index 7defcc41f..6e298ea90 100644 --- a/src/examples/client/simpleClientCredentials.ts +++ b/packages/examples/client/src/simpleClientCredentials.ts @@ -18,10 +18,8 @@ * MCP_SERVER_URL - Server URL (default: http://localhost:3000/mcp) */ -import { Client } from '../../client/index.js'; -import { StreamableHTTPClientTransport } from '../../client/streamableHttp.js'; -import { ClientCredentialsProvider, PrivateKeyJwtProvider } from '../../client/auth-extensions.js'; -import { OAuthClientProvider } from '../../client/auth.js'; +import type { OAuthClientProvider } from '@modelcontextprotocol/sdk-client'; +import { Client, ClientCredentialsProvider, PrivateKeyJwtProvider, StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk-client'; const DEFAULT_SERVER_URL = process.env.MCP_SERVER_URL || 'http://localhost:3000/mcp'; diff --git a/src/examples/client/simpleOAuthClient.ts b/packages/examples/client/src/simpleOAuthClient.ts similarity index 97% rename from src/examples/client/simpleOAuthClient.ts rename to packages/examples/client/src/simpleOAuthClient.ts index 8071e61ac..e74404fed 100644 --- a/src/examples/client/simpleOAuthClient.ts +++ b/packages/examples/client/src/simpleOAuthClient.ts @@ -1,14 +1,19 @@ #!/usr/bin/env node +import { exec } from 'node:child_process'; import { createServer } from 'node:http'; import { createInterface } from 'node:readline'; import { URL } from 'node:url'; -import { exec } from 'node:child_process'; -import { Client } from '../../client/index.js'; -import { StreamableHTTPClientTransport } from '../../client/streamableHttp.js'; -import { OAuthClientMetadata } from '../../shared/auth.js'; -import { CallToolRequest, ListToolsRequest, CallToolResultSchema, ListToolsResultSchema } from '../../types.js'; -import { UnauthorizedError } from '../../client/auth.js'; + +import type { CallToolRequest, ListToolsRequest, OAuthClientMetadata } from '@modelcontextprotocol/sdk-client'; +import { + CallToolResultSchema, + Client, + ListToolsResultSchema, + StreamableHTTPClientTransport, + UnauthorizedError +} from '@modelcontextprotocol/sdk-client'; + import { InMemoryOAuthClientProvider } from './simpleOAuthClientProvider.js'; // Configuration diff --git a/src/examples/client/simpleOAuthClientProvider.ts b/packages/examples/client/src/simpleOAuthClientProvider.ts similarity index 91% rename from src/examples/client/simpleOAuthClientProvider.ts rename to packages/examples/client/src/simpleOAuthClientProvider.ts index 3f1932c3e..8c21c14ca 100644 --- a/src/examples/client/simpleOAuthClientProvider.ts +++ b/packages/examples/client/src/simpleOAuthClientProvider.ts @@ -1,5 +1,4 @@ -import { OAuthClientProvider } from '../../client/auth.js'; -import { OAuthClientInformationMixed, OAuthClientMetadata, OAuthTokens } from '../../shared/auth.js'; +import type { OAuthClientInformationMixed, OAuthClientMetadata, OAuthClientProvider, OAuthTokens } from '@modelcontextprotocol/sdk-client'; /** * In-memory OAuth client provider for demonstration purposes diff --git a/src/examples/client/simpleStreamableHttp.ts b/packages/examples/client/src/simpleStreamableHttp.ts similarity index 98% rename from src/examples/client/simpleStreamableHttp.ts rename to packages/examples/client/src/simpleStreamableHttp.ts index 21ab4f556..a3cc7deb0 100644 --- a/src/examples/client/simpleStreamableHttp.ts +++ b/packages/examples/client/src/simpleStreamableHttp.ts @@ -1,28 +1,31 @@ -import { Client } from '../../client/index.js'; -import { StreamableHTTPClientTransport } from '../../client/streamableHttp.js'; import { createInterface } from 'node:readline'; -import { - ListToolsRequest, - ListToolsResultSchema, + +import type { CallToolRequest, - CallToolResultSchema, - ListPromptsRequest, - ListPromptsResultSchema, GetPromptRequest, - GetPromptResultSchema, + ListPromptsRequest, ListResourcesRequest, + ListToolsRequest, + ReadResourceRequest, + ResourceLink +} from '@modelcontextprotocol/sdk-client'; +import { + CallToolResultSchema, + Client, + ElicitRequestSchema, + ErrorCode, + getDisplayName, + GetPromptResultSchema, + ListPromptsResultSchema, ListResourcesResultSchema, + ListToolsResultSchema, LoggingMessageNotificationSchema, - ResourceListChangedNotificationSchema, - ElicitRequestSchema, - ResourceLink, - ReadResourceRequest, + McpError, ReadResourceResultSchema, RELATED_TASK_META_KEY, - ErrorCode, - McpError -} from '../../types.js'; -import { getDisplayName } from '../../shared/metadataUtils.js'; + ResourceListChangedNotificationSchema, + StreamableHTTPClientTransport +} from '@modelcontextprotocol/sdk-client'; import { Ajv } from 'ajv'; // Create readline interface for user input @@ -106,7 +109,7 @@ function commandLoop(): void { if (args.length < 2) { console.log('Usage: call-tool [args]'); } else { - const toolName = args[1]; + const toolName = args[1]!; let toolArgs = {}; if (args.length > 2) { try { @@ -149,7 +152,7 @@ function commandLoop(): void { if (args.length < 2) { console.log('Usage: call-tool-task [args]'); } else { - const toolName = args[1]; + const toolName = args[1]!; let toolArgs = {}; if (args.length > 2) { try { @@ -170,7 +173,7 @@ function commandLoop(): void { if (args.length < 2) { console.log('Usage: get-prompt [args]'); } else { - const promptName = args[1]; + const promptName = args[1]!; let promptArgs = {}; if (args.length > 2) { try { @@ -191,7 +194,7 @@ function commandLoop(): void { if (args.length < 2) { console.log('Usage: read-resource '); } else { - await readResource(args[1]); + await readResource(args[1]!); } break; diff --git a/src/examples/client/simpleTaskInteractiveClient.ts b/packages/examples/client/src/simpleTaskInteractiveClient.ts similarity index 95% rename from src/examples/client/simpleTaskInteractiveClient.ts rename to packages/examples/client/src/simpleTaskInteractiveClient.ts index 06ed0ead1..dacbc21e5 100644 --- a/src/examples/client/simpleTaskInteractiveClient.ts +++ b/packages/examples/client/src/simpleTaskInteractiveClient.ts @@ -7,19 +7,18 @@ * - Using task-based tool execution with streaming */ -import { Client } from '../../client/index.js'; -import { StreamableHTTPClientTransport } from '../../client/streamableHttp.js'; import { createInterface } from 'node:readline'; + +import type { CreateMessageRequest, CreateMessageResult, TextContent } from '@modelcontextprotocol/sdk-client'; import { CallToolResultSchema, - TextContent, - ElicitRequestSchema, + Client, CreateMessageRequestSchema, - CreateMessageRequest, - CreateMessageResult, + ElicitRequestSchema, ErrorCode, - McpError -} from '../../types.js'; + McpError, + StreamableHTTPClientTransport +} from '@modelcontextprotocol/sdk-client'; // Create readline interface for user input const readline = createInterface({ @@ -59,7 +58,7 @@ async function samplingCallback(params: CreateMessageRequest['params']): Promise // Get the prompt from the first message let prompt = 'unknown'; if (params.messages && params.messages.length > 0) { - const firstMessage = params.messages[0]; + const firstMessage = params.messages[0]!; const content = firstMessage.content; if (typeof content === 'object' && !Array.isArray(content) && content.type === 'text' && 'text' in content) { prompt = content.text; @@ -192,7 +191,7 @@ let url = 'http://localhost:8000/mcp'; for (let i = 0; i < args.length; i++) { if (args[i] === '--url' && args[i + 1]) { - url = args[i + 1]; + url = args[i + 1]!; i++; } } diff --git a/src/examples/client/ssePollingClient.ts b/packages/examples/client/src/ssePollingClient.ts similarity index 94% rename from src/examples/client/ssePollingClient.ts rename to packages/examples/client/src/ssePollingClient.ts index ac7bba37d..c98477936 100644 --- a/src/examples/client/ssePollingClient.ts +++ b/packages/examples/client/src/ssePollingClient.ts @@ -12,9 +12,12 @@ * Run with: npx tsx src/examples/client/ssePollingClient.ts * Requires: ssePollingExample.ts server running on port 3001 */ -import { Client } from '../../client/index.js'; -import { StreamableHTTPClientTransport } from '../../client/streamableHttp.js'; -import { CallToolResultSchema, LoggingMessageNotificationSchema } from '../../types.js'; +import { + CallToolResultSchema, + Client, + LoggingMessageNotificationSchema, + StreamableHTTPClientTransport +} from '@modelcontextprotocol/sdk-client'; const SERVER_URL = 'http://localhost:3001/mcp'; diff --git a/src/examples/client/streamableHttpWithSseFallbackClient.ts b/packages/examples/client/src/streamableHttpWithSseFallbackClient.ts similarity index 95% rename from src/examples/client/streamableHttpWithSseFallbackClient.ts rename to packages/examples/client/src/streamableHttpWithSseFallbackClient.ts index 657f48953..656b8ec98 100644 --- a/src/examples/client/streamableHttpWithSseFallbackClient.ts +++ b/packages/examples/client/src/streamableHttpWithSseFallbackClient.ts @@ -1,13 +1,12 @@ -import { Client } from '../../client/index.js'; -import { StreamableHTTPClientTransport } from '../../client/streamableHttp.js'; -import { SSEClientTransport } from '../../client/sse.js'; +import type { CallToolRequest, ListToolsRequest } from '@modelcontextprotocol/sdk-client'; import { - ListToolsRequest, - ListToolsResultSchema, - CallToolRequest, CallToolResultSchema, - LoggingMessageNotificationSchema -} from '../../types.js'; + Client, + ListToolsResultSchema, + LoggingMessageNotificationSchema, + SSEClientTransport, + StreamableHTTPClientTransport +} from '@modelcontextprotocol/sdk-client'; /** * Simplified Backwards Compatible MCP Client diff --git a/packages/examples/client/tsconfig.build.json b/packages/examples/client/tsconfig.build.json new file mode 100644 index 000000000..eabb8d8ff --- /dev/null +++ b/packages/examples/client/tsconfig.build.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "./dist", + "rootDir": "./src" + }, + "include": ["./"], + "exclude": ["dist", "node_modules", "test"] +} diff --git a/packages/examples/client/tsconfig.json b/packages/examples/client/tsconfig.json new file mode 100644 index 000000000..80eb913eb --- /dev/null +++ b/packages/examples/client/tsconfig.json @@ -0,0 +1,18 @@ +{ + "extends": "@modelcontextprotocol/tsconfig", + "include": ["./", "../shared/test/demoInMemoryOAuthProvider.test.ts"], + "exclude": ["node_modules", "dist"], + "compilerOptions": { + "baseUrl": ".", + "paths": { + "*": ["./*"], + "@modelcontextprotocol/sdk-client": ["node_modules/@modelcontextprotocol/sdk-client/src/index.ts"], + "@modelcontextprotocol/sdk-core": [ + "node_modules/@modelcontextprotocol/sdk-client/node_modules/@modelcontextprotocol/sdk-core/src/index.ts" + ], + "@modelcontextprotocol/eslint-config": ["node_modules/@modelcontextprotocol/eslint-config/tsconfig.json"], + "@modelcontextprotocol/vitest-config": ["node_modules/@modelcontextprotocol/vitest-config/tsconfig.json"], + "@modelcontextprotocol/sdk-examples-shared": ["node_modules/@modelcontextprotocol/sdk-examples-shared/src/index.ts"] + } + } +} diff --git a/packages/examples/client/vitest.config.js b/packages/examples/client/vitest.config.js new file mode 100644 index 000000000..496fca320 --- /dev/null +++ b/packages/examples/client/vitest.config.js @@ -0,0 +1,3 @@ +import baseConfig from '@modelcontextprotocol/vitest-config'; + +export default baseConfig; diff --git a/packages/examples/server/README.md b/packages/examples/server/README.md new file mode 100644 index 000000000..c8f7c4352 --- /dev/null +++ b/packages/examples/server/README.md @@ -0,0 +1,352 @@ +# MCP TypeScript SDK Examples + +This directory contains example implementations of MCP clients and servers using the TypeScript SDK. For a high-level index of scenarios and where they live, see the **Examples** table in the root `README.md`. + +## Table of Contents + +- [Client Implementations](#client-implementations) + - [Streamable HTTP Client](#streamable-http-client) + - [Backwards Compatible Client](#backwards-compatible-client) + - [URL Elicitation Example Client](#url-elicitation-example-client) +- [Server Implementations](#server-implementations) + - [Single Node Deployment](#single-node-deployment) + - [Streamable HTTP Transport](#streamable-http-transport) + - [Deprecated SSE Transport](#deprecated-sse-transport) + - [Backwards Compatible Server](#streamable-http-backwards-compatible-server-with-sse) + - [Form Elicitation Example](#form-elicitation-example) + - [URL Elicitation Example](#url-elicitation-example) + - [Multi-Node Deployment](#multi-node-deployment) +- [Backwards Compatibility](#testing-streamable-http-backwards-compatibility-with-sse) + +## Client Implementations + +### Streamable HTTP Client + +A full-featured interactive client that connects to a Streamable HTTP server, demonstrating how to: + +- Establish and manage a connection to an MCP server +- List and call tools with arguments +- Handle notifications through the SSE stream +- List and get prompts with arguments +- List available resources +- Handle session termination and reconnection +- Support for resumability with Last-Event-ID tracking + +```bash +npx tsx src/examples/client/simpleStreamableHttp.ts +``` + +Example client with OAuth: + +```bash +npx tsx src/examples/client/simpleOAuthClient.ts +``` + +Client credentials (machine-to-machine) example: + +```bash +npx tsx src/examples/client/simpleClientCredentials.ts +``` + +### Backwards Compatible Client + +A client that implements backwards compatibility according to the [MCP specification](https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#backwards-compatibility), allowing it to work with both new and legacy servers. This client demonstrates: + +- The client first POSTs an initialize request to the server URL: + - If successful, it uses the Streamable HTTP transport + - If it fails with a 4xx status, it attempts a GET request to establish an SSE stream + +```bash +npx tsx src/examples/client/streamableHttpWithSseFallbackClient.ts +``` + +### URL Elicitation Example Client + +A client that demonstrates how to use URL elicitation to securely collect _sensitive_ user input or perform secure third-party flows. + +```bash +# First, run the server: +npx tsx src/examples/server/elicitationUrlExample.ts + +# Then, run the client: +npx tsx src/examples/client/elicitationUrlExample.ts + +``` + +## Server Implementations + +### Single Node Deployment + +These examples demonstrate how to set up an MCP server on a single node with different transport options. + +#### Streamable HTTP Transport + +##### Simple Streamable HTTP Server + +A server that implements the Streamable HTTP transport (protocol version 2025-11-25). + +- Basic server setup with Express and the Streamable HTTP transport +- Session management with an in-memory event store for resumability +- Tool implementation with the `greet` and `multi-greet` tools +- Prompt implementation with the `greeting-template` prompt +- Static resource exposure +- Support for notifications via SSE stream established by GET requests +- Session termination via DELETE requests + +```bash +npx tsx src/examples/server/simpleStreamableHttp.ts + +# To add a demo of authentication to this example, use: +npx tsx src/examples/server/simpleStreamableHttp.ts --oauth + +# To mitigate impersonation risks, enable strict Resource Identifier verification: +npx tsx src/examples/server/simpleStreamableHttp.ts --oauth --oauth-strict +``` + +##### JSON Response Mode Server + +A server that uses Streamable HTTP transport with JSON response mode enabled (no SSE). + +- Streamable HTTP with JSON response mode, which returns responses directly in the response body +- Limited support for notifications (since SSE is disabled) +- Proper response handling according to the MCP specification for servers that don't support SSE +- Returning appropriate HTTP status codes for unsupported methods + +```bash +npx tsx src/examples/server/jsonResponseStreamableHttp.ts +``` + +##### Streamable HTTP with server notifications + +A server that demonstrates server notifications using Streamable HTTP. + +- Resource list change notifications with dynamically added resources +- Automatic resource creation on a timed interval + +```bash +npx tsx src/examples/server/standaloneSseWithGetStreamableHttp.ts +``` + +##### Form Elicitation Example + +A server that demonstrates using form elicitation to collect _non-sensitive_ user input. + +```bash +npx tsx src/examples/server/elicitationFormExample.ts +``` + +##### URL Elicitation Example + +A comprehensive example demonstrating URL mode elicitation in a server protected by MCP authorization. This example shows: + +- SSE-driven URL elicitation of an API Key on session initialization: obtain sensitive user input at session init +- Tools that require direct user interaction via URL elicitation (for payment confirmation and for third-party OAuth tokens) +- Completion notifications for URL elicitation + +To run this example: + +```bash +# Start the server +npx tsx src/examples/server/elicitationUrlExample.ts + +# In a separate terminal, start the client +npx tsx src/examples/client/elicitationUrlExample.ts +``` + +#### Deprecated SSE Transport + +A server that implements the deprecated HTTP+SSE transport (protocol version 2024-11-05). This example is only used for testing backwards compatibility for clients. + +- Two separate endpoints: `/mcp` for the SSE stream (GET) and `/messages` for client messages (POST) +- Tool implementation with a `start-notification-stream` tool that demonstrates sending periodic notifications + +```bash +npx tsx src/examples/server/simpleSseServer.ts +``` + +#### Streamable Http Backwards Compatible Server with SSE + +A server that supports both Streamable HTTP and SSE transports, adhering to the [MCP specification for backwards compatibility](https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#backwards-compatibility). + +- Single MCP server instance with multiple transport options +- Support for Streamable HTTP requests at `/mcp` endpoint (GET/POST/DELETE) +- Support for deprecated SSE transport with `/sse` (GET) and `/messages` (POST) +- Session type tracking to avoid mixing transport types +- Notifications and tool execution across both transport types + +```bash +npx tsx src/examples/server/sseAndStreamableHttpCompatibleServer.ts +``` + +### Multi-Node Deployment + +When deploying MCP servers in a horizontally scaled environment (multiple server instances), there are a few different options that can be useful for different use cases: + +- **Stateless mode** - No need to maintain state between calls to MCP servers. Useful for simple API wrapper servers. +- **Persistent storage mode** - No local state needed, but session data is stored in a database. Example: an MCP server for online ordering where the shopping cart is stored in a database. +- **Local state with message routing** - Local state is needed, and all requests for a session must be routed to the correct node. This can be done with a message queue and pub/sub system. + +#### Stateless Mode + +The Streamable HTTP transport can be configured to operate without tracking sessions. This is perfect for simple API proxies or when each request is completely independent. + +##### Implementation + +To enable stateless mode, configure the `StreamableHTTPServerTransport` with: + +```typescript +sessionIdGenerator: undefined; +``` + +This disables session management entirely, and the server won't generate or expect session IDs. + +- No session ID headers are sent or expected +- Any server node can process any request +- No state is preserved between requests +- Perfect for RESTful or stateless API scenarios +- Simplest deployment model with minimal infrastructure requirements + +``` +┌─────────────────────────────────────────────┐ +│ Client │ +└─────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────┐ +│ Load Balancer │ +└─────────────────────────────────────────────┘ + │ │ + ▼ ▼ +┌─────────────────┐ ┌─────────────────────┐ +│ MCP Server #1 │ │ MCP Server #2 │ +│ (Node.js) │ │ (Node.js) │ +└─────────────────┘ └─────────────────────┘ +``` + +#### Persistent Storage Mode + +For cases where you need session continuity but don't need to maintain in-memory state on specific nodes, you can use a database to persist session data while still allowing any node to handle requests. + +##### Implementation + +Configure the transport with session management, but retrieve and store all state in an external persistent storage: + +```typescript +sessionIdGenerator: () => randomUUID(), +eventStore: databaseEventStore +``` + +All session state is stored in the database, and any node can serve any client by retrieving the state when needed. + +- Maintains sessions with unique IDs +- Stores all session data in an external database +- Provides resumability through the database-backed EventStore +- Any node can handle any request for the same session +- No node-specific memory state means no need for message routing +- Good for applications where state can be fully externalized +- Somewhat higher latency due to database access for each request + +``` +┌─────────────────────────────────────────────┐ +│ Client │ +└─────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────┐ +│ Load Balancer │ +└─────────────────────────────────────────────┘ + │ │ + ▼ ▼ +┌─────────────────┐ ┌─────────────────────┐ +│ MCP Server #1 │ │ MCP Server #2 │ +│ (Node.js) │ │ (Node.js) │ +└─────────────────┘ └─────────────────────┘ + │ │ + │ │ + ▼ ▼ +┌─────────────────────────────────────────────┐ +│ Database (PostgreSQL) │ +│ │ +│ • Session state │ +│ • Event storage for resumability │ +└─────────────────────────────────────────────┘ +``` + +#### Streamable HTTP with Distributed Message Routing + +For scenarios where local in-memory state must be maintained on specific nodes (such as Computer Use or complex session state), the Streamable HTTP transport can be combined with a pub/sub system to route messages to the correct node handling each session. + +1. **Bidirectional Message Queue Integration**: + - All nodes both publish to and subscribe from the message queue + - Each node registers the sessions it's actively handling + - Messages are routed based on session ownership + +2. **Request Handling Flow**: + - When a client connects to Node A with an existing `mcp-session-id` + - If Node A doesn't own this session, it: + - Establishes and maintains the SSE connection with the client + - Publishes the request to the message queue with the session ID + - Node B (which owns the session) receives the request from the queue + - Node B processes the request with its local session state + - Node B publishes responses/notifications back to the queue + - Node A subscribes to the response channel and forwards to the client + +3. **Channel Identification**: + - Each message channel combines both `mcp-session-id` and `stream-id` + - This ensures responses are correctly routed back to the originating connection + +``` +┌─────────────────────────────────────────────┐ +│ Client │ +└─────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────┐ +│ Load Balancer │ +└─────────────────────────────────────────────┘ + │ │ + ▼ ▼ +┌─────────────────┐ ┌─────────────────────┐ +│ MCP Server #1 │◄───►│ MCP Server #2 │ +│ (Has Session A) │ │ (Has Session B) │ +└─────────────────┘ └─────────────────────┘ + ▲│ ▲│ + │▼ │▼ +┌─────────────────────────────────────────────┐ +│ Message Queue / Pub-Sub │ +│ │ +│ • Session ownership registry │ +│ • Bidirectional message routing │ +│ • Request/response forwarding │ +└─────────────────────────────────────────────┘ +``` + +- Maintains session affinity for stateful operations without client redirection +- Enables horizontal scaling while preserving complex in-memory state +- Provides fault tolerance through the message queue as intermediary + +## Backwards Compatibility + +### Testing Streamable HTTP Backwards Compatibility with SSE + +To test the backwards compatibility features: + +1. Start one of the server implementations: + + ```bash + # Legacy SSE server (protocol version 2024-11-05) + npx tsx src/examples/server/simpleSseServer.ts + + # Streamable HTTP server (protocol version 2025-11-25) + npx tsx src/examples/server/simpleStreamableHttp.ts + + # Backwards compatible server (supports both protocols) + npx tsx src/examples/server/sseAndStreamableHttpCompatibleServer.ts + ``` + +2. Then run the backwards compatible client: + ```bash + npx tsx src/examples/client/streamableHttpWithSseFallbackClient.ts + ``` + +This demonstrates how the MCP ecosystem ensures interoperability between clients and servers regardless of which protocol version they were built for. diff --git a/packages/examples/server/eslint.config.mjs b/packages/examples/server/eslint.config.mjs new file mode 100644 index 000000000..83b79879f --- /dev/null +++ b/packages/examples/server/eslint.config.mjs @@ -0,0 +1,14 @@ +// @ts-check + +import baseConfig from '@modelcontextprotocol/eslint-config'; + +export default [ + ...baseConfig, + { + files: ['src/**/*.{ts,tsx,js,jsx,mts,cts}'], + rules: { + // Allow console statements in examples only + 'no-console': 'off' + } + } +]; diff --git a/packages/examples/server/package.json b/packages/examples/server/package.json new file mode 100644 index 000000000..66811b740 --- /dev/null +++ b/packages/examples/server/package.json @@ -0,0 +1,41 @@ +{ + "name": "@modelcontextprotocol/sdk-examples-server", + "private": true, + "version": "2.0.0-alpha.0", + "description": "Model Context Protocol implementation for TypeScript", + "license": "MIT", + "author": "Anthropic, PBC (https://anthropic.com)", + "homepage": "https://modelcontextprotocol.io", + "bugs": "https://github.com/modelcontextprotocol/typescript-sdk/issues", + "type": "module", + "repository": { + "type": "git", + "url": "git+https://github.com/modelcontextprotocol/typescript-sdk.git" + }, + "engines": { + "node": ">=18" + }, + "keywords": [ + "modelcontextprotocol", + "mcp" + ], + "scripts": { + "typecheck": "tsc -p tsconfig.build.json --noEmit", + "prepack": "npm run build:esm && npm run build:cjs", + "lint": "eslint src/ && prettier --check .", + "lint:fix": "eslint src/ --fix && prettier --write .", + "check": "npm run typecheck && npm run lint", + "start": "npm run server", + "server": "tsx watch --clear-screen=false scripts/cli.ts server", + "client": "tsx scripts/cli.ts client" + }, + "dependencies": { + "@modelcontextprotocol/sdk-server": "workspace:^", + "@modelcontextprotocol/sdk-examples-shared": "workspace:^" + }, + "devDependencies": { + "@modelcontextprotocol/tsconfig": "workspace:^", + "@modelcontextprotocol/eslint-config": "workspace:^", + "@modelcontextprotocol/vitest-config": "workspace:^" + } +} diff --git a/src/examples/server/README-simpleTaskInteractive.md b/packages/examples/server/src/README-simpleTaskInteractive.md similarity index 100% rename from src/examples/server/README-simpleTaskInteractive.md rename to packages/examples/server/src/README-simpleTaskInteractive.md diff --git a/src/examples/server/elicitationFormExample.ts b/packages/examples/server/src/elicitationFormExample.ts similarity index 98% rename from src/examples/server/elicitationFormExample.ts rename to packages/examples/server/src/elicitationFormExample.ts index 6c0800949..81a286e8e 100644 --- a/src/examples/server/elicitationFormExample.ts +++ b/packages/examples/server/src/elicitationFormExample.ts @@ -8,11 +8,9 @@ // to collect *sensitive* user input via a browser. import { randomUUID } from 'node:crypto'; + +import { createMcpExpressApp, isInitializeRequest, McpServer, StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk-server'; import { type Request, type Response } from 'express'; -import { McpServer } from '../../server/mcp.js'; -import { StreamableHTTPServerTransport } from '../../server/streamableHttp.js'; -import { isInitializeRequest } from '../../types.js'; -import { createMcpExpressApp } from '../../server/express.js'; // Create MCP server - it will automatically use AjvJsonSchemaValidator with sensible defaults // The validator supports format validation (email, date, etc.) if ajv-formats is installed @@ -454,7 +452,7 @@ async function main() { for (const sessionId in transports) { try { console.log(`Closing transport for session ${sessionId}`); - await transports[sessionId].close(); + await transports[sessionId]!.close(); delete transports[sessionId]; } catch (error) { console.error(`Error closing transport for session ${sessionId}:`, error); diff --git a/src/examples/server/elicitationUrlExample.ts b/packages/examples/server/src/elicitationUrlExample.ts similarity index 96% rename from src/examples/server/elicitationUrlExample.ts rename to packages/examples/server/src/elicitationUrlExample.ts index 5ddecc4e1..2f5b5da76 100644 --- a/src/examples/server/elicitationUrlExample.ts +++ b/packages/examples/server/src/elicitationUrlExample.ts @@ -7,21 +7,27 @@ // Note: See also elicitationFormExample.ts for an example of using form (not URL) elicitation // to collect *non-sensitive* user input with a structured schema. -import express, { Request, Response } from 'express'; import { randomUUID } from 'node:crypto'; -import { z } from 'zod'; -import { McpServer } from '../../server/mcp.js'; -import { createMcpExpressApp } from '../../server/express.js'; -import { StreamableHTTPServerTransport } from '../../server/streamableHttp.js'; -import { getOAuthProtectedResourceMetadataUrl, mcpAuthMetadataRouter } from '../../server/auth/router.js'; -import { requireBearerAuth } from '../../server/auth/middleware/bearerAuth.js'; -import { CallToolResult, UrlElicitationRequiredError, ElicitRequestURLParams, ElicitResult, isInitializeRequest } from '../../types.js'; -import { InMemoryEventStore } from '../shared/inMemoryEventStore.js'; -import { setupAuthServer } from './demoInMemoryOAuthProvider.js'; -import { OAuthMetadata } from '../../shared/auth.js'; -import { checkResourceAllowed } from '../../shared/auth-utils.js'; +import { setupAuthServer } from '@modelcontextprotocol/sdk-examples-shared'; +import type { CallToolResult, ElicitRequestURLParams, ElicitResult, OAuthMetadata } from '@modelcontextprotocol/sdk-server'; +import { + checkResourceAllowed, + createMcpExpressApp, + getOAuthProtectedResourceMetadataUrl, + isInitializeRequest, + mcpAuthMetadataRouter, + McpServer, + requireBearerAuth, + StreamableHTTPServerTransport, + UrlElicitationRequiredError +} from '@modelcontextprotocol/sdk-server'; import cors from 'cors'; +import type { Request, Response } from 'express'; +import express from 'express'; +import { z } from 'zod'; + +import { InMemoryEventStore } from './inMemoryEventStore.js'; // Create an MCP server with implementation details const getServer = () => { @@ -257,7 +263,7 @@ const tokenVerifier = { throw new Error(`Invalid or expired token: ${text}`); } - const data = await response.json(); + const data = (await response.json()) as { aud: string; client_id: string; scope: string; exp: number }; if (!data.aud) { throw new Error(`Resource Indicator (RFC8707) missing`); @@ -759,7 +765,7 @@ process.on('SIGINT', async () => { for (const sessionId in transports) { try { console.log(`Closing transport for session ${sessionId}`); - await transports[sessionId].close(); + await transports[sessionId]!.close(); delete transports[sessionId]; delete sessionsNeedingElicitation[sessionId]; } catch (error) { diff --git a/src/examples/shared/inMemoryEventStore.ts b/packages/examples/server/src/inMemoryEventStore.ts similarity index 93% rename from src/examples/shared/inMemoryEventStore.ts rename to packages/examples/server/src/inMemoryEventStore.ts index d4d02eb91..7af31c6f8 100644 --- a/src/examples/shared/inMemoryEventStore.ts +++ b/packages/examples/server/src/inMemoryEventStore.ts @@ -1,5 +1,4 @@ -import { JSONRPCMessage } from '../../types.js'; -import { EventStore } from '../../server/streamableHttp.js'; +import type { EventStore, JSONRPCMessage } from '@modelcontextprotocol/sdk-server'; /** * Simple in-memory implementation of the EventStore interface for resumability @@ -21,7 +20,7 @@ export class InMemoryEventStore implements EventStore { */ private getStreamIdFromEventId(eventId: string): string { const parts = eventId.split('_'); - return parts.length > 0 ? parts[0] : ''; + return parts.length > 0 ? parts[0]! : ''; } /** diff --git a/src/examples/server/jsonResponseStreamableHttp.ts b/packages/examples/server/src/jsonResponseStreamableHttp.ts similarity index 94% rename from src/examples/server/jsonResponseStreamableHttp.ts rename to packages/examples/server/src/jsonResponseStreamableHttp.ts index a066c9bf8..994f4fa05 100644 --- a/src/examples/server/jsonResponseStreamableHttp.ts +++ b/packages/examples/server/src/jsonResponseStreamableHttp.ts @@ -1,10 +1,9 @@ -import { Request, Response } from 'express'; import { randomUUID } from 'node:crypto'; -import { McpServer } from '../../server/mcp.js'; -import { StreamableHTTPServerTransport } from '../../server/streamableHttp.js'; + +import type { CallToolResult } from '@modelcontextprotocol/sdk-server'; +import { createMcpExpressApp, isInitializeRequest, McpServer, StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk-server'; +import type { Request, Response } from 'express'; import * as z from 'zod/v4'; -import { CallToolResult, isInitializeRequest } from '../../types.js'; -import { createMcpExpressApp } from '../../server/express.js'; // Create an MCP server with implementation details const getServer = () => { diff --git a/src/examples/server/mcpServerOutputSchema.ts b/packages/examples/server/src/mcpServerOutputSchema.ts similarity index 95% rename from src/examples/server/mcpServerOutputSchema.ts rename to packages/examples/server/src/mcpServerOutputSchema.ts index 7ef9f6227..076a22c4f 100644 --- a/src/examples/server/mcpServerOutputSchema.ts +++ b/packages/examples/server/src/mcpServerOutputSchema.ts @@ -4,8 +4,7 @@ * This demonstrates how to easily create tools with structured output */ -import { McpServer } from '../../server/mcp.js'; -import { StdioServerTransport } from '../../server/stdio.js'; +import { McpServer, StdioServerTransport } from '@modelcontextprotocol/sdk-server'; import * as z from 'zod/v4'; const server = new McpServer({ diff --git a/src/examples/server/simpleSseServer.ts b/packages/examples/server/src/simpleSseServer.ts similarity index 94% rename from src/examples/server/simpleSseServer.ts rename to packages/examples/server/src/simpleSseServer.ts index 64d6b0f81..ae381985c 100644 --- a/src/examples/server/simpleSseServer.ts +++ b/packages/examples/server/src/simpleSseServer.ts @@ -1,9 +1,7 @@ -import { Request, Response } from 'express'; -import { McpServer } from '../../server/mcp.js'; -import { SSEServerTransport } from '../../server/sse.js'; +import type { CallToolResult } from '@modelcontextprotocol/sdk-server'; +import { createMcpExpressApp, McpServer, SSEServerTransport } from '@modelcontextprotocol/sdk-server'; +import type { Request, Response } from 'express'; import * as z from 'zod/v4'; -import { CallToolResult } from '../../types.js'; -import { createMcpExpressApp } from '../../server/express.js'; /** * This example server demonstrates the deprecated HTTP+SSE transport @@ -165,7 +163,7 @@ process.on('SIGINT', async () => { for (const sessionId in transports) { try { console.log(`Closing transport for session ${sessionId}`); - await transports[sessionId].close(); + await transports[sessionId]!.close(); delete transports[sessionId]; } catch (error) { console.error(`Error closing transport for session ${sessionId}:`, error); diff --git a/src/examples/server/simpleStatelessStreamableHttp.ts b/packages/examples/server/src/simpleStatelessStreamableHttp.ts similarity index 94% rename from src/examples/server/simpleStatelessStreamableHttp.ts rename to packages/examples/server/src/simpleStatelessStreamableHttp.ts index 48ca98dc8..1cec427fd 100644 --- a/src/examples/server/simpleStatelessStreamableHttp.ts +++ b/packages/examples/server/src/simpleStatelessStreamableHttp.ts @@ -1,9 +1,7 @@ -import { Request, Response } from 'express'; -import { McpServer } from '../../server/mcp.js'; -import { StreamableHTTPServerTransport } from '../../server/streamableHttp.js'; +import type { CallToolResult, GetPromptResult, ReadResourceResult } from '@modelcontextprotocol/sdk-server'; +import { createMcpExpressApp, McpServer, StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk-server'; +import type { Request, Response } from 'express'; import * as z from 'zod/v4'; -import { CallToolResult, GetPromptResult, ReadResourceResult } from '../../types.js'; -import { createMcpExpressApp } from '../../server/express.js'; const getServer = () => { // Create an MCP server with implementation details diff --git a/src/examples/server/simpleStreamableHttp.ts b/packages/examples/server/src/simpleStreamableHttp.ts similarity index 96% rename from src/examples/server/simpleStreamableHttp.ts rename to packages/examples/server/src/simpleStreamableHttp.ts index e3b754fa6..72382501c 100644 --- a/src/examples/server/simpleStreamableHttp.ts +++ b/packages/examples/server/src/simpleStreamableHttp.ts @@ -1,25 +1,31 @@ -import { Request, Response } from 'express'; import { randomUUID } from 'node:crypto'; -import * as z from 'zod/v4'; -import { McpServer } from '../../server/mcp.js'; -import { StreamableHTTPServerTransport } from '../../server/streamableHttp.js'; -import { getOAuthProtectedResourceMetadataUrl, mcpAuthMetadataRouter } from '../../server/auth/router.js'; -import { requireBearerAuth } from '../../server/auth/middleware/bearerAuth.js'; -import { createMcpExpressApp } from '../../server/express.js'; -import { + +import { setupAuthServer } from '@modelcontextprotocol/sdk-examples-shared'; +import type { CallToolResult, - ElicitResultSchema, GetPromptResult, - isInitializeRequest, + OAuthMetadata, PrimitiveSchemaDefinition, ReadResourceResult, ResourceLink -} from '../../types.js'; -import { InMemoryEventStore } from '../shared/inMemoryEventStore.js'; -import { InMemoryTaskStore, InMemoryTaskMessageQueue } from '../../experimental/tasks/stores/in-memory.js'; -import { setupAuthServer } from './demoInMemoryOAuthProvider.js'; -import { OAuthMetadata } from '../../shared/auth.js'; -import { checkResourceAllowed } from '../../shared/auth-utils.js'; +} from '@modelcontextprotocol/sdk-server'; +import { + checkResourceAllowed, + createMcpExpressApp, + ElicitResultSchema, + getOAuthProtectedResourceMetadataUrl, + InMemoryTaskMessageQueue, + InMemoryTaskStore, + isInitializeRequest, + mcpAuthMetadataRouter, + McpServer, + requireBearerAuth, + StreamableHTTPServerTransport +} from '@modelcontextprotocol/sdk-server'; +import type { Request, Response } from 'express'; +import * as z from 'zod/v4'; + +import { InMemoryEventStore } from './inMemoryEventStore.js'; // Check for OAuth flag const useOAuth = process.argv.includes('--oauth'); @@ -546,7 +552,7 @@ if (useOAuth) { throw new Error(`Invalid or expired token: ${text}`); } - const data = await response.json(); + const data = (await response.json()) as { aud: string; client_id: string; scope: string; exp: number }; if (strictOAuth) { if (!data.aud) { @@ -746,7 +752,7 @@ process.on('SIGINT', async () => { for (const sessionId in transports) { try { console.log(`Closing transport for session ${sessionId}`); - await transports[sessionId].close(); + await transports[sessionId]!.close(); delete transports[sessionId]; } catch (error) { console.error(`Error closing transport for session ${sessionId}:`, error); diff --git a/src/examples/server/simpleTaskInteractive.ts b/packages/examples/server/src/simpleTaskInteractive.ts similarity index 96% rename from src/examples/server/simpleTaskInteractive.ts rename to packages/examples/server/src/simpleTaskInteractive.ts index db0a4b579..ff1105fac 100644 --- a/src/examples/server/simpleTaskInteractive.ts +++ b/packages/examples/server/src/simpleTaskInteractive.ts @@ -9,36 +9,43 @@ * creates a task, and the result is fetched via tasks/result endpoint. */ -import { Request, Response } from 'express'; import { randomUUID } from 'node:crypto'; -import { Server } from '../../server/index.js'; -import { createMcpExpressApp } from '../../server/express.js'; -import { StreamableHTTPServerTransport } from '../../server/streamableHttp.js'; -import { + +import type { CallToolResult, + CreateMessageRequest, + CreateMessageResult, + CreateTaskOptions, CreateTaskResult, - GetTaskResult, - Tool, - TextContent, - RELATED_TASK_META_KEY, - Task, - Result, - RequestId, - JSONRPCRequest, - SamplingMessage, ElicitRequestFormParams, - CreateMessageRequest, ElicitResult, - CreateMessageResult, + GetTaskPayloadResult, + GetTaskResult, + JSONRPCRequest, PrimitiveSchemaDefinition, - ListToolsRequestSchema, + QueuedMessage, + QueuedRequest, + RequestId, + Result, + SamplingMessage, + Task, + TaskMessageQueue, + TextContent, + Tool +} from '@modelcontextprotocol/sdk-server'; +import { CallToolRequestSchema, - GetTaskRequestSchema, + createMcpExpressApp, GetTaskPayloadRequestSchema, - GetTaskPayloadResult -} from '../../types.js'; -import { TaskMessageQueue, QueuedMessage, QueuedRequest, isTerminal, CreateTaskOptions } from '../../experimental/tasks/interfaces.js'; -import { InMemoryTaskStore } from '../../experimental/tasks/stores/in-memory.js'; + GetTaskRequestSchema, + InMemoryTaskStore, + isTerminal, + ListToolsRequestSchema, + RELATED_TASK_META_KEY, + Server, + StreamableHTTPServerTransport +} from '@modelcontextprotocol/sdk-server'; +import type { Request, Response } from 'express'; // ============================================================================ // Resolver - Promise-like for passing results between async operations @@ -180,12 +187,12 @@ class TaskMessageQueueWithResolvers implements TaskMessageQueue { class TaskStoreWithNotifications extends InMemoryTaskStore { private updateResolvers = new Map void)[]>(); - async updateTaskStatus(taskId: string, status: Task['status'], statusMessage?: string, sessionId?: string): Promise { + override async updateTaskStatus(taskId: string, status: Task['status'], statusMessage?: string, sessionId?: string): Promise { await super.updateTaskStatus(taskId, status, statusMessage, sessionId); this.notifyUpdate(taskId); } - async storeTaskResult(taskId: string, status: 'completed' | 'failed', result: Result, sessionId?: string): Promise { + override async storeTaskResult(taskId: string, status: 'completed' | 'failed', result: Result, sessionId?: string): Promise { await super.storeTaskResult(taskId, status, result, sessionId); this.notifyUpdate(taskId); } @@ -732,7 +739,7 @@ process.on('SIGINT', async () => { console.log('\nShutting down server...'); for (const sessionId of Object.keys(transports)) { try { - await transports[sessionId].close(); + await transports[sessionId]!.close(); delete transports[sessionId]; } catch (error) { console.error(`Error closing session ${sessionId}:`, error); diff --git a/src/examples/server/sseAndStreamableHttpCompatibleServer.ts b/packages/examples/server/src/sseAndStreamableHttpCompatibleServer.ts similarity index 94% rename from src/examples/server/sseAndStreamableHttpCompatibleServer.ts rename to packages/examples/server/src/sseAndStreamableHttpCompatibleServer.ts index 99ba9022d..7943faba3 100644 --- a/src/examples/server/sseAndStreamableHttpCompatibleServer.ts +++ b/packages/examples/server/src/sseAndStreamableHttpCompatibleServer.ts @@ -1,12 +1,17 @@ -import { Request, Response } from 'express'; import { randomUUID } from 'node:crypto'; -import { McpServer } from '../../server/mcp.js'; -import { StreamableHTTPServerTransport } from '../../server/streamableHttp.js'; -import { SSEServerTransport } from '../../server/sse.js'; + +import type { CallToolResult } from '@modelcontextprotocol/sdk-server'; +import { + createMcpExpressApp, + isInitializeRequest, + McpServer, + SSEServerTransport, + StreamableHTTPServerTransport +} from '@modelcontextprotocol/sdk-server'; +import type { Request, Response } from 'express'; import * as z from 'zod/v4'; -import { CallToolResult, isInitializeRequest } from '../../types.js'; -import { InMemoryEventStore } from '../shared/inMemoryEventStore.js'; -import { createMcpExpressApp } from '../../server/express.js'; + +import { InMemoryEventStore } from './inMemoryEventStore.js'; /** * This example server demonstrates backwards compatibility with both: @@ -242,7 +247,7 @@ process.on('SIGINT', async () => { for (const sessionId in transports) { try { console.log(`Closing transport for session ${sessionId}`); - await transports[sessionId].close(); + await transports[sessionId]!.close(); delete transports[sessionId]; } catch (error) { console.error(`Error closing transport for session ${sessionId}:`, error); diff --git a/src/examples/server/ssePollingExample.ts b/packages/examples/server/src/ssePollingExample.ts similarity index 93% rename from src/examples/server/ssePollingExample.ts rename to packages/examples/server/src/ssePollingExample.ts index bbecf2fdb..0c7e02a78 100644 --- a/src/examples/server/ssePollingExample.ts +++ b/packages/examples/server/src/ssePollingExample.ts @@ -12,14 +12,14 @@ * Run with: npx tsx src/examples/server/ssePollingExample.ts * Test with: curl or the MCP Inspector */ -import { Request, Response } from 'express'; import { randomUUID } from 'node:crypto'; -import { McpServer } from '../../server/mcp.js'; -import { createMcpExpressApp } from '../../server/express.js'; -import { StreamableHTTPServerTransport } from '../../server/streamableHttp.js'; -import { CallToolResult } from '../../types.js'; -import { InMemoryEventStore } from '../shared/inMemoryEventStore.js'; + +import type { CallToolResult } from '@modelcontextprotocol/sdk-server'; +import { createMcpExpressApp, McpServer, StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk-server'; import cors from 'cors'; +import type { Request, Response } from 'express'; + +import { InMemoryEventStore } from './inMemoryEventStore.js'; // Create the MCP server const server = new McpServer( diff --git a/src/examples/server/standaloneSseWithGetStreamableHttp.ts b/packages/examples/server/src/standaloneSseWithGetStreamableHttp.ts similarity index 93% rename from src/examples/server/standaloneSseWithGetStreamableHttp.ts rename to packages/examples/server/src/standaloneSseWithGetStreamableHttp.ts index 225ef1f34..0f3f7bcb1 100644 --- a/src/examples/server/standaloneSseWithGetStreamableHttp.ts +++ b/packages/examples/server/src/standaloneSseWithGetStreamableHttp.ts @@ -1,9 +1,8 @@ -import { Request, Response } from 'express'; import { randomUUID } from 'node:crypto'; -import { McpServer } from '../../server/mcp.js'; -import { StreamableHTTPServerTransport } from '../../server/streamableHttp.js'; -import { isInitializeRequest, ReadResourceResult } from '../../types.js'; -import { createMcpExpressApp } from '../../server/express.js'; + +import type { ReadResourceResult } from '@modelcontextprotocol/sdk-server'; +import { createMcpExpressApp, isInitializeRequest, McpServer, StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk-server'; +import type { Request, Response } from 'express'; // Create an MCP server with implementation details const server = new McpServer({ diff --git a/src/examples/server/toolWithSampleServer.ts b/packages/examples/server/src/toolWithSampleServer.ts similarity index 93% rename from src/examples/server/toolWithSampleServer.ts rename to packages/examples/server/src/toolWithSampleServer.ts index e6d733598..4b592f4b3 100644 --- a/src/examples/server/toolWithSampleServer.ts +++ b/packages/examples/server/src/toolWithSampleServer.ts @@ -1,7 +1,6 @@ // Run with: npx tsx src/examples/server/toolWithSampleServer.ts -import { McpServer } from '../../server/mcp.js'; -import { StdioServerTransport } from '../../server/stdio.js'; +import { McpServer, StdioServerTransport } from '@modelcontextprotocol/sdk-server'; import * as z from 'zod/v4'; const mcpServer = new McpServer({ diff --git a/packages/examples/server/tsconfig.build.json b/packages/examples/server/tsconfig.build.json new file mode 100644 index 000000000..eabb8d8ff --- /dev/null +++ b/packages/examples/server/tsconfig.build.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "./dist", + "rootDir": "./src" + }, + "include": ["./"], + "exclude": ["dist", "node_modules", "test"] +} diff --git a/packages/examples/server/tsconfig.json b/packages/examples/server/tsconfig.json new file mode 100644 index 000000000..95df1a35a --- /dev/null +++ b/packages/examples/server/tsconfig.json @@ -0,0 +1,18 @@ +{ + "extends": "@modelcontextprotocol/tsconfig", + "include": ["./", "../shared/src/demoInMemoryOAuthProvider.ts"], + "exclude": ["node_modules", "dist"], + "compilerOptions": { + "baseUrl": ".", + "paths": { + "*": ["./*"], + "@modelcontextprotocol/sdk-server": ["node_modules/@modelcontextprotocol/sdk-server/src/index.ts"], + "@modelcontextprotocol/sdk-core": [ + "node_modules/@modelcontextprotocol/sdk-server/node_modules/@modelcontextprotocol/sdk-core/src/index.ts" + ], + "@modelcontextprotocol/sdk-examples-shared": ["node_modules/@modelcontextprotocol/sdk-examples-shared/src/index.ts"], + "@modelcontextprotocol/eslint-config": ["node_modules/@modelcontextprotocol/eslint-config/tsconfig.json"], + "@modelcontextprotocol/vitest-config": ["node_modules/@modelcontextprotocol/vitest-config/tsconfig.json"] + } + } +} diff --git a/packages/examples/server/vitest.config.js b/packages/examples/server/vitest.config.js new file mode 100644 index 000000000..496fca320 --- /dev/null +++ b/packages/examples/server/vitest.config.js @@ -0,0 +1,3 @@ +import baseConfig from '@modelcontextprotocol/vitest-config'; + +export default baseConfig; diff --git a/packages/examples/shared/eslint.config.mjs b/packages/examples/shared/eslint.config.mjs new file mode 100644 index 000000000..83b79879f --- /dev/null +++ b/packages/examples/shared/eslint.config.mjs @@ -0,0 +1,14 @@ +// @ts-check + +import baseConfig from '@modelcontextprotocol/eslint-config'; + +export default [ + ...baseConfig, + { + files: ['src/**/*.{ts,tsx,js,jsx,mts,cts}'], + rules: { + // Allow console statements in examples only + 'no-console': 'off' + } + } +]; diff --git a/packages/examples/shared/package.json b/packages/examples/shared/package.json new file mode 100644 index 000000000..3295f70c5 --- /dev/null +++ b/packages/examples/shared/package.json @@ -0,0 +1,42 @@ +{ + "name": "@modelcontextprotocol/sdk-examples-shared", + "private": true, + "version": "2.0.0-alpha.0", + "description": "Model Context Protocol implementation for TypeScript", + "license": "MIT", + "author": "Anthropic, PBC (https://anthropic.com)", + "homepage": "https://modelcontextprotocol.io", + "bugs": "https://github.com/modelcontextprotocol/typescript-sdk/issues", + "type": "module", + "repository": { + "type": "git", + "url": "git+https://github.com/modelcontextprotocol/typescript-sdk.git" + }, + "engines": { + "node": ">=18" + }, + "keywords": [ + "modelcontextprotocol", + "mcp" + ], + "scripts": { + "typecheck": "tsc -p tsconfig.build.json --noEmit", + "prepack": "npm run build:esm && npm run build:cjs", + "lint": "eslint src/ && prettier --check .", + "lint:fix": "eslint src/ --fix && prettier --write .", + "check": "npm run typecheck && npm run lint", + "test": "vitest run", + "test:watch": "vitest", + "start": "npm run server", + "server": "tsx watch --clear-screen=false scripts/cli.ts server", + "client": "tsx scripts/cli.ts client" + }, + "dependencies": { + "@modelcontextprotocol/sdk-server": "workspace:^" + }, + "devDependencies": { + "@modelcontextprotocol/tsconfig": "workspace:^", + "@modelcontextprotocol/eslint-config": "workspace:^", + "@modelcontextprotocol/vitest-config": "workspace:^" + } +} diff --git a/src/examples/server/demoInMemoryOAuthProvider.ts b/packages/examples/shared/src/demoInMemoryOAuthProvider.ts similarity index 93% rename from src/examples/server/demoInMemoryOAuthProvider.ts rename to packages/examples/shared/src/demoInMemoryOAuthProvider.ts index 1abc040ce..e4f94dc28 100644 --- a/src/examples/server/demoInMemoryOAuthProvider.ts +++ b/packages/examples/shared/src/demoInMemoryOAuthProvider.ts @@ -1,12 +1,17 @@ import { randomUUID } from 'node:crypto'; -import { AuthorizationParams, OAuthServerProvider } from '../../server/auth/provider.js'; -import { OAuthRegisteredClientsStore } from '../../server/auth/clients.js'; -import { OAuthClientInformationFull, OAuthMetadata, OAuthTokens } from '../../shared/auth.js'; -import express, { Request, Response } from 'express'; -import { AuthInfo } from '../../server/auth/types.js'; -import { createOAuthMetadata, mcpAuthRouter } from '../../server/auth/router.js'; -import { resourceUrlFromServerUrl } from '../../shared/auth-utils.js'; -import { InvalidRequestError } from '../../server/auth/errors.js'; + +import type { + AuthInfo, + AuthorizationParams, + OAuthClientInformationFull, + OAuthMetadata, + OAuthRegisteredClientsStore, + OAuthServerProvider, + OAuthTokens +} from '@modelcontextprotocol/sdk-server'; +import { createOAuthMetadata, InvalidRequestError, mcpAuthRouter, resourceUrlFromServerUrl } from '@modelcontextprotocol/sdk-server'; +import type { Request, Response } from 'express'; +import express from 'express'; export class DemoInMemoryClientsStore implements OAuthRegisteredClientsStore { private clients = new Map(); diff --git a/packages/examples/shared/src/index.ts b/packages/examples/shared/src/index.ts new file mode 100644 index 000000000..1c31cf06e --- /dev/null +++ b/packages/examples/shared/src/index.ts @@ -0,0 +1 @@ +export * from './demoInMemoryOAuthProvider.js'; diff --git a/test/examples/server/demoInMemoryOAuthProvider.test.ts b/packages/examples/shared/test/demoInMemoryOAuthProvider.test.ts similarity index 96% rename from test/examples/server/demoInMemoryOAuthProvider.test.ts rename to packages/examples/shared/test/demoInMemoryOAuthProvider.test.ts index a49a8b426..90710af04 100644 --- a/test/examples/server/demoInMemoryOAuthProvider.test.ts +++ b/packages/examples/shared/test/demoInMemoryOAuthProvider.test.ts @@ -1,10 +1,10 @@ -import { Response } from 'express'; -import { DemoInMemoryAuthProvider, DemoInMemoryClientsStore } from '../../../src/examples/server/demoInMemoryOAuthProvider.js'; -import { AuthorizationParams } from '../../../src/server/auth/provider.js'; -import { OAuthClientInformationFull } from '../../../src/shared/auth.js'; -import { InvalidRequestError } from '../../../src/server/auth/errors.js'; +import type { Response } from 'express'; +import { DemoInMemoryAuthProvider, DemoInMemoryClientsStore } from '../src/demoInMemoryOAuthProvider.js'; +import type { AuthorizationParams } from '@modelcontextprotocol/sdk-server'; +import type { OAuthClientInformationFull } from '@modelcontextprotocol/sdk-core'; +import { InvalidRequestError } from '@modelcontextprotocol/sdk-core'; -import { createExpressResponseMock } from '../../helpers/http.js'; +import { createExpressResponseMock } from '../../../integration/test/helpers/http.js'; describe('DemoInMemoryAuthProvider', () => { let provider: DemoInMemoryAuthProvider; diff --git a/packages/examples/shared/tsconfig.build.json b/packages/examples/shared/tsconfig.build.json new file mode 100644 index 000000000..eabb8d8ff --- /dev/null +++ b/packages/examples/shared/tsconfig.build.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "./dist", + "rootDir": "./src" + }, + "include": ["./"], + "exclude": ["dist", "node_modules", "test"] +} diff --git a/packages/examples/shared/tsconfig.json b/packages/examples/shared/tsconfig.json new file mode 100644 index 000000000..804705d8b --- /dev/null +++ b/packages/examples/shared/tsconfig.json @@ -0,0 +1,17 @@ +{ + "extends": "@modelcontextprotocol/tsconfig", + "include": ["./"], + "exclude": ["node_modules", "dist"], + "compilerOptions": { + "baseUrl": ".", + "paths": { + "*": ["./*"], + "@modelcontextprotocol/sdk-server": ["node_modules/@modelcontextprotocol/sdk-server/src/index.ts"], + "@modelcontextprotocol/sdk-core": [ + "node_modules/@modelcontextprotocol/sdk-server/node_modules/@modelcontextprotocol/sdk-core/src/index.ts" + ], + "@modelcontextprotocol/eslint-config": ["node_modules/@modelcontextprotocol/eslint-config/tsconfig.json"], + "@modelcontextprotocol/vitest-config": ["node_modules/@modelcontextprotocol/vitest-config/tsconfig.json"] + } + } +} diff --git a/packages/examples/shared/vitest.config.js b/packages/examples/shared/vitest.config.js new file mode 100644 index 000000000..496fca320 --- /dev/null +++ b/packages/examples/shared/vitest.config.js @@ -0,0 +1,3 @@ +import baseConfig from '@modelcontextprotocol/vitest-config'; + +export default baseConfig; diff --git a/packages/integration/eslint.config.mjs b/packages/integration/eslint.config.mjs new file mode 100644 index 000000000..951c9f3a9 --- /dev/null +++ b/packages/integration/eslint.config.mjs @@ -0,0 +1,5 @@ +// @ts-check + +import baseConfig from '@modelcontextprotocol/eslint-config'; + +export default baseConfig; diff --git a/packages/integration/package.json b/packages/integration/package.json new file mode 100644 index 000000000..fd584d581 --- /dev/null +++ b/packages/integration/package.json @@ -0,0 +1,59 @@ +{ + "name": "@modelcontextprotocol/integration-tests", + "private": true, + "version": "2.0.0-alpha.0", + "description": "Model Context Protocol implementation for TypeScript", + "license": "MIT", + "author": "Anthropic, PBC (https://anthropic.com)", + "homepage": "https://modelcontextprotocol.io", + "bugs": "https://github.com/modelcontextprotocol/typescript-sdk/issues", + "type": "module", + "repository": { + "type": "git", + "url": "git+https://github.com/modelcontextprotocol/typescript-sdk.git" + }, + "engines": { + "node": ">=18" + }, + "keywords": [ + "modelcontextprotocol", + "mcp" + ], + "exports": { + ".": { + "import": "./dist/index.js" + }, + "./types": { + "import": "./dist/exports/types/index.js" + } + }, + "typesVersions": { + "*": { + "*": [ + "./dist/*" + ] + } + }, + "files": [ + "dist" + ], + "scripts": { + "fetch:spec-types": "tsx scripts/fetch-spec-types.ts", + "lint": "eslint test/ && prettier --check .", + "lint:fix": "eslint test/ --fix && prettier --write .", + "check": "npm run typecheck && npm run lint", + "test": "vitest run", + "test:watch": "vitest", + "start": "npm run server", + "server": "tsx watch --clear-screen=false scripts/cli.ts server", + "client": "tsx scripts/cli.ts client" + }, + "devDependencies": { + "@modelcontextprotocol/sdk-core": "workspace:^", + "@modelcontextprotocol/sdk-client": "workspace:^", + "@modelcontextprotocol/sdk-server": "workspace:^", + "@modelcontextprotocol/tsconfig": "workspace:^", + "@modelcontextprotocol/vitest-config": "workspace:^", + "@modelcontextprotocol/eslint-config": "workspace:^" + } +} diff --git a/src/__fixtures__/serverThatHangs.ts b/packages/integration/test/__fixtures__/serverThatHangs.ts similarity index 90% rename from src/__fixtures__/serverThatHangs.ts rename to packages/integration/test/__fixtures__/serverThatHangs.ts index 82c244aa2..2780ca557 100644 --- a/src/__fixtures__/serverThatHangs.ts +++ b/packages/integration/test/__fixtures__/serverThatHangs.ts @@ -1,7 +1,7 @@ -import { setInterval } from 'node:timers'; import process from 'node:process'; -import { McpServer } from '../server/mcp.js'; -import { StdioServerTransport } from '../server/stdio.js'; +import { setInterval } from 'node:timers'; + +import { McpServer, StdioServerTransport } from '@modelcontextprotocol/sdk-server'; const transport = new StdioServerTransport(); diff --git a/src/__fixtures__/testServer.ts b/packages/integration/test/__fixtures__/testServer.ts similarity index 74% rename from src/__fixtures__/testServer.ts rename to packages/integration/test/__fixtures__/testServer.ts index 6401d0f83..6d3164744 100644 --- a/src/__fixtures__/testServer.ts +++ b/packages/integration/test/__fixtures__/testServer.ts @@ -1,5 +1,4 @@ -import { McpServer } from '../server/mcp.js'; -import { StdioServerTransport } from '../server/stdio.js'; +import { McpServer, StdioServerTransport } from '@modelcontextprotocol/sdk-server'; const transport = new StdioServerTransport(); diff --git a/src/__fixtures__/zodTestMatrix.ts b/packages/integration/test/__fixtures__/zodTestMatrix.ts similarity index 100% rename from src/__fixtures__/zodTestMatrix.ts rename to packages/integration/test/__fixtures__/zodTestMatrix.ts diff --git a/test/client/index.test.ts b/packages/integration/test/client/client.test.ts similarity index 97% rename from test/client/index.test.ts rename to packages/integration/test/client/client.test.ts index 9735eb2ba..d0762ce12 100644 --- a/test/client/index.test.ts +++ b/packages/integration/test/client/client.test.ts @@ -1,36 +1,31 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ /* eslint-disable no-constant-binary-expression */ /* eslint-disable @typescript-eslint/no-unused-expressions */ -import { Client, getSupportedElicitationModes } from '../../src/client/index.js'; +import { Client, getSupportedElicitationModes } from '@modelcontextprotocol/sdk-client'; +import type { Prompt, Resource, Tool, Transport } from '@modelcontextprotocol/sdk-core'; import { - RequestSchema, - NotificationSchema, - ResultSchema, - LATEST_PROTOCOL_VERSION, - SUPPORTED_PROTOCOL_VERSIONS, - InitializeRequestSchema, - ListResourcesRequestSchema, - ListToolsRequestSchema, - ListToolsResultSchema, - ListPromptsRequestSchema, CallToolRequestSchema, CallToolResultSchema, CreateMessageRequestSchema, + CreateTaskResultSchema, ElicitRequestSchema, ElicitResultSchema, - ListRootsRequestSchema, ErrorCode, + InitializeRequestSchema, + InMemoryTransport, + LATEST_PROTOCOL_VERSION, + ListPromptsRequestSchema, + ListResourcesRequestSchema, + ListRootsRequestSchema, + ListToolsRequestSchema, + ListToolsResultSchema, McpError, - CreateTaskResultSchema, - Tool, - Prompt, - Resource -} from '../../src/types.js'; -import { Transport } from '../../src/shared/transport.js'; -import { Server } from '../../src/server/index.js'; -import { McpServer } from '../../src/server/mcp.js'; -import { InMemoryTransport } from '../../src/inMemory.js'; -import { InMemoryTaskStore } from '../../src/experimental/tasks/stores/in-memory.js'; + NotificationSchema, + RequestSchema, + ResultSchema, + SUPPORTED_PROTOCOL_VERSIONS +} from '@modelcontextprotocol/sdk-core'; +import { InMemoryTaskStore, McpServer, Server } from '@modelcontextprotocol/sdk-server'; import * as z3 from 'zod/v3'; import * as z4 from 'zod/v4'; @@ -1292,9 +1287,9 @@ test('should handle tool list changed notification with auto refresh', async () // Should be 1 notification with 2 tools because autoRefresh is true expect(notifications).toHaveLength(1); - expect(notifications[0][0]).toBeNull(); - expect(notifications[0][1]).toHaveLength(2); - expect(notifications[0][1]?.[1].name).toBe('test-tool'); + expect(notifications[0]![0]).toBeNull(); + expect(notifications[0]![1]).toHaveLength(2); + expect(notifications[0]![1]?.[1]!.name).toBe('test-tool'); }); /*** @@ -1352,8 +1347,8 @@ test('should handle tool list changed notification with manual refresh', async ( // Should be 1 notification with no tool data because autoRefresh is false expect(notifications).toHaveLength(1); - expect(notifications[0][0]).toBeNull(); - expect(notifications[0][1]).toBeNull(); + expect(notifications[0]![0]).toBeNull(); + expect(notifications[0]![1]).toBeNull(); }); /*** @@ -1412,9 +1407,9 @@ test('should handle prompt list changed notification with auto refresh', async ( // Should be 1 notification with 2 prompts because autoRefresh is true expect(notifications).toHaveLength(1); - expect(notifications[0][0]).toBeNull(); - expect(notifications[0][1]).toHaveLength(2); - expect(notifications[0][1]?.[1].name).toBe('test-prompt'); + expect(notifications[0]![0]).toBeNull(); + expect(notifications[0]![1]).toHaveLength(2); + expect(notifications[0]![1]?.[1]!.name).toBe('test-prompt'); }); /*** @@ -1467,9 +1462,9 @@ test('should handle resource list changed notification with auto refresh', async // Should be 1 notification with 2 resources because autoRefresh is true expect(notifications).toHaveLength(1); - expect(notifications[0][0]).toBeNull(); - expect(notifications[0][1]).toHaveLength(2); - expect(notifications[0][1]?.[1].name).toBe('test-resource'); + expect(notifications[0]![0]).toBeNull(); + expect(notifications[0]![1]).toHaveLength(2); + expect(notifications[0]![1]?.[1]!.name).toBe('test-resource'); }); /*** @@ -1553,10 +1548,10 @@ test('should handle multiple list changed handlers configured together', async ( // Both handlers should have received their respective notifications expect(toolNotifications).toHaveLength(1); - expect(toolNotifications[0][1]).toHaveLength(2); + expect(toolNotifications[0]![1]).toHaveLength(2); expect(promptNotifications).toHaveLength(1); - expect(promptNotifications[0][1]).toHaveLength(2); + expect(promptNotifications[0]![1]).toHaveLength(2); }); /*** @@ -1655,8 +1650,8 @@ test('should activate listChanged handler when server advertises capability', as // Handler SHOULD have been called expect(notifications).toHaveLength(1); - expect(notifications[0][0]).toBeNull(); - expect(notifications[0][1]).toHaveLength(1); + expect(notifications[0]![0]).toBeNull(); + expect(notifications[0]![1]).toHaveLength(1); }); /*** @@ -2419,7 +2414,7 @@ describe('Task-based execution', () => { // Verify task was created successfully by listing tasks const taskList = await client.experimental.tasks.listTasks(); expect(taskList.tasks.length).toBeGreaterThan(0); - const task = taskList.tasks[0]; + const task = taskList.tasks[0]!; expect(task.status).toBe('completed'); }); @@ -2493,7 +2488,7 @@ describe('Task-based execution', () => { // Query task status by listing tasks and getting the first one const taskList = await client.experimental.tasks.listTasks(); expect(taskList.tasks.length).toBeGreaterThan(0); - const task = taskList.tasks[0]; + const task = taskList.tasks[0]!; expect(task).toBeDefined(); expect(task.taskId).toBeDefined(); expect(task.status).toBe('completed'); @@ -3492,9 +3487,9 @@ test('should expose requestStream() method for streaming responses', async () => // Should have received only a result message (no task messages) expect(messages.length).toBe(1); - expect(messages[0].type).toBe('result'); - if (messages[0].type === 'result') { - expect(messages[0].result.content).toEqual([{ type: 'text', text: 'Tool result' }]); + expect(messages[0]!.type).toBe('result'); + if (messages[0]!.type === 'result') { + expect(messages[0]!.result.content).toEqual([{ type: 'text', text: 'Tool result' }]); } await client.close(); @@ -3547,9 +3542,9 @@ test('should expose callToolStream() method for streaming tool calls', async () // Should have received messages ending with result expect(messages.length).toBe(1); - expect(messages[0].type).toBe('result'); - if (messages[0].type === 'result') { - expect(messages[0].result.content).toEqual([{ type: 'text', text: 'Tool result' }]); + expect(messages[0]!.type).toBe('result'); + if (messages[0]!.type === 'result') { + expect(messages[0]!.result.content).toEqual([{ type: 'text', text: 'Tool result' }]); } await client.close(); @@ -3628,9 +3623,9 @@ test('should validate structured output in callToolStream()', async () => { // Should have received result with validated structured content expect(messages.length).toBe(1); - expect(messages[0].type).toBe('result'); - if (messages[0].type === 'result') { - expect(messages[0].result.structuredContent).toEqual({ value: 42 }); + expect(messages[0]!.type).toBe('result'); + if (messages[0]!.type === 'result') { + expect(messages[0]!.result.structuredContent).toEqual({ value: 42 }); } await client.close(); @@ -3704,9 +3699,9 @@ test('callToolStream() should yield error when structuredContent does not match } expect(messages.length).toBe(1); - expect(messages[0].type).toBe('error'); - if (messages[0].type === 'error') { - expect(messages[0].error.message).toMatch(/Structured content does not match the tool's output schema/); + expect(messages[0]!.type).toBe('error'); + if (messages[0]!.type === 'error') { + expect(messages[0]!.error.message).toMatch(/Structured content does not match the tool's output schema/); } await client.close(); @@ -3776,9 +3771,9 @@ test('callToolStream() should yield error when tool with outputSchema returns no } expect(messages.length).toBe(1); - expect(messages[0].type).toBe('error'); - if (messages[0].type === 'error') { - expect(messages[0].error.message).toMatch(/Tool test-tool has an output schema but did not return structured content/); + expect(messages[0]!.type).toBe('error'); + if (messages[0]!.type === 'error') { + expect(messages[0]!.error.message).toMatch(/Tool test-tool has an output schema but did not return structured content/); } await client.close(); @@ -3841,9 +3836,9 @@ test('callToolStream() should handle tools without outputSchema normally', async } expect(messages.length).toBe(1); - expect(messages[0].type).toBe('result'); - if (messages[0].type === 'result') { - expect(messages[0].result.content).toEqual([{ type: 'text', text: 'Normal response' }]); + expect(messages[0]!.type).toBe('result'); + if (messages[0]!.type === 'result') { + expect(messages[0]!.result.content).toEqual([{ type: 'text', text: 'Normal response' }]); } await client.close(); @@ -3936,10 +3931,10 @@ test('callToolStream() should handle complex JSON schema validation', async () = } expect(messages.length).toBe(1); - expect(messages[0].type).toBe('result'); - if (messages[0].type === 'result') { - expect(messages[0].result.structuredContent).toBeDefined(); - const structuredContent = messages[0].result.structuredContent as { name: string; age: number }; + expect(messages[0]!.type).toBe('result'); + if (messages[0]!.type === 'result') { + expect(messages[0]!.result.structuredContent).toBeDefined(); + const structuredContent = messages[0]!.result.structuredContent as { name: string; age: number }; expect(structuredContent.name).toBe('John Doe'); expect(structuredContent.age).toBe(30); } @@ -4015,9 +4010,9 @@ test('callToolStream() should yield error with additional properties when not al } expect(messages.length).toBe(1); - expect(messages[0].type).toBe('error'); - if (messages[0].type === 'error') { - expect(messages[0].error.message).toMatch(/Structured content does not match the tool's output schema/); + expect(messages[0]!.type).toBe('error'); + if (messages[0]!.type === 'error') { + expect(messages[0]!.error.message).toMatch(/Structured content does not match the tool's output schema/); } await client.close(); @@ -4090,10 +4085,10 @@ test('callToolStream() should not validate structuredContent when isError is tru // Should have received result (not error), with isError flag set expect(messages.length).toBe(1); - expect(messages[0].type).toBe('result'); - if (messages[0].type === 'result') { - expect(messages[0].result.isError).toBe(true); - expect(messages[0].result.content).toEqual([{ type: 'text', text: 'Something went wrong' }]); + expect(messages[0]!.type).toBe('result'); + if (messages[0]!.type === 'result') { + expect(messages[0]!.result.isError).toBe(true); + expect(messages[0]!.result.content).toEqual([{ type: 'text', text: 'Something went wrong' }]); } await client.close(); diff --git a/test/experimental/tasks/task-listing.test.ts b/packages/integration/test/experimental/tasks/task-listing.test.ts similarity index 94% rename from test/experimental/tasks/task-listing.test.ts rename to packages/integration/test/experimental/tasks/task-listing.test.ts index bf51f1404..ae541c6f8 100644 --- a/test/experimental/tasks/task-listing.test.ts +++ b/packages/integration/test/experimental/tasks/task-listing.test.ts @@ -1,5 +1,6 @@ -import { describe, it, expect, beforeEach, afterEach } from 'vitest'; -import { ErrorCode, McpError } from '../../../src/types.js'; +import { ErrorCode, McpError } from '@modelcontextprotocol/sdk-core'; +import { afterEach, beforeEach, describe, expect, it } from 'vitest'; + import { createInMemoryTaskEnvironment } from '../../helpers/mcp.js'; describe('Task Listing with Pagination', () => { @@ -73,7 +74,7 @@ describe('Task Listing with Pagination', () => { // Get all tasks to get a valid cursor const allTasks = taskStore.getAllTasks(); - const validCursor = allTasks[2].taskId; + const validCursor = allTasks[2]!.taskId; // Use the cursor - should work even though we don't know its internal structure const result = await client.experimental.tasks.listTasks(validCursor); @@ -109,7 +110,7 @@ describe('Task Listing with Pagination', () => { // Verify it's also accessible via tasks/list const listResult = await client.experimental.tasks.listTasks(); expect(listResult.tasks).toHaveLength(1); - expect(listResult.tasks[0].taskId).toBe(task.taskId); + expect(listResult.tasks[0]!.taskId).toBe(task.taskId); }); it('should not include related-task metadata in list response', async () => { diff --git a/test/experimental/tasks/task.test.ts b/packages/integration/test/experimental/tasks/task.test.ts similarity index 95% rename from test/experimental/tasks/task.test.ts rename to packages/integration/test/experimental/tasks/task.test.ts index 37e3938d2..293f61c9f 100644 --- a/test/experimental/tasks/task.test.ts +++ b/packages/integration/test/experimental/tasks/task.test.ts @@ -1,6 +1,6 @@ -import { describe, it, expect } from 'vitest'; -import { isTerminal } from '../../../src/experimental/tasks/interfaces.js'; -import type { Task } from '../../../src/types.js'; +import { isTerminal } from '@modelcontextprotocol/sdk-core'; +import type { Task } from '@modelcontextprotocol/sdk-server'; +import { describe, expect, it } from 'vitest'; describe('Task utility functions', () => { describe('isTerminal', () => { diff --git a/packages/integration/test/helpers/http.ts b/packages/integration/test/helpers/http.ts new file mode 100644 index 000000000..7d165da83 --- /dev/null +++ b/packages/integration/test/helpers/http.ts @@ -0,0 +1,97 @@ +import type http from 'node:http'; +import { type Server } from 'node:http'; +import type { AddressInfo } from 'node:net'; + +import type { Response } from 'express'; +import { vi } from 'vitest'; + +/** + * Attach a listener to an existing server on a random localhost port and return its base URL. + */ +export async function listenOnRandomPort(server: Server, host: string = '127.0.0.1'): Promise { + return new Promise(resolve => { + server.listen(0, host, () => { + const addr = server.address() as AddressInfo; + resolve(new URL(`http://${host}:${addr.port}`)); + }); + }); +} + +// ========================= +// HTTP/Express mock helpers +// ========================= + +/** + * Create a minimal Express-like Response mock for tests. + * + * The mock supports: + * - redirect() + * - status().json().send() chaining + * - set()/header() + * - optional getRedirectUrl() helper used in some tests + */ +export function createExpressResponseMock(options: { trackRedirectUrl?: boolean } = {}): Response & { + getRedirectUrl?: () => string; +} { + let capturedRedirectUrl: string | undefined; + + const res: Partial & { getRedirectUrl?: () => string } = { + redirect: vi.fn((urlOrStatus: string | number, maybeUrl?: string | number) => { + if (options.trackRedirectUrl) { + if (typeof urlOrStatus === 'string') { + capturedRedirectUrl = urlOrStatus; + } else if (typeof maybeUrl === 'string') { + capturedRedirectUrl = maybeUrl; + } + } + return res as Response; + }) as unknown as Response['redirect'], + status: vi.fn().mockImplementation((_code: number) => { + // status code is ignored for now; tests assert it via jest/vitest spies + return res as Response; + }), + json: vi.fn().mockImplementation((_body: unknown) => { + // body is ignored; tests usually assert via spy + return res as Response; + }), + send: vi.fn().mockImplementation((_body?: unknown) => { + // body is ignored; tests usually assert via spy + return res as Response; + }), + set: vi.fn().mockImplementation((_field: string, _value?: string | string[]) => { + // header value is ignored in the generic mock; tests spy on set() + return res as Response; + }), + header: vi.fn().mockImplementation((_field: string, _value?: string | string[]) => { + return res as Response; + }) + }; + + if (options.trackRedirectUrl) { + res.getRedirectUrl = () => { + if (capturedRedirectUrl === undefined) { + throw new Error('No redirect URL was captured. Ensure redirect() was called first.'); + } + return capturedRedirectUrl; + }; + } + + return res as Response & { getRedirectUrl?: () => string }; +} + +/** + * Create a Node http.ServerResponse mock used for low-level transport tests. + * + * All core methods are jest/vitest fns returning `this` so that + * tests can assert on writeHead/write/on/end calls. + */ +export function createNodeServerResponseMock(): http.ServerResponse { + const res = { + writeHead: vi.fn().mockReturnThis(), + write: vi.fn().mockReturnThis(), + on: vi.fn().mockReturnThis(), + end: vi.fn().mockReturnThis() + }; + + return res as unknown as http.ServerResponse; +} diff --git a/test/helpers/mcp.ts b/packages/integration/test/helpers/mcp.ts similarity index 82% rename from test/helpers/mcp.ts rename to packages/integration/test/helpers/mcp.ts index 6cd08fdf0..5b49f2bae 100644 --- a/test/helpers/mcp.ts +++ b/packages/integration/test/helpers/mcp.ts @@ -1,8 +1,7 @@ -import { InMemoryTransport } from '../../src/inMemory.js'; -import { Client } from '../../src/client/index.js'; -import { Server } from '../../src/server/index.js'; -import { InMemoryTaskStore, InMemoryTaskMessageQueue } from '../../src/experimental/tasks/stores/in-memory.js'; -import type { ClientCapabilities, ServerCapabilities } from '../../src/types.js'; +import { Client } from '@modelcontextprotocol/sdk-client'; +import { InMemoryTransport } from '@modelcontextprotocol/sdk-core'; +import type { ClientCapabilities, ServerCapabilities } from '@modelcontextprotocol/sdk-server'; +import { InMemoryTaskMessageQueue, InMemoryTaskStore, Server } from '@modelcontextprotocol/sdk-server'; export interface InMemoryTaskEnvironment { client: Client; diff --git a/packages/integration/test/helpers/oauth.ts b/packages/integration/test/helpers/oauth.ts new file mode 100644 index 000000000..afb834c16 --- /dev/null +++ b/packages/integration/test/helpers/oauth.ts @@ -0,0 +1,88 @@ +import type { FetchLike } from '@modelcontextprotocol/sdk-core'; + +export interface MockOAuthFetchOptions { + resourceServerUrl: string; + authServerUrl: string; + /** + * Optional hook to inspect or override the token request. + */ + onTokenRequest?: (url: URL, init: RequestInit | undefined) => void | Promise; +} + +/** + * Shared mock fetch implementation for OAuth flows used in client tests. + * + * It handles: + * - OAuth Protected Resource Metadata discovery + * - Authorization Server Metadata discovery + * - Token endpoint responses + */ +export function createMockOAuthFetch(options: MockOAuthFetchOptions): FetchLike { + const { resourceServerUrl, authServerUrl, onTokenRequest } = options; + + return async (input: string | URL, init?: RequestInit): Promise => { + const url = input instanceof URL ? input : new URL(input); + + // Protected resource metadata discovery + if (url.origin === resourceServerUrl.slice(0, -1) && url.pathname === '/.well-known/oauth-protected-resource') { + return new Response( + JSON.stringify({ + resource: resourceServerUrl, + authorization_servers: [authServerUrl] + }), + { + status: 200, + headers: { 'Content-Type': 'application/json' } + } + ); + } + + // Authorization server metadata discovery + if (url.origin === authServerUrl && url.pathname === '/.well-known/oauth-authorization-server') { + return new Response( + JSON.stringify({ + issuer: authServerUrl, + authorization_endpoint: `${authServerUrl}/authorize`, + token_endpoint: `${authServerUrl}/token`, + response_types_supported: ['code'], + token_endpoint_auth_methods_supported: ['client_secret_basic', 'private_key_jwt'] + }), + { + status: 200, + headers: { 'Content-Type': 'application/json' } + } + ); + } + + // Token endpoint + if (url.origin === authServerUrl && url.pathname === '/token') { + if (onTokenRequest) { + await onTokenRequest(url, init); + } + + return new Response( + JSON.stringify({ + access_token: 'test-access-token', + token_type: 'Bearer' + }), + { + status: 200, + headers: { 'Content-Type': 'application/json' } + } + ); + } + + throw new Error(`Unexpected URL in mock OAuth fetch: ${url.toString()}`); + }; +} + +type MockFetch = (...args: unknown[]) => unknown; + +/** + * Helper to install a vi.fn-based global.fetch mock for tests that rely on global fetch. + */ +export function mockGlobalFetch(): MockFetch { + const mockFetch = vi.fn() as unknown as MockFetch; + (globalThis as { fetch?: MockFetch }).fetch = mockFetch; + return mockFetch; +} diff --git a/test/helpers/tasks.ts b/packages/integration/test/helpers/tasks.ts similarity index 93% rename from test/helpers/tasks.ts rename to packages/integration/test/helpers/tasks.ts index d2fed9f5d..6b8db0c1b 100644 --- a/test/helpers/tasks.ts +++ b/packages/integration/test/helpers/tasks.ts @@ -1,4 +1,4 @@ -import type { Task } from '../../src/types.js'; +import type { Task } from '@modelcontextprotocol/sdk-core'; /** * Polls the provided getTask function until the task reaches the desired status or times out. diff --git a/test/integration-tests/processCleanup.test.ts b/packages/integration/test/processCleanup.test.ts similarity index 89% rename from test/integration-tests/processCleanup.test.ts rename to packages/integration/test/processCleanup.test.ts index 11940697b..5c8fd97e1 100644 --- a/test/integration-tests/processCleanup.test.ts +++ b/packages/integration/test/processCleanup.test.ts @@ -1,12 +1,11 @@ import path from 'node:path'; import { Readable, Writable } from 'node:stream'; -import { Client } from '../../src/client/index.js'; -import { StdioClientTransport } from '../../src/client/stdio.js'; -import { Server } from '../../src/server/index.js'; -import { StdioServerTransport } from '../../src/server/stdio.js'; -import { LoggingMessageNotificationSchema } from '../../src/types.js'; -const FIXTURES_DIR = path.resolve(__dirname, '../../src/__fixtures__'); +import { Client, StdioClientTransport } from '@modelcontextprotocol/sdk-client'; +import { LoggingMessageNotificationSchema, Server, StdioServerTransport } from '@modelcontextprotocol/sdk-server'; + +// Use the local fixtures directory alongside this test file +const FIXTURES_DIR = path.resolve(__dirname, './__fixtures__'); describe('Process cleanup', () => { vi.setConfig({ testTimeout: 5000 }); // 5 second timeout diff --git a/test/server/index.test.ts b/packages/integration/test/server.test.ts similarity index 99% rename from test/server/index.test.ts rename to packages/integration/test/server.test.ts index e434e57fc..af07a4b99 100644 --- a/test/server/index.test.ts +++ b/packages/integration/test/server.test.ts @@ -1,37 +1,39 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ -import supertest from 'supertest'; -import { Client } from '../../src/client/index.js'; -import { InMemoryTransport } from '../../src/inMemory.js'; -import type { Transport } from '../../src/shared/transport.js'; +import { Client } from '@modelcontextprotocol/sdk-client'; +import type { + AnyObjectSchema, + JsonSchemaType, + JsonSchemaValidator, + jsonSchemaValidator, + LoggingMessageNotification, + Transport +} from '@modelcontextprotocol/sdk-core'; import { + CallToolRequestSchema, + CallToolResultSchema, CreateMessageRequestSchema, CreateMessageResultSchema, + CreateTaskResultSchema, + ElicitationCompleteNotificationSchema, ElicitRequestSchema, ElicitResultSchema, - ElicitationCompleteNotificationSchema, ErrorCode, + InMemoryTransport, LATEST_PROTOCOL_VERSION, ListPromptsRequestSchema, ListResourcesRequestSchema, ListToolsRequestSchema, - type LoggingMessageNotification, McpError, NotificationSchema, RequestSchema, ResultSchema, SetLevelRequestSchema, - SUPPORTED_PROTOCOL_VERSIONS, - CreateTaskResultSchema -} from '../../src/types.js'; -import { Server } from '../../src/server/index.js'; -import { McpServer } from '../../src/server/mcp.js'; -import { InMemoryTaskStore, InMemoryTaskMessageQueue } from '../../src/experimental/tasks/stores/in-memory.js'; -import { CallToolRequestSchema, CallToolResultSchema } from '../../src/types.js'; -import type { JsonSchemaType, JsonSchemaValidator, jsonSchemaValidator } from '../../src/validation/types.js'; -import type { AnyObjectSchema } from '../../src/server/zod-compat.js'; + SUPPORTED_PROTOCOL_VERSIONS +} from '@modelcontextprotocol/sdk-core'; +import { createMcpExpressApp, InMemoryTaskMessageQueue, InMemoryTaskStore, McpServer, Server } from '@modelcontextprotocol/sdk-server'; +import supertest from 'supertest'; import * as z3 from 'zod/v3'; import * as z4 from 'zod/v4'; -import { createMcpExpressApp } from '../../src/server/express.js'; describe('Zod v3', () => { /* @@ -3021,11 +3023,11 @@ describe('Task-based execution', () => { // Verify all tasks completed successfully for (let i = 0; i < taskIds.length; i++) { - const task = await client.experimental.tasks.getTask(taskIds[i]); + const task = await client.experimental.tasks.getTask(taskIds[i]!); expect(task.status).toBe('completed'); - expect(task.taskId).toBe(taskIds[i]); + expect(task.taskId).toBe(taskIds[i]!); - const result = await client.experimental.tasks.getTaskResult(taskIds[i], CallToolResultSchema); + const result = await client.experimental.tasks.getTaskResult(taskIds[i]!, CallToolResultSchema); expect(result.content).toEqual([{ type: 'text', text: `Completed task ${i + 1}` }]); } diff --git a/test/server/elicitation.test.ts b/packages/integration/test/server/elicitation.test.ts similarity index 98% rename from test/server/elicitation.test.ts rename to packages/integration/test/server/elicitation.test.ts index c6f297b46..d43880a4c 100644 --- a/test/server/elicitation.test.ts +++ b/packages/integration/test/server/elicitation.test.ts @@ -7,12 +7,15 @@ * Per the MCP spec, elicitation only supports object schemas, not primitives. */ -import { Client } from '../../src/client/index.js'; -import { InMemoryTransport } from '../../src/inMemory.js'; -import { ElicitRequestFormParams, ElicitRequestSchema } from '../../src/types.js'; -import { AjvJsonSchemaValidator } from '../../src/validation/ajv-provider.js'; -import { CfWorkerJsonSchemaValidator } from '../../src/validation/cfworker-provider.js'; -import { Server } from '../../src/server/index.js'; +import { Client } from '@modelcontextprotocol/sdk-client'; +import type { ElicitRequestFormParams } from '@modelcontextprotocol/sdk-core'; +import { + AjvJsonSchemaValidator, + CfWorkerJsonSchemaValidator, + ElicitRequestSchema, + InMemoryTransport +} from '@modelcontextprotocol/sdk-core'; +import { Server } from '@modelcontextprotocol/sdk-server'; const ajvProvider = new AjvJsonSchemaValidator(); const cfWorkerProvider = new CfWorkerJsonSchemaValidator(); diff --git a/test/server/mcp.test.ts b/packages/integration/test/server/mcp.test.ts similarity index 97% rename from test/server/mcp.test.ts rename to packages/integration/test/server/mcp.test.ts index f6c2124e1..f6597bd09 100644 --- a/test/server/mcp.test.ts +++ b/packages/integration/test/server/mcp.test.ts @@ -1,12 +1,11 @@ -import { Client } from '../../src/client/index.js'; -import { InMemoryTransport } from '../../src/inMemory.js'; -import { getDisplayName } from '../../src/shared/metadataUtils.js'; -import { UriTemplate } from '../../src/shared/uriTemplate.js'; +import { Client } from '@modelcontextprotocol/sdk-client'; +import { getDisplayName, InMemoryTaskStore, InMemoryTransport, UriTemplate } from '@modelcontextprotocol/sdk-core'; import { - CallToolResultSchema, type CallToolResult, + CallToolResultSchema, CompleteResultSchema, ElicitRequestSchema, + ErrorCode, GetPromptResultSchema, ListPromptsResultSchema, ListResourcesResultSchema, @@ -16,13 +15,12 @@ import { type Notification, ReadResourceResultSchema, type TextContent, - UrlElicitationRequiredError, - ErrorCode -} from '../../src/types.js'; -import { completable } from '../../src/server/completable.js'; -import { McpServer, ResourceTemplate } from '../../src/server/mcp.js'; -import { InMemoryTaskStore } from '../../src/experimental/tasks/stores/in-memory.js'; -import { zodTestMatrix, type ZodMatrixEntry } from '../../src/__fixtures__/zodTestMatrix.js'; + UrlElicitationRequiredError +} from '@modelcontextprotocol/sdk-core'; + +import { completable } from '../../../server/src/server/completable.js'; +import { McpServer, ResourceTemplate } from '../../../server/src/server/mcp.js'; +import { type ZodMatrixEntry, zodTestMatrix } from '../../../server/test/server/__fixtures__/zodTestMatrix.js'; function createLatch() { let latch = false; @@ -292,8 +290,8 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => { ); expect(result.tools).toHaveLength(1); - expect(result.tools[0].name).toBe('test'); - expect(result.tools[0].inputSchema).toEqual({ + expect(result.tools[0]!.name).toBe('test'); + expect(result.tools[0]!.inputSchema).toEqual({ type: 'object', properties: {} }); @@ -447,7 +445,7 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => { ListToolsResultSchema ); - expect(listResult.tools[0].inputSchema).toMatchObject({ + expect(listResult.tools[0]!.inputSchema).toMatchObject({ properties: { name: { type: 'string' }, value: { type: 'number' } @@ -540,7 +538,7 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => { ListToolsResultSchema ); - expect(listResult.tools[0].outputSchema).toMatchObject({ + expect(listResult.tools[0]!.outputSchema).toMatchObject({ type: 'object', properties: { result: { type: 'number' }, @@ -684,16 +682,16 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => { ); expect(result.tools).toHaveLength(2); - expect(result.tools[0].name).toBe('test'); - expect(result.tools[0].inputSchema).toMatchObject({ + expect(result.tools[0]!.name).toBe('test'); + expect(result.tools[0]!.inputSchema).toMatchObject({ type: 'object', properties: { name: { type: 'string' }, value: { type: 'number' } } }); - expect(result.tools[1].name).toBe('test (new api)'); - expect(result.tools[1].inputSchema).toEqual(result.tools[0].inputSchema); + expect(result.tools[1]!.name).toBe('test (new api)'); + expect(result.tools[1]!.inputSchema).toEqual(result.tools[0]!.inputSchema); }); /*** @@ -747,10 +745,10 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => { ); expect(result.tools).toHaveLength(2); - expect(result.tools[0].name).toBe('test'); - expect(result.tools[0].description).toBe('Test description'); - expect(result.tools[1].name).toBe('test (new api)'); - expect(result.tools[1].description).toBe('Test description'); + expect(result.tools[0]!.name).toBe('test'); + expect(result.tools[0]!.description).toBe('Test description'); + expect(result.tools[1]!.name).toBe('test (new api)'); + expect(result.tools[1]!.description).toBe('Test description'); }); /*** @@ -802,13 +800,13 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => { ); expect(result.tools).toHaveLength(2); - expect(result.tools[0].name).toBe('test'); - expect(result.tools[0].annotations).toEqual({ + expect(result.tools[0]!.name).toBe('test'); + expect(result.tools[0]!.annotations).toEqual({ title: 'Test Tool', readOnlyHint: true }); - expect(result.tools[1].name).toBe('test (new api)'); - expect(result.tools[1].annotations).toEqual({ + expect(result.tools[1]!.name).toBe('test (new api)'); + expect(result.tools[1]!.annotations).toEqual({ title: 'Test Tool', readOnlyHint: true }); @@ -849,18 +847,18 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => { const result = await client.request({ method: 'tools/list' }, ListToolsResultSchema); expect(result.tools).toHaveLength(2); - expect(result.tools[0].name).toBe('test'); - expect(result.tools[0].inputSchema).toMatchObject({ + expect(result.tools[0]!.name).toBe('test'); + expect(result.tools[0]!.inputSchema).toMatchObject({ type: 'object', properties: { name: { type: 'string' } } }); - expect(result.tools[0].annotations).toEqual({ + expect(result.tools[0]!.annotations).toEqual({ title: 'Test Tool', readOnlyHint: true }); - expect(result.tools[1].name).toBe('test (new api)'); - expect(result.tools[1].inputSchema).toEqual(result.tools[0].inputSchema); - expect(result.tools[1].annotations).toEqual(result.tools[0].annotations); + expect(result.tools[1]!.name).toBe('test (new api)'); + expect(result.tools[1]!.inputSchema).toEqual(result.tools[0]!.inputSchema); + expect(result.tools[1]!.annotations).toEqual(result.tools[0]!.annotations); }); /*** @@ -909,21 +907,21 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => { const result = await client.request({ method: 'tools/list' }, ListToolsResultSchema); expect(result.tools).toHaveLength(2); - expect(result.tools[0].name).toBe('test'); - expect(result.tools[0].description).toBe('A tool with everything'); - expect(result.tools[0].inputSchema).toMatchObject({ + expect(result.tools[0]!.name).toBe('test'); + expect(result.tools[0]!.description).toBe('A tool with everything'); + expect(result.tools[0]!.inputSchema).toMatchObject({ type: 'object', properties: { name: { type: 'string' } } }); - expect(result.tools[0].annotations).toEqual({ + expect(result.tools[0]!.annotations).toEqual({ title: 'Complete Test Tool', readOnlyHint: true, openWorldHint: false }); - expect(result.tools[1].name).toBe('test (new api)'); - expect(result.tools[1].description).toBe('A tool with everything'); - expect(result.tools[1].inputSchema).toEqual(result.tools[0].inputSchema); - expect(result.tools[1].annotations).toEqual(result.tools[0].annotations); + expect(result.tools[1]!.name).toBe('test (new api)'); + expect(result.tools[1]!.description).toBe('A tool with everything'); + expect(result.tools[1]!.inputSchema).toEqual(result.tools[0]!.inputSchema); + expect(result.tools[1]!.annotations).toEqual(result.tools[0]!.annotations); }); /*** @@ -976,21 +974,21 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => { const result = await client.request({ method: 'tools/list' }, ListToolsResultSchema); expect(result.tools).toHaveLength(2); - expect(result.tools[0].name).toBe('test'); - expect(result.tools[0].description).toBe('A tool with everything but empty params'); - expect(result.tools[0].inputSchema).toMatchObject({ + expect(result.tools[0]!.name).toBe('test'); + expect(result.tools[0]!.description).toBe('A tool with everything but empty params'); + expect(result.tools[0]!.inputSchema).toMatchObject({ type: 'object', properties: {} }); - expect(result.tools[0].annotations).toEqual({ + expect(result.tools[0]!.annotations).toEqual({ title: 'Complete Test Tool with empty params', readOnlyHint: true, openWorldHint: false }); - expect(result.tools[1].name).toBe('test (new api)'); - expect(result.tools[1].description).toBe('A tool with everything but empty params'); - expect(result.tools[1].inputSchema).toEqual(result.tools[0].inputSchema); - expect(result.tools[1].annotations).toEqual(result.tools[0].annotations); + expect(result.tools[1]!.name).toBe('test (new api)'); + expect(result.tools[1]!.description).toBe('A tool with everything but empty params'); + expect(result.tools[1]!.inputSchema).toEqual(result.tools[0]!.inputSchema); + expect(result.tools[1]!.annotations).toEqual(result.tools[0]!.annotations); }); /*** @@ -1199,7 +1197,7 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => { ); expect(listResult.tools).toHaveLength(1); - expect(listResult.tools[0].outputSchema).toMatchObject({ + expect(listResult.tools[0]!.outputSchema).toMatchObject({ type: 'object', properties: { processedInput: { type: 'string' }, @@ -1823,9 +1821,9 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => { const result = await client.request({ method: 'tools/list' }, ListToolsResultSchema); expect(result.tools).toHaveLength(1); - expect(result.tools[0].name).toBe('test-with-meta'); - expect(result.tools[0].description).toBe('A tool with _meta field'); - expect(result.tools[0]._meta).toEqual(metaData); + expect(result.tools[0]!.name).toBe('test-with-meta'); + expect(result.tools[0]!.description).toBe('A tool with _meta field'); + expect(result.tools[0]!._meta).toEqual(metaData); }); /*** @@ -1859,8 +1857,8 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => { const result = await client.request({ method: 'tools/list' }, ListToolsResultSchema); expect(result.tools).toHaveLength(1); - expect(result.tools[0].name).toBe('test-without-meta'); - expect(result.tools[0]._meta).toBeUndefined(); + expect(result.tools[0]!.name).toBe('test-without-meta'); + expect(result.tools[0]!._meta).toBeUndefined(); }); test('should include execution field in listTools response when tool has execution settings', async () => { @@ -1924,8 +1922,8 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => { const result = await client.request({ method: 'tools/list' }, ListToolsResultSchema); expect(result.tools).toHaveLength(1); - expect(result.tools[0].name).toBe('task-tool'); - expect(result.tools[0].execution).toEqual({ + expect(result.tools[0]!.name).toBe('task-tool'); + expect(result.tools[0]!.execution).toEqual({ taskSupport: 'required' }); @@ -1993,8 +1991,8 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => { const result = await client.request({ method: 'tools/list' }, ListToolsResultSchema); expect(result.tools).toHaveLength(1); - expect(result.tools[0].name).toBe('optional-task-tool'); - expect(result.tools[0].execution).toEqual({ + expect(result.tools[0]!.name).toBe('optional-task-tool'); + expect(result.tools[0]!.execution).toEqual({ taskSupport: 'optional' }); @@ -2087,8 +2085,8 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => { ); expect(result.resources).toHaveLength(1); - expect(result.resources[0].name).toBe('test'); - expect(result.resources[0].uri).toBe('test://resource'); + expect(result.resources[0]!.name).toBe('test'); + expect(result.resources[0]!.uri).toBe('test://resource'); }); /*** @@ -2332,7 +2330,7 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => { result = await client.request({ method: 'resources/list' }, ListResourcesResultSchema); expect(result.resources).toHaveLength(1); - expect(result.resources[0].uri).toBe('test://resource2'); + expect(result.resources[0]!.uri).toBe('test://resource2'); }); /*** @@ -2439,9 +2437,9 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => { ); expect(result.resources).toHaveLength(1); - expect(result.resources[0].description).toBe('Test resource'); - expect(result.resources[0].mimeType).toBe('text/plain'); - expect(result.resources[0].annotations).toEqual({ + expect(result.resources[0]!.description).toBe('Test resource'); + expect(result.resources[0]!.mimeType).toBe('text/plain'); + expect(result.resources[0]!.annotations).toEqual({ audience: ['user'], priority: 0.5, lastModified: mockDate @@ -2482,8 +2480,8 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => { ); expect(result.resourceTemplates).toHaveLength(1); - expect(result.resourceTemplates[0].name).toBe('test'); - expect(result.resourceTemplates[0].uriTemplate).toBe('test://resource/{id}'); + expect(result.resourceTemplates[0]!.name).toBe('test'); + expect(result.resourceTemplates[0]!.uriTemplate).toBe('test://resource/{id}'); }); /*** @@ -2537,10 +2535,10 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => { ); expect(result.resources).toHaveLength(2); - expect(result.resources[0].name).toBe('Resource 1'); - expect(result.resources[0].uri).toBe('test://resource/1'); - expect(result.resources[1].name).toBe('Resource 2'); - expect(result.resources[1].uri).toBe('test://resource/2'); + expect(result.resources[0]!.name).toBe('Resource 1'); + expect(result.resources[0]!.uri).toBe('test://resource/1'); + expect(result.resources[1]!.name).toBe('Resource 2'); + expect(result.resources[1]!.uri).toBe('test://resource/2'); }); /*** @@ -3037,8 +3035,8 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => { ); expect(result.prompts).toHaveLength(1); - expect(result.prompts[0].name).toBe('test'); - expect(result.prompts[0].arguments).toBeUndefined(); + expect(result.prompts[0]!.name).toBe('test'); + expect(result.prompts[0]!.arguments).toBeUndefined(); }); /*** * Test: Updating Existing Prompt @@ -3184,8 +3182,8 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => { ListPromptsResultSchema ); - expect(listResult.prompts[0].arguments).toHaveLength(2); - expect(listResult.prompts[0].arguments?.map(a => a.name).sort()).toEqual(['name', 'value']); + expect(listResult.prompts[0]!.arguments).toHaveLength(2); + expect(listResult.prompts[0]!.arguments!.map(a => a.name).sort()).toEqual(['name', 'value']); // Call the prompt with the new schema const getResult = await client.request( @@ -3343,7 +3341,7 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => { result = await client.request({ method: 'prompts/list' }, ListPromptsResultSchema); expect(result.prompts).toHaveLength(1); - expect(result.prompts[0].name).toBe('prompt2'); + expect(result.prompts[0]!.name).toBe('prompt2'); }); /*** @@ -3390,8 +3388,8 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => { ); expect(result.prompts).toHaveLength(1); - expect(result.prompts[0].name).toBe('test'); - expect(result.prompts[0].arguments).toEqual([ + expect(result.prompts[0]!.name).toBe('test'); + expect(result.prompts[0]!.arguments).toEqual([ { name: 'name', required: true }, { name: 'value', required: true } ]); @@ -3434,8 +3432,8 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => { ); expect(result.prompts).toHaveLength(1); - expect(result.prompts[0].name).toBe('test'); - expect(result.prompts[0].description).toBe('Test description'); + expect(result.prompts[0]!.name).toBe('test'); + expect(result.prompts[0]!.description).toBe('Test description'); }); /*** @@ -3983,14 +3981,14 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => { expect(result.resources).toHaveLength(2); // Resource 1 should have its own metadata - expect(result.resources[0].name).toBe('Resource 1'); - expect(result.resources[0].description).toBe('Individual resource description'); - expect(result.resources[0].mimeType).toBe('text/plain'); + expect(result.resources[0]!.name).toBe('Resource 1'); + expect(result.resources[0]!.description).toBe('Individual resource description'); + expect(result.resources[0]!.mimeType).toBe('text/plain'); // Resource 2 should inherit template metadata - expect(result.resources[1].name).toBe('Resource 2'); - expect(result.resources[1].description).toBe('Template description'); - expect(result.resources[1].mimeType).toBe('application/json'); + expect(result.resources[1]!.name).toBe('Resource 2'); + expect(result.resources[1]!.description).toBe('Template description'); + expect(result.resources[1]!.mimeType).toBe('application/json'); }); /*** @@ -4050,9 +4048,9 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => { expect(result.resources).toHaveLength(1); // All fields should be from the individual resource, not the template - expect(result.resources[0].name).toBe('Overridden Name'); - expect(result.resources[0].description).toBe('Overridden description'); - expect(result.resources[0].mimeType).toBe('text/markdown'); + expect(result.resources[0]!.name).toBe('Overridden Name'); + expect(result.resources[0]!.description).toBe('Overridden description'); + expect(result.resources[0]!.mimeType).toBe('text/markdown'); }); test('should support optional prompt arguments', async () => { @@ -4090,8 +4088,8 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => { ); expect(result.prompts).toHaveLength(1); - expect(result.prompts[0].name).toBe('test-prompt'); - expect(result.prompts[0].arguments).toEqual([ + expect(result.prompts[0]!.name).toBe('test-prompt'); + expect(result.prompts[0]!.arguments).toEqual([ { name: 'name', description: undefined, @@ -5170,8 +5168,8 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => { ); expect(result.resources).toHaveLength(1); - expect(result.resources[0].name).toBe('test'); - expect(result.resources[0].uri).toBe('test://resource'); + expect(result.resources[0]!.name).toBe('test'); + expect(result.resources[0]!.uri).toBe('test://resource'); }); /*** @@ -5315,14 +5313,14 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => { expect(result.resources).toHaveLength(2); // Resource 1 should have its own metadata - expect(result.resources[0].name).toBe('Resource 1'); - expect(result.resources[0].description).toBe('Individual resource description'); - expect(result.resources[0].mimeType).toBe('text/plain'); + expect(result.resources[0]!.name).toBe('Resource 1'); + expect(result.resources[0]!.description).toBe('Individual resource description'); + expect(result.resources[0]!.mimeType).toBe('text/plain'); // Resource 2 should inherit template metadata - expect(result.resources[1].name).toBe('Resource 2'); - expect(result.resources[1].description).toBe('Template description'); - expect(result.resources[1].mimeType).toBe('application/json'); + expect(result.resources[1]!.name).toBe('Resource 2'); + expect(result.resources[1]!.description).toBe('Template description'); + expect(result.resources[1]!.mimeType).toBe('application/json'); }); /*** @@ -5382,9 +5380,9 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => { expect(result.resources).toHaveLength(1); // All fields should be from the individual resource, not the template - expect(result.resources[0].name).toBe('Overridden Name'); - expect(result.resources[0].description).toBe('Overridden description'); - expect(result.resources[0].mimeType).toBe('text/markdown'); + expect(result.resources[0]!.name).toBe('Overridden Name'); + expect(result.resources[0]!.description).toBe('Overridden description'); + expect(result.resources[0]!.mimeType).toBe('text/markdown'); }); }); @@ -6346,7 +6344,7 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => { // Should receive error result expect(result.isError).toBe(true); const content = result.content as TextContent[]; - expect(content[0].text).toContain('requires task augmentation'); + expect(content[0]!.text).toContain('requires task augmentation'); taskStore.cleanup(); }); diff --git a/test/integration-tests/stateManagementStreamableHttp.test.ts b/packages/integration/test/stateManagementStreamableHttp.test.ts similarity index 96% rename from test/integration-tests/stateManagementStreamableHttp.test.ts rename to packages/integration/test/stateManagementStreamableHttp.test.ts index d79d95c75..3fdf40391 100644 --- a/test/integration-tests/stateManagementStreamableHttp.test.ts +++ b/packages/integration/test/stateManagementStreamableHttp.test.ts @@ -1,18 +1,19 @@ -import { createServer, type Server } from 'node:http'; import { randomUUID } from 'node:crypto'; -import { Client } from '../../src/client/index.js'; -import { StreamableHTTPClientTransport } from '../../src/client/streamableHttp.js'; -import { McpServer } from '../../src/server/mcp.js'; -import { StreamableHTTPServerTransport } from '../../src/server/streamableHttp.js'; +import { createServer, type Server } from 'node:http'; + +import { Client, StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk-client'; import { CallToolResultSchema, - ListToolsResultSchema, - ListResourcesResultSchema, + LATEST_PROTOCOL_VERSION, ListPromptsResultSchema, - LATEST_PROTOCOL_VERSION -} from '../../src/types.js'; -import { zodTestMatrix, type ZodMatrixEntry } from '../../src/__fixtures__/zodTestMatrix.js'; -import { listenOnRandomPort } from '../helpers/http.js'; + ListResourcesResultSchema, + ListToolsResultSchema, + McpServer, + StreamableHTTPServerTransport +} from '@modelcontextprotocol/sdk-server'; + +import { type ZodMatrixEntry, zodTestMatrix } from './__fixtures__/zodTestMatrix.js'; +import { listenOnRandomPort } from './helpers/http.js'; describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => { const { z } = entry; diff --git a/test/integration-tests/taskLifecycle.test.ts b/packages/integration/test/taskLifecycle.test.ts similarity index 97% rename from test/integration-tests/taskLifecycle.test.ts rename to packages/integration/test/taskLifecycle.test.ts index 629a61b66..d7e3dc8ad 100644 --- a/test/integration-tests/taskLifecycle.test.ts +++ b/packages/integration/test/taskLifecycle.test.ts @@ -1,24 +1,26 @@ -import { createServer, type Server } from 'node:http'; import { randomUUID } from 'node:crypto'; -import { Client } from '../../src/client/index.js'; -import { StreamableHTTPClientTransport } from '../../src/client/streamableHttp.js'; -import { McpServer } from '../../src/server/mcp.js'; -import { StreamableHTTPServerTransport } from '../../src/server/streamableHttp.js'; +import { createServer, type Server } from 'node:http'; + +import { Client, StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk-client'; +import type { TaskRequestOptions } from '@modelcontextprotocol/sdk-server'; import { CallToolResultSchema, CreateTaskResultSchema, ElicitRequestSchema, ElicitResultSchema, ErrorCode, + InMemoryTaskMessageQueue, + InMemoryTaskStore, McpError, + McpServer, RELATED_TASK_META_KEY, + StreamableHTTPServerTransport, TaskSchema -} from '../../src/types.js'; +} from '@modelcontextprotocol/sdk-server'; import { z } from 'zod'; -import { InMemoryTaskStore, InMemoryTaskMessageQueue } from '../../src/experimental/tasks/stores/in-memory.js'; -import type { TaskRequestOptions } from '../../src/shared/protocol.js'; -import { listenOnRandomPort } from '../helpers/http.js'; -import { waitForTaskStatus } from '../helpers/tasks.js'; + +import { listenOnRandomPort } from './helpers/http.js'; +import { waitForTaskStatus } from './helpers/tasks.js'; describe('Task Lifecycle Integration Tests', () => { let server: Server; @@ -556,9 +558,9 @@ describe('Task Lifecycle Integration Tests', () => { // Verify all messages were delivered in order expect(receivedMessages.length).toBe(3); - expect(receivedMessages[0].message).toBe('Request 1 of 3'); - expect(receivedMessages[1].message).toBe('Request 2 of 3'); - expect(receivedMessages[2].message).toBe('Request 3 of 3'); + expect(receivedMessages[0]!.message).toBe('Request 1 of 3'); + expect(receivedMessages[1]!.message).toBe('Request 2 of 3'); + expect(receivedMessages[2]!.message).toBe('Request 3 of 3'); // Verify final result includes all responses expect(result.content).toEqual([{ type: 'text', text: 'Received responses: Response 1, Response 2, Response 3' }]); @@ -1274,14 +1276,14 @@ describe('Task Lifecycle Integration Tests', () => { // Verify all 3 messages were delivered expect(receivedMessages.length).toBe(3); - expect(receivedMessages[0].message).toBe('Streaming message 1 of 3'); - expect(receivedMessages[1].message).toBe('Streaming message 2 of 3'); - expect(receivedMessages[2].message).toBe('Streaming message 3 of 3'); + expect(receivedMessages[0]!.message).toBe('Streaming message 1 of 3'); + expect(receivedMessages[1]!.message).toBe('Streaming message 2 of 3'); + expect(receivedMessages[2]!.message).toBe('Streaming message 3 of 3'); // Verify messages were delivered over time (not all at once) // The delay between messages should be approximately 300ms - const timeBetweenFirstAndSecond = receivedMessages[1].timestamp - receivedMessages[0].timestamp; - const timeBetweenSecondAndThird = receivedMessages[2].timestamp - receivedMessages[1].timestamp; + const timeBetweenFirstAndSecond = receivedMessages[1]!.timestamp - receivedMessages[0]!.timestamp; + const timeBetweenSecondAndThird = receivedMessages[2]!.timestamp - receivedMessages[1]!.timestamp; // Allow some tolerance for timing (messages should be at least 200ms apart) expect(timeBetweenFirstAndSecond).toBeGreaterThan(200); @@ -1470,8 +1472,8 @@ describe('Task Lifecycle Integration Tests', () => { // Verify all queued messages were delivered before the final result expect(receivedMessages.length).toBe(2); - expect(receivedMessages[0].message).toBe('Quick message 1 of 2'); - expect(receivedMessages[1].message).toBe('Quick message 2 of 2'); + expect(receivedMessages[0]!.message).toBe('Quick message 1 of 2'); + expect(receivedMessages[1]!.message).toBe('Quick message 2 of 2'); // Verify final result is correct expect(result.content).toEqual([{ type: 'text', text: 'Task completed quickly' }]); @@ -1638,15 +1640,15 @@ describe('Task Lifecycle Integration Tests', () => { expect(messages.length).toBeGreaterThanOrEqual(2); // First message should be taskCreated - expect(messages[0].type).toBe('taskCreated'); - expect(messages[0].task).toBeDefined(); + expect(messages[0]!.type).toBe('taskCreated'); + expect(messages[0]!.task).toBeDefined(); // Should have a taskStatus message const statusMessages = messages.filter(m => m.type === 'taskStatus'); expect(statusMessages.length).toBeGreaterThanOrEqual(1); // Last message should be result - const lastMessage = messages[messages.length - 1]; + const lastMessage = messages[messages.length - 1]!; expect(lastMessage.type).toBe('result'); expect(lastMessage.result).toBeDefined(); diff --git a/test/integration-tests/taskResumability.test.ts b/packages/integration/test/taskResumability.test.ts similarity index 94% rename from test/integration-tests/taskResumability.test.ts rename to packages/integration/test/taskResumability.test.ts index 187a3d2ff..560c157d0 100644 --- a/test/integration-tests/taskResumability.test.ts +++ b/packages/integration/test/taskResumability.test.ts @@ -1,13 +1,17 @@ -import { createServer, type Server } from 'node:http'; import { randomUUID } from 'node:crypto'; -import { Client } from '../../src/client/index.js'; -import { StreamableHTTPClientTransport } from '../../src/client/streamableHttp.js'; -import { McpServer } from '../../src/server/mcp.js'; -import { StreamableHTTPServerTransport } from '../../src/server/streamableHttp.js'; -import { CallToolResultSchema, LoggingMessageNotificationSchema } from '../../src/types.js'; -import { InMemoryEventStore } from '../../src/examples/shared/inMemoryEventStore.js'; -import { zodTestMatrix, type ZodMatrixEntry } from '../../src/__fixtures__/zodTestMatrix.js'; -import { listenOnRandomPort } from '../helpers/http.js'; +import { createServer, type Server } from 'node:http'; + +import { Client, StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk-client'; +import { + CallToolResultSchema, + InMemoryEventStore, + LoggingMessageNotificationSchema, + McpServer, + StreamableHTTPServerTransport +} from '@modelcontextprotocol/sdk-server'; + +import { type ZodMatrixEntry, zodTestMatrix } from './__fixtures__/zodTestMatrix.js'; +import { listenOnRandomPort } from './helpers/http.js'; describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => { const { z } = entry; diff --git a/test/server/title.test.ts b/packages/integration/test/title.test.ts similarity index 80% rename from test/server/title.test.ts rename to packages/integration/test/title.test.ts index de353af30..d4d5f40ac 100644 --- a/test/server/title.test.ts +++ b/packages/integration/test/title.test.ts @@ -1,8 +1,8 @@ -import { Server } from '../../src/server/index.js'; -import { Client } from '../../src/client/index.js'; -import { InMemoryTransport } from '../../src/inMemory.js'; -import { McpServer, ResourceTemplate } from '../../src/server/mcp.js'; -import { zodTestMatrix, type ZodMatrixEntry } from '../../src/__fixtures__/zodTestMatrix.js'; +import { Client } from '@modelcontextprotocol/sdk-client'; +import { InMemoryTransport } from '@modelcontextprotocol/sdk-core'; +import { McpServer, ResourceTemplate, Server } from '@modelcontextprotocol/sdk-server'; + +import { type ZodMatrixEntry, zodTestMatrix } from './__fixtures__/zodTestMatrix.js'; describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => { const { z } = entry; @@ -33,9 +33,9 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => { const tools = await client.listTools(); expect(tools.tools).toHaveLength(1); - expect(tools.tools[0].name).toBe('test-tool'); - expect(tools.tools[0].title).toBe('Test Tool Display Name'); - expect(tools.tools[0].description).toBe('A test tool'); + expect(tools.tools[0]!.name).toBe('test-tool'); + expect(tools.tools[0]!.title).toBe('Test Tool Display Name'); + expect(tools.tools[0]!.description).toBe('A test tool'); }); it('should work with tools without title', async () => { @@ -53,9 +53,9 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => { const tools = await client.listTools(); expect(tools.tools).toHaveLength(1); - expect(tools.tools[0].name).toBe('test-tool'); - expect(tools.tools[0].title).toBeUndefined(); - expect(tools.tools[0].description).toBe('A test tool'); + expect(tools.tools[0]!.name).toBe('test-tool'); + expect(tools.tools[0]!.title).toBeUndefined(); + expect(tools.tools[0]!.description).toBe('A test tool'); }); it('should work with prompts that have title using update', async () => { @@ -76,9 +76,9 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => { const prompts = await client.listPrompts(); expect(prompts.prompts).toHaveLength(1); - expect(prompts.prompts[0].name).toBe('test-prompt'); - expect(prompts.prompts[0].title).toBe('Test Prompt Display Name'); - expect(prompts.prompts[0].description).toBe('A test prompt'); + expect(prompts.prompts[0]!.name).toBe('test-prompt'); + expect(prompts.prompts[0]!.title).toBe('Test Prompt Display Name'); + expect(prompts.prompts[0]!.description).toBe('A test prompt'); }); it('should work with prompts using registerPrompt', async () => { @@ -111,10 +111,10 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => { const prompts = await client.listPrompts(); expect(prompts.prompts).toHaveLength(1); - expect(prompts.prompts[0].name).toBe('test-prompt'); - expect(prompts.prompts[0].title).toBe('Test Prompt Display Name'); - expect(prompts.prompts[0].description).toBe('A test prompt'); - expect(prompts.prompts[0].arguments).toHaveLength(1); + expect(prompts.prompts[0]!.name).toBe('test-prompt'); + expect(prompts.prompts[0]!.title).toBe('Test Prompt Display Name'); + expect(prompts.prompts[0]!.description).toBe('A test prompt'); + expect(prompts.prompts[0]!.arguments).toHaveLength(1); }); it('should work with resources using registerResource', async () => { @@ -148,10 +148,10 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => { const resources = await client.listResources(); expect(resources.resources).toHaveLength(1); - expect(resources.resources[0].name).toBe('test-resource'); - expect(resources.resources[0].title).toBe('Test Resource Display Name'); - expect(resources.resources[0].description).toBe('A test resource'); - expect(resources.resources[0].mimeType).toBe('text/plain'); + expect(resources.resources[0]!.name).toBe('test-resource'); + expect(resources.resources[0]!.title).toBe('Test Resource Display Name'); + expect(resources.resources[0]!.description).toBe('A test resource'); + expect(resources.resources[0]!.mimeType).toBe('text/plain'); }); it('should work with dynamic resources using registerResource', async () => { @@ -184,10 +184,10 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => { const resourceTemplates = await client.listResourceTemplates(); expect(resourceTemplates.resourceTemplates).toHaveLength(1); - expect(resourceTemplates.resourceTemplates[0].name).toBe('user-profile'); - expect(resourceTemplates.resourceTemplates[0].title).toBe('User Profile'); - expect(resourceTemplates.resourceTemplates[0].description).toBe('User profile information'); - expect(resourceTemplates.resourceTemplates[0].uriTemplate).toBe('users://{userId}/profile'); + expect(resourceTemplates.resourceTemplates[0]!.name).toBe('user-profile'); + expect(resourceTemplates.resourceTemplates[0]!.title).toBe('User Profile'); + expect(resourceTemplates.resourceTemplates[0]!.description).toBe('User profile information'); + expect(resourceTemplates.resourceTemplates[0]!.uriTemplate).toBe('users://{userId}/profile'); // Test reading the resource const readResult = await client.readResource({ uri: 'users://123/profile' }); diff --git a/packages/integration/tsconfig.json b/packages/integration/tsconfig.json new file mode 100644 index 000000000..63523d433 --- /dev/null +++ b/packages/integration/tsconfig.json @@ -0,0 +1,15 @@ +{ + "extends": "@modelcontextprotocol/tsconfig", + "include": ["./"], + "exclude": ["node_modules", "dist"], + "compilerOptions": { + "baseUrl": ".", + "paths": { + "*": ["./*"], + "@modelcontextprotocol/sdk-core": ["node_modules/@modelcontextprotocol/sdk-core/src/index.ts"], + "@modelcontextprotocol/sdk-client": ["node_modules/@modelcontextprotocol/sdk-client/src/index.ts"], + "@modelcontextprotocol/sdk-server": ["node_modules/@modelcontextprotocol/sdk-server/src/index.ts"], + "@modelcontextprotocol/vitest-config": ["node_modules/@modelcontextprotocol/vitest-config/tsconfig.json"] + } + } +} diff --git a/packages/integration/vitest.config.js b/packages/integration/vitest.config.js new file mode 100644 index 000000000..38f030fdd --- /dev/null +++ b/packages/integration/vitest.config.js @@ -0,0 +1,3 @@ +import baseConfig from '../../common/vitest-config/vitest.config.js'; + +export default baseConfig; diff --git a/packages/server/eslint.config.mjs b/packages/server/eslint.config.mjs new file mode 100644 index 000000000..951c9f3a9 --- /dev/null +++ b/packages/server/eslint.config.mjs @@ -0,0 +1,5 @@ +// @ts-check + +import baseConfig from '@modelcontextprotocol/eslint-config'; + +export default baseConfig; diff --git a/packages/server/package.json b/packages/server/package.json new file mode 100644 index 000000000..443aa652a --- /dev/null +++ b/packages/server/package.json @@ -0,0 +1,108 @@ +{ + "name": "@modelcontextprotocol/sdk-server", + "version": "2.0.0-alpha.0", + "description": "Model Context Protocol implementation for TypeScript", + "license": "MIT", + "author": "Anthropic, PBC (https://anthropic.com)", + "homepage": "https://modelcontextprotocol.io", + "bugs": "https://github.com/modelcontextprotocol/typescript-sdk/issues", + "type": "module", + "repository": { + "type": "git", + "url": "git+https://github.com/modelcontextprotocol/typescript-sdk.git" + }, + "engines": { + "node": ">=18" + }, + "keywords": [ + "modelcontextprotocol", + "mcp" + ], + "exports": { + ".": { + "import": "./dist/index.js" + } + }, + "typesVersions": { + "*": { + "*": [ + "./dist/*" + ] + } + }, + "files": [ + "dist" + ], + "scripts": { + "fetch:spec-types": "tsx scripts/fetch-spec-types.ts", + "typecheck": "tsc -p tsconfig.build.json --noEmit", + "build": "npm run build:esm", + "build:esm": "mkdir -p dist && echo '{\"type\": \"module\"}' > dist/package.json && tsc -p tsconfig.build.json", + "build:esm:w": "npm run build:esm -- -w", + "prepack": "npm run build:esm", + "lint": "eslint src/ && prettier --check .", + "lint:fix": "eslint src/ --fix && prettier --write .", + "check": "npm run typecheck && npm run lint", + "test": "vitest run", + "test:watch": "vitest", + "start": "npm run server", + "server": "tsx watch --clear-screen=false scripts/cli.ts server", + "client": "tsx scripts/cli.ts client" + }, + "dependencies": { + "@modelcontextprotocol/sdk-core": "workspace:^", + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1", + "content-type": "^1.0.5", + "cors": "^2.8.5", + "cross-spawn": "^7.0.5", + "eventsource": "^3.0.2", + "eventsource-parser": "^3.0.0", + "express": "^5.0.1", + "express-rate-limit": "^7.5.0", + "jose": "^6.1.1", + "json-schema-typed": "^8.0.2", + "pkce-challenge": "^5.0.0", + "raw-body": "^3.0.0", + "zod": "^3.25 || ^4.0", + "zod-to-json-schema": "^3.25.0" + }, + "peerDependencies": { + "@cfworker/json-schema": "^4.1.1", + "zod": "^3.25 || ^4.0" + }, + "peerDependenciesMeta": { + "@cfworker/json-schema": { + "optional": true + }, + "zod": { + "optional": false + } + }, + "devDependencies": { + "@modelcontextprotocol/tsconfig": "workspace:^", + "@modelcontextprotocol/vitest-config": "workspace:^", + "@modelcontextprotocol/eslint-config": "workspace:^", + "@cfworker/json-schema": "^4.1.1", + "@eslint/js": "^9.39.1", + "@types/content-type": "^1.1.8", + "@types/cors": "^2.8.17", + "@types/cross-spawn": "^6.0.6", + "@types/eventsource": "^1.1.15", + "@types/express": "^5.0.0", + "@types/express-serve-static-core": "^5.1.0", + "@types/supertest": "^6.0.2", + "@types/ws": "^8.5.12", + "@typescript/native-preview": "^7.0.0-dev.20251103.1", + "eslint": "^9.8.0", + "eslint-config-prettier": "^10.1.8", + "eslint-plugin-n": "^17.23.1", + "prettier": "3.6.2", + "supertest": "^7.0.0", + "tsx": "^4.16.5", + "typescript": "^5.5.4", + "typescript-eslint": "^8.48.1", + "vitest": "^4.0.8", + "ws": "^8.18.0" + } +} diff --git a/src/experimental/index.ts b/packages/server/src/experimental/index.ts similarity index 100% rename from src/experimental/index.ts rename to packages/server/src/experimental/index.ts diff --git a/packages/server/src/experimental/tasks/index.ts b/packages/server/src/experimental/tasks/index.ts new file mode 100644 index 000000000..51ebd7fec --- /dev/null +++ b/packages/server/src/experimental/tasks/index.ts @@ -0,0 +1,13 @@ +/** + * Experimental task features for MCP SDK. + * WARNING: These APIs are experimental and may change without notice. + * + * @experimental + */ + +// SDK implementation interfaces +export * from './interfaces.js'; + +// Wrapper classes +export * from './mcp-server.js'; +export * from './server.js'; diff --git a/packages/server/src/experimental/tasks/interfaces.ts b/packages/server/src/experimental/tasks/interfaces.ts new file mode 100644 index 000000000..cae24bcb4 --- /dev/null +++ b/packages/server/src/experimental/tasks/interfaces.ts @@ -0,0 +1,49 @@ +/** + * Experimental task interfaces for MCP SDK. + * WARNING: These APIs are experimental and may change without notice. + */ + +import type { + AnySchema, + CallToolResult, + CreateTaskRequestHandlerExtra, + CreateTaskResult, + GetTaskResult, + Result, + TaskRequestHandlerExtra, + ZodRawShapeCompat +} from '@modelcontextprotocol/sdk-core'; + +import type { BaseToolCallback } from '../../server/mcp.js'; + +// ============================================================================ +// Task Handler Types (for registerToolTask) +// ============================================================================ + +/** + * Handler for creating a task. + * @experimental + */ +export type CreateTaskRequestHandler< + SendResultT extends Result, + Args extends undefined | ZodRawShapeCompat | AnySchema = undefined +> = BaseToolCallback; + +/** + * Handler for task operations (get, getResult). + * @experimental + */ +export type TaskRequestHandler< + SendResultT extends Result, + Args extends undefined | ZodRawShapeCompat | AnySchema = undefined +> = BaseToolCallback; + +/** + * Interface for task-based tool handlers. + * @experimental + */ +export interface ToolTaskHandler { + createTask: CreateTaskRequestHandler; + getTask: TaskRequestHandler; + getTaskResult: TaskRequestHandler; +} diff --git a/src/experimental/tasks/mcp-server.ts b/packages/server/src/experimental/tasks/mcp-server.ts similarity index 94% rename from src/experimental/tasks/mcp-server.ts rename to packages/server/src/experimental/tasks/mcp-server.ts index 506f3d72b..29bce908f 100644 --- a/src/experimental/tasks/mcp-server.ts +++ b/packages/server/src/experimental/tasks/mcp-server.ts @@ -5,10 +5,10 @@ * @experimental */ -import type { McpServer, RegisteredTool, AnyToolHandler } from '../../server/mcp.js'; -import type { ZodRawShapeCompat, AnySchema } from '../../server/zod-compat.js'; -import type { ToolAnnotations, ToolExecution } from '../../types.js'; -import type { ToolTaskHandler, TaskToolExecution } from './interfaces.js'; +import type { AnySchema, TaskToolExecution, ToolAnnotations, ToolExecution, ZodRawShapeCompat } from '@modelcontextprotocol/sdk-core'; + +import type { AnyToolHandler, McpServer, RegisteredTool } from '../../server/mcp.js'; +import type { ToolTaskHandler } from './interfaces.js'; /** * Internal interface for accessing McpServer's private _createRegisteredTool method. diff --git a/src/experimental/tasks/server.ts b/packages/server/src/experimental/tasks/server.ts similarity index 91% rename from src/experimental/tasks/server.ts rename to packages/server/src/experimental/tasks/server.ts index a4150a8d7..c521e38dc 100644 --- a/src/experimental/tasks/server.ts +++ b/packages/server/src/experimental/tasks/server.ts @@ -5,11 +5,21 @@ * @experimental */ -import type { Server } from '../../server/index.js'; -import type { RequestOptions } from '../../shared/protocol.js'; -import type { ResponseMessage } from '../../shared/responseMessage.js'; -import type { AnySchema, SchemaOutput } from '../../server/zod-compat.js'; -import type { ServerRequest, Notification, Request, Result, GetTaskResult, ListTasksResult, CancelTaskResult } from '../../types.js'; +import type { + AnySchema, + CancelTaskResult, + GetTaskResult, + ListTasksResult, + Notification, + Request, + RequestOptions, + ResponseMessage, + Result, + SchemaOutput, + ServerRequest +} from '@modelcontextprotocol/sdk-core'; + +import type { Server } from '../../server/server.js'; /** * Experimental task features for low-level MCP servers. diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts new file mode 100644 index 000000000..b98402c6c --- /dev/null +++ b/packages/server/src/index.ts @@ -0,0 +1,17 @@ +export * from './server/completable.js'; +export * from './server/express.js'; +export * from './server/inMemoryEventStore.js'; +export * from './server/mcp.js'; +export * from './server/server.js'; +export * from './server/sse.js'; +export * from './server/stdio.js'; +export * from './server/streamableHttp.js'; + +// auth exports +export * from './server/auth/index.js'; + +// experimental exports +export * from './experimental/index.js'; + +// re-export shared types +export * from '@modelcontextprotocol/sdk-core'; diff --git a/src/server/auth/clients.ts b/packages/server/src/server/auth/clients.ts similarity index 93% rename from src/server/auth/clients.ts rename to packages/server/src/server/auth/clients.ts index 4e3f8e17e..60d587825 100644 --- a/src/server/auth/clients.ts +++ b/packages/server/src/server/auth/clients.ts @@ -1,4 +1,4 @@ -import { OAuthClientInformationFull } from '../../shared/auth.js'; +import type { OAuthClientInformationFull } from '@modelcontextprotocol/sdk-core'; /** * Stores information about registered OAuth clients for this server. diff --git a/src/server/auth/handlers/authorize.ts b/packages/server/src/server/auth/handlers/authorize.ts similarity index 91% rename from src/server/auth/handlers/authorize.ts rename to packages/server/src/server/auth/handlers/authorize.ts index dcb6c03ec..32d96d017 100644 --- a/src/server/auth/handlers/authorize.ts +++ b/packages/server/src/server/auth/handlers/authorize.ts @@ -1,10 +1,12 @@ -import { RequestHandler } from 'express'; -import * as z from 'zod/v4'; +import { InvalidClientError, InvalidRequestError, OAuthError, ServerError, TooManyRequestsError } from '@modelcontextprotocol/sdk-core'; +import type { RequestHandler } from 'express'; import express from 'express'; -import { OAuthServerProvider } from '../provider.js'; -import { rateLimit, Options as RateLimitOptions } from 'express-rate-limit'; +import type { Options as RateLimitOptions } from 'express-rate-limit'; +import { rateLimit } from 'express-rate-limit'; +import * as z from 'zod/v4'; + import { allowedMethods } from '../middleware/allowedMethods.js'; -import { InvalidRequestError, InvalidClientError, ServerError, TooManyRequestsError, OAuthError } from '../errors.js'; +import type { OAuthServerProvider } from '../provider.js'; export type AuthorizationHandlerOptions = { provider: OAuthServerProvider; @@ -128,7 +130,7 @@ export function authorizationHandler({ provider, rateLimit: rateLimitConfig }: A { state, scopes: requestedScopes, - redirectUri: redirect_uri, + redirectUri: redirect_uri!, // TODO: Someone to look at. Strict tsconfig showed this could be undefined, while the return type is string. codeChallenge: code_challenge, resource: resource ? new URL(resource) : undefined }, @@ -137,10 +139,10 @@ export function authorizationHandler({ provider, rateLimit: rateLimitConfig }: A } catch (error) { // Post-redirect errors - redirect with error parameters if (error instanceof OAuthError) { - res.redirect(302, createErrorRedirect(redirect_uri, error, state)); + res.redirect(302, createErrorRedirect(redirect_uri!, error, state)); } else { const serverError = new ServerError('Internal Server Error'); - res.redirect(302, createErrorRedirect(redirect_uri, serverError, state)); + res.redirect(302, createErrorRedirect(redirect_uri!, serverError, state)); } } }); diff --git a/src/server/auth/handlers/metadata.ts b/packages/server/src/server/auth/handlers/metadata.ts similarity index 76% rename from src/server/auth/handlers/metadata.ts rename to packages/server/src/server/auth/handlers/metadata.ts index e0f07a99b..7583ce624 100644 --- a/src/server/auth/handlers/metadata.ts +++ b/packages/server/src/server/auth/handlers/metadata.ts @@ -1,6 +1,8 @@ -import express, { RequestHandler } from 'express'; -import { OAuthMetadata, OAuthProtectedResourceMetadata } from '../../../shared/auth.js'; +import type { OAuthMetadata, OAuthProtectedResourceMetadata } from '@modelcontextprotocol/sdk-core'; import cors from 'cors'; +import type { RequestHandler } from 'express'; +import express from 'express'; + import { allowedMethods } from '../middleware/allowedMethods.js'; export function metadataHandler(metadata: OAuthMetadata | OAuthProtectedResourceMetadata): RequestHandler { diff --git a/src/server/auth/handlers/register.ts b/packages/server/src/server/auth/handlers/register.ts similarity index 89% rename from src/server/auth/handlers/register.ts rename to packages/server/src/server/auth/handlers/register.ts index 1830619b4..af7570997 100644 --- a/src/server/auth/handlers/register.ts +++ b/packages/server/src/server/auth/handlers/register.ts @@ -1,11 +1,21 @@ -import express, { RequestHandler } from 'express'; -import { OAuthClientInformationFull, OAuthClientMetadataSchema } from '../../../shared/auth.js'; import crypto from 'node:crypto'; + +import type { OAuthClientInformationFull } from '@modelcontextprotocol/sdk-core'; +import { + InvalidClientMetadataError, + OAuthClientMetadataSchema, + OAuthError, + ServerError, + TooManyRequestsError +} from '@modelcontextprotocol/sdk-core'; import cors from 'cors'; -import { OAuthRegisteredClientsStore } from '../clients.js'; -import { rateLimit, Options as RateLimitOptions } from 'express-rate-limit'; +import type { RequestHandler } from 'express'; +import express from 'express'; +import type { Options as RateLimitOptions } from 'express-rate-limit'; +import { rateLimit } from 'express-rate-limit'; + +import type { OAuthRegisteredClientsStore } from '../clients.js'; import { allowedMethods } from '../middleware/allowedMethods.js'; -import { InvalidClientMetadataError, ServerError, TooManyRequestsError, OAuthError } from '../errors.js'; export type ClientRegistrationHandlerOptions = { /** diff --git a/src/server/auth/handlers/revoke.ts b/packages/server/src/server/auth/handlers/revoke.ts similarity index 86% rename from src/server/auth/handlers/revoke.ts rename to packages/server/src/server/auth/handlers/revoke.ts index da7ef04f8..a32d817a9 100644 --- a/src/server/auth/handlers/revoke.ts +++ b/packages/server/src/server/auth/handlers/revoke.ts @@ -1,11 +1,19 @@ -import { OAuthServerProvider } from '../provider.js'; -import express, { RequestHandler } from 'express'; +import { + InvalidRequestError, + OAuthError, + OAuthTokenRevocationRequestSchema, + ServerError, + TooManyRequestsError +} from '@modelcontextprotocol/sdk-core'; import cors from 'cors'; -import { authenticateClient } from '../middleware/clientAuth.js'; -import { OAuthTokenRevocationRequestSchema } from '../../../shared/auth.js'; -import { rateLimit, Options as RateLimitOptions } from 'express-rate-limit'; +import type { RequestHandler } from 'express'; +import express from 'express'; +import type { Options as RateLimitOptions } from 'express-rate-limit'; +import { rateLimit } from 'express-rate-limit'; + import { allowedMethods } from '../middleware/allowedMethods.js'; -import { InvalidRequestError, ServerError, TooManyRequestsError, OAuthError } from '../errors.js'; +import { authenticateClient } from '../middleware/clientAuth.js'; +import type { OAuthServerProvider } from '../provider.js'; export type RevocationHandlerOptions = { provider: OAuthServerProvider; diff --git a/src/server/auth/handlers/token.ts b/packages/server/src/server/auth/handlers/token.ts similarity index 94% rename from src/server/auth/handlers/token.ts rename to packages/server/src/server/auth/handlers/token.ts index 4cc4e8ab8..6a86de283 100644 --- a/src/server/auth/handlers/token.ts +++ b/packages/server/src/server/auth/handlers/token.ts @@ -1,19 +1,22 @@ -import * as z from 'zod/v4'; -import express, { RequestHandler } from 'express'; -import { OAuthServerProvider } from '../provider.js'; -import cors from 'cors'; -import { verifyChallenge } from 'pkce-challenge'; -import { authenticateClient } from '../middleware/clientAuth.js'; -import { rateLimit, Options as RateLimitOptions } from 'express-rate-limit'; -import { allowedMethods } from '../middleware/allowedMethods.js'; import { - InvalidRequestError, InvalidGrantError, - UnsupportedGrantTypeError, + InvalidRequestError, + OAuthError, ServerError, TooManyRequestsError, - OAuthError -} from '../errors.js'; + UnsupportedGrantTypeError +} from '@modelcontextprotocol/sdk-core'; +import cors from 'cors'; +import type { RequestHandler } from 'express'; +import express from 'express'; +import type { Options as RateLimitOptions } from 'express-rate-limit'; +import { rateLimit } from 'express-rate-limit'; +import { verifyChallenge } from 'pkce-challenge'; +import * as z from 'zod/v4'; + +import { allowedMethods } from '../middleware/allowedMethods.js'; +import { authenticateClient } from '../middleware/clientAuth.js'; +import type { OAuthServerProvider } from '../provider.js'; export type TokenHandlerOptions = { provider: OAuthServerProvider; diff --git a/packages/server/src/server/auth/index.ts b/packages/server/src/server/auth/index.ts new file mode 100644 index 000000000..5369224cf --- /dev/null +++ b/packages/server/src/server/auth/index.ts @@ -0,0 +1,12 @@ +export * from './clients.js'; +export * from './handlers/authorize.js'; +export * from './handlers/metadata.js'; +export * from './handlers/register.js'; +export * from './handlers/revoke.js'; +export * from './handlers/token.js'; +export * from './middleware/allowedMethods.js'; +export * from './middleware/bearerAuth.js'; +export * from './middleware/clientAuth.js'; +export * from './provider.js'; +export * from './providers/proxyProvider.js'; +export * from './router.js'; diff --git a/src/server/auth/middleware/allowedMethods.ts b/packages/server/src/server/auth/middleware/allowedMethods.ts similarity index 85% rename from src/server/auth/middleware/allowedMethods.ts rename to packages/server/src/server/auth/middleware/allowedMethods.ts index 74633aa57..54e1671e4 100644 --- a/src/server/auth/middleware/allowedMethods.ts +++ b/packages/server/src/server/auth/middleware/allowedMethods.ts @@ -1,5 +1,5 @@ -import { RequestHandler } from 'express'; -import { MethodNotAllowedError } from '../errors.js'; +import { MethodNotAllowedError } from '@modelcontextprotocol/sdk-core'; +import type { RequestHandler } from 'express'; /** * Middleware to handle unsupported HTTP methods with a 405 Method Not Allowed response. diff --git a/src/server/auth/middleware/bearerAuth.ts b/packages/server/src/server/auth/middleware/bearerAuth.ts similarity index 93% rename from src/server/auth/middleware/bearerAuth.ts rename to packages/server/src/server/auth/middleware/bearerAuth.ts index dac653086..97abcccaf 100644 --- a/src/server/auth/middleware/bearerAuth.ts +++ b/packages/server/src/server/auth/middleware/bearerAuth.ts @@ -1,7 +1,8 @@ -import { RequestHandler } from 'express'; -import { InsufficientScopeError, InvalidTokenError, OAuthError, ServerError } from '../errors.js'; -import { OAuthTokenVerifier } from '../provider.js'; -import { AuthInfo } from '../types.js'; +import type { AuthInfo } from '@modelcontextprotocol/sdk-core'; +import { InsufficientScopeError, InvalidTokenError, OAuthError, ServerError } from '@modelcontextprotocol/sdk-core'; +import type { RequestHandler } from 'express'; + +import type { OAuthTokenVerifier } from '../provider.js'; export type BearerAuthMiddlewareOptions = { /** @@ -46,7 +47,7 @@ export function requireBearerAuth({ verifier, requiredScopes = [], resourceMetad } const [type, token] = authHeader.split(' '); - if (type.toLowerCase() !== 'bearer' || !token) { + if (type!.toLowerCase() !== 'bearer' || !token) { throw new InvalidTokenError("Invalid Authorization header format, expected 'Bearer TOKEN'"); } diff --git a/src/server/auth/middleware/clientAuth.ts b/packages/server/src/server/auth/middleware/clientAuth.ts similarity index 87% rename from src/server/auth/middleware/clientAuth.ts rename to packages/server/src/server/auth/middleware/clientAuth.ts index 6cc6a1923..6e4a09e24 100644 --- a/src/server/auth/middleware/clientAuth.ts +++ b/packages/server/src/server/auth/middleware/clientAuth.ts @@ -1,8 +1,9 @@ +import type { OAuthClientInformationFull } from '@modelcontextprotocol/sdk-core'; +import { InvalidClientError, InvalidRequestError, OAuthError, ServerError } from '@modelcontextprotocol/sdk-core'; +import type { RequestHandler } from 'express'; import * as z from 'zod/v4'; -import { RequestHandler } from 'express'; -import { OAuthRegisteredClientsStore } from '../clients.js'; -import { OAuthClientInformationFull } from '../../../shared/auth.js'; -import { InvalidRequestError, InvalidClientError, ServerError, OAuthError } from '../errors.js'; + +import type { OAuthRegisteredClientsStore } from '../clients.js'; export type ClientAuthenticationMiddlewareOptions = { /** diff --git a/src/server/auth/provider.ts b/packages/server/src/server/auth/provider.ts similarity index 92% rename from src/server/auth/provider.ts rename to packages/server/src/server/auth/provider.ts index cf1c306de..3cde1c5e1 100644 --- a/src/server/auth/provider.ts +++ b/packages/server/src/server/auth/provider.ts @@ -1,7 +1,7 @@ -import { Response } from 'express'; -import { OAuthRegisteredClientsStore } from './clients.js'; -import { OAuthClientInformationFull, OAuthTokenRevocationRequest, OAuthTokens } from '../../shared/auth.js'; -import { AuthInfo } from './types.js'; +import type { AuthInfo, OAuthClientInformationFull, OAuthTokenRevocationRequest, OAuthTokens } from '@modelcontextprotocol/sdk-core'; +import type { Response } from 'express'; + +import type { OAuthRegisteredClientsStore } from './clients.js'; export type AuthorizationParams = { state?: string; diff --git a/src/server/auth/providers/proxyProvider.ts b/packages/server/src/server/auth/providers/proxyProvider.ts similarity index 94% rename from src/server/auth/providers/proxyProvider.ts rename to packages/server/src/server/auth/providers/proxyProvider.ts index 855856c89..b2f22a451 100644 --- a/src/server/auth/providers/proxyProvider.ts +++ b/packages/server/src/server/auth/providers/proxyProvider.ts @@ -1,16 +1,15 @@ -import { Response } from 'express'; -import { OAuthRegisteredClientsStore } from '../clients.js'; -import { +import type { + AuthInfo, + FetchLike, OAuthClientInformationFull, - OAuthClientInformationFullSchema, OAuthTokenRevocationRequest, - OAuthTokens, - OAuthTokensSchema -} from '../../../shared/auth.js'; -import { AuthInfo } from '../types.js'; -import { AuthorizationParams, OAuthServerProvider } from '../provider.js'; -import { ServerError } from '../errors.js'; -import { FetchLike } from '../../../shared/transport.js'; + OAuthTokens +} from '@modelcontextprotocol/sdk-core'; +import { OAuthClientInformationFullSchema, OAuthTokensSchema, ServerError } from '@modelcontextprotocol/sdk-core'; +import type { Response } from 'express'; + +import type { OAuthRegisteredClientsStore } from '../clients.js'; +import type { AuthorizationParams, OAuthServerProvider } from '../provider.js'; export type ProxyEndpoints = { authorizationUrl: string; diff --git a/src/server/auth/router.ts b/packages/server/src/server/auth/router.ts similarity index 91% rename from src/server/auth/router.ts rename to packages/server/src/server/auth/router.ts index 1df0be091..3f820396c 100644 --- a/src/server/auth/router.ts +++ b/packages/server/src/server/auth/router.ts @@ -1,11 +1,17 @@ -import express, { RequestHandler } from 'express'; -import { clientRegistrationHandler, ClientRegistrationHandlerOptions } from './handlers/register.js'; -import { tokenHandler, TokenHandlerOptions } from './handlers/token.js'; -import { authorizationHandler, AuthorizationHandlerOptions } from './handlers/authorize.js'; -import { revocationHandler, RevocationHandlerOptions } from './handlers/revoke.js'; +import type { OAuthMetadata, OAuthProtectedResourceMetadata } from '@modelcontextprotocol/sdk-core'; +import type { RequestHandler } from 'express'; +import express from 'express'; + +import type { AuthorizationHandlerOptions } from './handlers/authorize.js'; +import { authorizationHandler } from './handlers/authorize.js'; import { metadataHandler } from './handlers/metadata.js'; -import { OAuthServerProvider } from './provider.js'; -import { OAuthMetadata, OAuthProtectedResourceMetadata } from '../../shared/auth.js'; +import type { ClientRegistrationHandlerOptions } from './handlers/register.js'; +import { clientRegistrationHandler } from './handlers/register.js'; +import type { RevocationHandlerOptions } from './handlers/revoke.js'; +import { revocationHandler } from './handlers/revoke.js'; +import type { TokenHandlerOptions } from './handlers/token.js'; +import { tokenHandler } from './handlers/token.js'; +import type { OAuthServerProvider } from './provider.js'; // Check for dev mode flag that allows HTTP issuer URLs (for development/testing only) const allowInsecureIssuerUrl = diff --git a/src/server/completable.ts b/packages/server/src/server/completable.ts similarity index 96% rename from src/server/completable.ts rename to packages/server/src/server/completable.ts index be067ac55..72e191cc2 100644 --- a/src/server/completable.ts +++ b/packages/server/src/server/completable.ts @@ -1,4 +1,4 @@ -import { AnySchema, SchemaInput } from './zod-compat.js'; +import type { AnySchema, SchemaInput } from '@modelcontextprotocol/sdk-core'; export const COMPLETABLE_SYMBOL: unique symbol = Symbol.for('mcp.completable'); diff --git a/src/server/express.ts b/packages/server/src/server/express.ts similarity index 97% rename from src/server/express.ts rename to packages/server/src/server/express.ts index a542acd7a..ff23cde85 100644 --- a/src/server/express.ts +++ b/packages/server/src/server/express.ts @@ -1,4 +1,6 @@ -import express, { Express } from 'express'; +import type { Express } from 'express'; +import express from 'express'; + import { hostHeaderValidation, localhostHostValidation } from './middleware/hostHeaderValidation.js'; /** diff --git a/packages/server/src/server/inMemoryEventStore.ts b/packages/server/src/server/inMemoryEventStore.ts new file mode 100644 index 000000000..45c1e4d89 --- /dev/null +++ b/packages/server/src/server/inMemoryEventStore.ts @@ -0,0 +1,79 @@ +import type { JSONRPCMessage } from '@modelcontextprotocol/sdk-core'; + +import type { EventStore } from './streamableHttp.js'; + +/** + * Simple in-memory implementation of the EventStore interface for resumability + * This is primarily intended for examples and testing, not for production use + * where a persistent storage solution would be more appropriate. + */ +export class InMemoryEventStore implements EventStore { + private events: Map = new Map(); + + /** + * Generates a unique event ID for a given stream ID + */ + private generateEventId(streamId: string): string { + return `${streamId}_${Date.now()}_${Math.random().toString(36).substring(2, 10)}`; + } + + /** + * Extracts the stream ID from an event ID + */ + private getStreamIdFromEventId(eventId: string): string { + const parts = eventId.split('_'); + return parts.length > 0 ? parts[0]! : ''; + } + + /** + * Stores an event with a generated event ID + * Implements EventStore.storeEvent + */ + async storeEvent(streamId: string, message: JSONRPCMessage): Promise { + const eventId = this.generateEventId(streamId); + this.events.set(eventId, { streamId, message }); + return eventId; + } + + /** + * Replays events that occurred after a specific event ID + * Implements EventStore.replayEventsAfter + */ + async replayEventsAfter( + lastEventId: string, + { send }: { send: (eventId: string, message: JSONRPCMessage) => Promise } + ): Promise { + if (!lastEventId || !this.events.has(lastEventId)) { + return ''; + } + + // Extract the stream ID from the event ID + const streamId = this.getStreamIdFromEventId(lastEventId); + if (!streamId) { + return ''; + } + + let foundLastEvent = false; + + // Sort events by eventId for chronological ordering + const sortedEvents = [...this.events.entries()].sort((a, b) => a[0].localeCompare(b[0])); + + for (const [eventId, { streamId: eventStreamId, message }] of sortedEvents) { + // Only include events from the same stream + if (eventStreamId !== streamId) { + continue; + } + + // Start sending events after we find the lastEventId + if (eventId === lastEventId) { + foundLastEvent = true; + continue; + } + + if (foundLastEvent) { + await send(eventId, message); + } + } + return streamId; + } +} diff --git a/src/server/mcp.ts b/packages/server/src/server/mcp.ts similarity index 99% rename from src/server/mcp.ts rename to packages/server/src/server/mcp.ts index 7e61b4364..f569f2c83 100644 --- a/src/server/mcp.ts +++ b/packages/server/src/server/mcp.ts @@ -1,69 +1,71 @@ -import { Server, ServerOptions } from './index.js'; -import { - AnySchema, +import type { AnyObjectSchema, - ZodRawShapeCompat, - SchemaOutput, - ShapeOutput, - normalizeObjectSchema, - safeParseAsync, - getObjectShape, - objectFromShape, - getParseErrorMessage, - getSchemaDescription, - isSchemaOptional, - getLiteralValue -} from './zod-compat.js'; -import { toJsonSchemaCompat } from './zod-json-schema-compat.js'; -import { - Implementation, - Tool, - ListToolsResult, + AnySchema, + BaseMetadata, + CallToolRequest, CallToolResult, - McpError, - ErrorCode, + CompleteRequestPrompt, + CompleteRequestResourceTemplate, CompleteResult, - PromptReference, - ResourceTemplateReference, - BaseMetadata, - Resource, - ListResourcesResult, - ListResourceTemplatesRequestSchema, - ReadResourceRequestSchema, - ListToolsRequestSchema, - CallToolRequestSchema, - ListResourcesRequestSchema, - ListPromptsRequestSchema, - GetPromptRequestSchema, - CompleteRequestSchema, + CreateTaskResult, + GetPromptResult, + Implementation, ListPromptsResult, + ListResourcesResult, + ListToolsResult, + LoggingMessageNotification, Prompt, PromptArgument, - GetPromptResult, + PromptReference, ReadResourceResult, - ServerRequest, + RequestHandlerExtra, + Resource, + ResourceTemplateReference, + Result, + SchemaOutput, ServerNotification, + ServerRequest, + ShapeOutput, + Tool, ToolAnnotations, - LoggingMessageNotification, - CreateTaskResult, - Result, - CompleteRequestPrompt, - CompleteRequestResourceTemplate, + ToolExecution, + Transport, + Variables, + ZodRawShapeCompat +} from '@modelcontextprotocol/sdk-core'; +import { assertCompleteRequestPrompt, assertCompleteRequestResourceTemplate, - CallToolRequest, - ToolExecution -} from '../types.js'; -import { isCompletable, getCompleter } from './completable.js'; -import { UriTemplate, Variables } from '../shared/uriTemplate.js'; -import { RequestHandlerExtra } from '../shared/protocol.js'; -import { Transport } from '../shared/transport.js'; - -import { validateAndWarnToolName } from '../shared/toolNameValidation.js'; -import { ExperimentalMcpServerTasks } from '../experimental/tasks/mcp-server.js'; -import type { ToolTaskHandler } from '../experimental/tasks/interfaces.js'; + CallToolRequestSchema, + CompleteRequestSchema, + ErrorCode, + getLiteralValue, + getObjectShape, + getParseErrorMessage, + GetPromptRequestSchema, + getSchemaDescription, + isSchemaOptional, + ListPromptsRequestSchema, + ListResourcesRequestSchema, + ListResourceTemplatesRequestSchema, + ListToolsRequestSchema, + McpError, + normalizeObjectSchema, + objectFromShape, + ReadResourceRequestSchema, + safeParseAsync, + toJsonSchemaCompat, + UriTemplate, + validateAndWarnToolName +} from '@modelcontextprotocol/sdk-core'; import { ZodOptional } from 'zod'; +import type { ToolTaskHandler } from '../experimental/tasks/interfaces.js'; +import { ExperimentalMcpServerTasks } from '../experimental/tasks/mcp-server.js'; +import { getCompleter, isCompletable } from './completable.js'; +import type { ServerOptions } from './server.js'; +import { Server } from './server.js'; + /** * High-level MCP server that provides a simpler API for working with resources, tools, and prompts. * For advanced usage (like sending notifications or setting custom request handlers), use the underlying diff --git a/src/server/middleware/hostHeaderValidation.ts b/packages/server/src/server/middleware/hostHeaderValidation.ts similarity index 96% rename from src/server/middleware/hostHeaderValidation.ts rename to packages/server/src/server/middleware/hostHeaderValidation.ts index 165003635..f46178db3 100644 --- a/src/server/middleware/hostHeaderValidation.ts +++ b/packages/server/src/server/middleware/hostHeaderValidation.ts @@ -1,4 +1,4 @@ -import { Request, Response, NextFunction, RequestHandler } from 'express'; +import type { NextFunction, Request, RequestHandler, Response } from 'express'; /** * Express middleware for DNS rebinding protection. diff --git a/src/server/index.ts b/packages/server/src/server/server.ts similarity index 95% rename from src/server/index.ts rename to packages/server/src/server/server.ts index 531a559dd..9ecf1e04d 100644 --- a/src/server/index.ts +++ b/packages/server/src/server/server.ts @@ -1,61 +1,68 @@ -import { mergeCapabilities, Protocol, type NotificationOptions, type ProtocolOptions, type RequestOptions } from '../shared/protocol.js'; +import type { + AnyObjectSchema, + ClientCapabilities, + CreateMessageRequest, + CreateMessageRequestParamsBase, + CreateMessageRequestParamsWithTools, + CreateMessageResult, + CreateMessageResultWithTools, + ElicitRequestFormParams, + ElicitRequestURLParams, + ElicitResult, + Implementation, + InitializeRequest, + InitializeResult, + JsonSchemaType, + jsonSchemaValidator, + ListRootsRequest, + LoggingLevel, + LoggingMessageNotification, + Notification, + NotificationOptions, + ProtocolOptions, + Request, + RequestHandlerExtra, + RequestOptions, + ResourceUpdatedNotification, + Result, + SchemaOutput, + ServerCapabilities, + ServerNotification, + ServerRequest, + ServerResult, + ToolResultContent, + ToolUseContent, + ZodV3Internal, + ZodV4Internal +} from '@modelcontextprotocol/sdk-core'; import { - type ClientCapabilities, - type CreateMessageRequest, - type CreateMessageResult, + AjvJsonSchemaValidator, + assertClientRequestTaskCapability, + assertToolsCallTaskCapability, + CallToolRequestSchema, + CallToolResultSchema, CreateMessageResultSchema, - type CreateMessageResultWithTools, CreateMessageResultWithToolsSchema, - type CreateMessageRequestParamsBase, - type CreateMessageRequestParamsWithTools, - type ElicitRequestFormParams, - type ElicitRequestURLParams, - type ElicitResult, + CreateTaskResultSchema, ElicitResultSchema, EmptyResultSchema, ErrorCode, - type Implementation, + getObjectShape, InitializedNotificationSchema, - type InitializeRequest, InitializeRequestSchema, - type InitializeResult, + isZ4Schema, LATEST_PROTOCOL_VERSION, - type ListRootsRequest, ListRootsResultSchema, - type LoggingLevel, LoggingLevelSchema, - type LoggingMessageNotification, McpError, - type ResourceUpdatedNotification, - type ServerCapabilities, - type ServerNotification, - type ServerRequest, - type ServerResult, - SetLevelRequestSchema, - SUPPORTED_PROTOCOL_VERSIONS, - type ToolResultContent, - type ToolUseContent, - CallToolRequestSchema, - CallToolResultSchema, - CreateTaskResultSchema, - type Request, - type Notification, - type Result -} from '../types.js'; -import { AjvJsonSchemaValidator } from '../validation/ajv-provider.js'; -import type { JsonSchemaType, jsonSchemaValidator } from '../validation/types.js'; -import { - AnyObjectSchema, - getObjectShape, - isZ4Schema, + mergeCapabilities, + Protocol, safeParse, - SchemaOutput, - type ZodV3Internal, - type ZodV4Internal -} from './zod-compat.js'; -import { RequestHandlerExtra } from '../shared/protocol.js'; + SetLevelRequestSchema, + SUPPORTED_PROTOCOL_VERSIONS +} from '@modelcontextprotocol/sdk-core'; + import { ExperimentalServerTasks } from '../experimental/tasks/server.js'; -import { assertToolsCallTaskCapability, assertClientRequestTaskCapability } from '../experimental/tasks/helpers.js'; export type ServerOptions = ProtocolOptions & { /** @@ -509,7 +516,7 @@ export class Server< // These may appear even without tools/toolChoice in the current request when // a previous sampling request returned tool_use and this is a follow-up with results. if (params.messages.length > 0) { - const lastMessage = params.messages[params.messages.length - 1]; + const lastMessage = params.messages[params.messages.length - 1]!; const lastContent = Array.isArray(lastMessage.content) ? lastMessage.content : [lastMessage.content]; const hasToolResults = lastContent.some(c => c.type === 'tool_result'); diff --git a/src/server/sse.ts b/packages/server/src/server/sse.ts similarity index 96% rename from src/server/sse.ts rename to packages/server/src/server/sse.ts index b7450a09e..8afeb7de8 100644 --- a/src/server/sse.ts +++ b/packages/server/src/server/sse.ts @@ -1,12 +1,12 @@ import { randomUUID } from 'node:crypto'; -import { IncomingMessage, ServerResponse } from 'node:http'; -import { Transport } from '../shared/transport.js'; -import { JSONRPCMessage, JSONRPCMessageSchema, MessageExtraInfo, RequestInfo } from '../types.js'; -import getRawBody from 'raw-body'; -import contentType from 'content-type'; -import { AuthInfo } from './auth/types.js'; +import type { IncomingMessage, ServerResponse } from 'node:http'; import { URL } from 'node:url'; +import type { AuthInfo, JSONRPCMessage, MessageExtraInfo, RequestInfo, Transport } from '@modelcontextprotocol/sdk-core'; +import { JSONRPCMessageSchema } from '@modelcontextprotocol/sdk-core'; +import contentType from 'content-type'; +import getRawBody from 'raw-body'; + const MAXIMUM_MESSAGE_SIZE = '4mb'; /** diff --git a/src/server/stdio.ts b/packages/server/src/server/stdio.ts similarity index 92% rename from src/server/stdio.ts rename to packages/server/src/server/stdio.ts index e552af0fa..f6fce4568 100644 --- a/src/server/stdio.ts +++ b/packages/server/src/server/stdio.ts @@ -1,8 +1,8 @@ import process from 'node:process'; -import { Readable, Writable } from 'node:stream'; -import { ReadBuffer, serializeMessage } from '../shared/stdio.js'; -import { JSONRPCMessage } from '../types.js'; -import { Transport } from '../shared/transport.js'; +import type { Readable, Writable } from 'node:stream'; + +import type { JSONRPCMessage, Transport } from '@modelcontextprotocol/sdk-core'; +import { ReadBuffer, serializeMessage } from '@modelcontextprotocol/sdk-core'; /** * Server transport for stdio: this communicates with an MCP client by reading from the current process' stdin and writing to stdout. diff --git a/src/server/streamableHttp.ts b/packages/server/src/server/streamableHttp.ts similarity index 99% rename from src/server/streamableHttp.ts rename to packages/server/src/server/streamableHttp.ts index ab1131f63..1f7d31dde 100644 --- a/src/server/streamableHttp.ts +++ b/packages/server/src/server/streamableHttp.ts @@ -1,22 +1,18 @@ -import { IncomingMessage, ServerResponse } from 'node:http'; -import { Transport } from '../shared/transport.js'; +import { randomUUID } from 'node:crypto'; +import type { IncomingMessage, ServerResponse } from 'node:http'; + +import type { AuthInfo, JSONRPCMessage, MessageExtraInfo, RequestId, RequestInfo, Transport } from '@modelcontextprotocol/sdk-core'; import { - MessageExtraInfo, - RequestInfo, + DEFAULT_NEGOTIATED_PROTOCOL_VERSION, isInitializeRequest, + isJSONRPCErrorResponse, isJSONRPCRequest, isJSONRPCResultResponse, - JSONRPCMessage, JSONRPCMessageSchema, - RequestId, - SUPPORTED_PROTOCOL_VERSIONS, - DEFAULT_NEGOTIATED_PROTOCOL_VERSION, - isJSONRPCErrorResponse -} from '../types.js'; -import getRawBody from 'raw-body'; + SUPPORTED_PROTOCOL_VERSIONS +} from '@modelcontextprotocol/sdk-core'; import contentType from 'content-type'; -import { randomUUID } from 'node:crypto'; -import { AuthInfo } from './auth/types.js'; +import getRawBody from 'raw-body'; const MAXIMUM_MESSAGE_SIZE = '4mb'; diff --git a/packages/server/test/server/__fixtures__/zodTestMatrix.ts b/packages/server/test/server/__fixtures__/zodTestMatrix.ts new file mode 100644 index 000000000..fc4ee63db --- /dev/null +++ b/packages/server/test/server/__fixtures__/zodTestMatrix.ts @@ -0,0 +1,22 @@ +import * as z3 from 'zod/v3'; +import * as z4 from 'zod/v4'; + +// Shared Zod namespace type that exposes the common surface area used in tests. +export type ZNamespace = typeof z3 & typeof z4; + +export const zodTestMatrix = [ + { + zodVersionLabel: 'Zod v3', + z: z3 as ZNamespace, + isV3: true as const, + isV4: false as const + }, + { + zodVersionLabel: 'Zod v4', + z: z4 as ZNamespace, + isV3: false as const, + isV4: true as const + } +] as const; + +export type ZodMatrixEntry = (typeof zodTestMatrix)[number]; diff --git a/test/server/auth/handlers/authorize.test.ts b/packages/server/test/server/auth/handlers/authorize.test.ts similarity index 93% rename from test/server/auth/handlers/authorize.test.ts rename to packages/server/test/server/auth/handlers/authorize.test.ts index 0f831ae7d..a718f8e53 100644 --- a/test/server/auth/handlers/authorize.test.ts +++ b/packages/server/test/server/auth/handlers/authorize.test.ts @@ -1,11 +1,11 @@ import { authorizationHandler, AuthorizationHandlerOptions } from '../../../../src/server/auth/handlers/authorize.js'; import { OAuthServerProvider, AuthorizationParams } from '../../../../src/server/auth/provider.js'; import { OAuthRegisteredClientsStore } from '../../../../src/server/auth/clients.js'; -import { OAuthClientInformationFull, OAuthTokens } from '../../../../src/shared/auth.js'; +import { OAuthClientInformationFull, OAuthTokens } from '@modelcontextprotocol/sdk-core'; import express, { Response } from 'express'; import supertest from 'supertest'; -import { AuthInfo } from '../../../../src/server/auth/types.js'; -import { InvalidTokenError } from '../../../../src/server/auth/errors.js'; +import { AuthInfo } from '@modelcontextprotocol/sdk-core'; +import { InvalidTokenError } from '@modelcontextprotocol/sdk-core'; describe('Authorization Handler', () => { // Mock client data @@ -132,7 +132,7 @@ describe('Authorization Handler', () => { }); expect(response.status).toBe(302); - const location = new URL(response.header.location); + const location = new URL(response.header.location!); expect(location.origin + location.pathname).toBe('https://example.com/callback'); }); @@ -169,7 +169,7 @@ describe('Authorization Handler', () => { }); expect(response.status).toBe(302); - const location = new URL(response.header.location); + const location = new URL(response.header.location!); expect(location.origin + location.pathname).toBe('https://example.com/callback'); }); }); @@ -185,7 +185,7 @@ describe('Authorization Handler', () => { }); expect(response.status).toBe(302); - const location = new URL(response.header.location); + const location = new URL(response.header.location!); expect(location.searchParams.get('error')).toBe('invalid_request'); }); @@ -199,7 +199,7 @@ describe('Authorization Handler', () => { }); expect(response.status).toBe(302); - const location = new URL(response.header.location); + const location = new URL(response.header.location!); expect(location.searchParams.get('error')).toBe('invalid_request'); }); @@ -213,7 +213,7 @@ describe('Authorization Handler', () => { }); expect(response.status).toBe(302); - const location = new URL(response.header.location); + const location = new URL(response.header.location!); expect(location.searchParams.get('error')).toBe('invalid_request'); }); }); @@ -257,7 +257,7 @@ describe('Authorization Handler', () => { }); expect(response.status).toBe(302); - const location = new URL(response.header.location); + const location = new URL(response.header.location!); expect(location.origin + location.pathname).toBe('https://example.com/callback'); expect(location.searchParams.get('code')).toBe('mock_auth_code'); expect(location.searchParams.get('state')).toBe('xyz789'); @@ -274,7 +274,7 @@ describe('Authorization Handler', () => { }); expect(response.status).toBe(302); - const location = new URL(response.header.location); + const location = new URL(response.header.location!); expect(location.searchParams.get('state')).toBe('state-value-123'); }); @@ -287,7 +287,7 @@ describe('Authorization Handler', () => { }); expect(response.status).toBe(302); - const location = new URL(response.header.location); + const location = new URL(response.header.location!); expect(location.searchParams.has('code')).toBe(true); }); }); diff --git a/test/server/auth/handlers/metadata.test.ts b/packages/server/test/server/auth/handlers/metadata.test.ts similarity index 97% rename from test/server/auth/handlers/metadata.test.ts rename to packages/server/test/server/auth/handlers/metadata.test.ts index 2eb7693f2..1472548d1 100644 --- a/test/server/auth/handlers/metadata.test.ts +++ b/packages/server/test/server/auth/handlers/metadata.test.ts @@ -1,5 +1,5 @@ import { metadataHandler } from '../../../../src/server/auth/handlers/metadata.js'; -import { OAuthMetadata } from '../../../../src/shared/auth.js'; +import type { OAuthMetadata } from '@modelcontextprotocol/sdk-core'; import express from 'express'; import supertest from 'supertest'; diff --git a/test/server/auth/handlers/register.test.ts b/packages/server/test/server/auth/handlers/register.test.ts similarity index 99% rename from test/server/auth/handlers/register.test.ts rename to packages/server/test/server/auth/handlers/register.test.ts index 03fde46d2..a769ba84d 100644 --- a/test/server/auth/handlers/register.test.ts +++ b/packages/server/test/server/auth/handlers/register.test.ts @@ -1,6 +1,6 @@ import { clientRegistrationHandler, ClientRegistrationHandlerOptions } from '../../../../src/server/auth/handlers/register.js'; import { OAuthRegisteredClientsStore } from '../../../../src/server/auth/clients.js'; -import { OAuthClientInformationFull, OAuthClientMetadata } from '../../../../src/shared/auth.js'; +import type { OAuthClientInformationFull, OAuthClientMetadata } from '@modelcontextprotocol/sdk-core'; import express from 'express'; import supertest from 'supertest'; import { MockInstance } from 'vitest'; diff --git a/test/server/auth/handlers/revoke.test.ts b/packages/server/test/server/auth/handlers/revoke.test.ts similarity index 97% rename from test/server/auth/handlers/revoke.test.ts rename to packages/server/test/server/auth/handlers/revoke.test.ts index 69cac83d9..7c59f9334 100644 --- a/test/server/auth/handlers/revoke.test.ts +++ b/packages/server/test/server/auth/handlers/revoke.test.ts @@ -1,11 +1,11 @@ import { revocationHandler, RevocationHandlerOptions } from '../../../../src/server/auth/handlers/revoke.js'; import { OAuthServerProvider, AuthorizationParams } from '../../../../src/server/auth/provider.js'; import { OAuthRegisteredClientsStore } from '../../../../src/server/auth/clients.js'; -import { OAuthClientInformationFull, OAuthTokenRevocationRequest, OAuthTokens } from '../../../../src/shared/auth.js'; +import { OAuthClientInformationFull, OAuthTokenRevocationRequest, OAuthTokens } from '@modelcontextprotocol/sdk-core'; import express, { Response } from 'express'; import supertest from 'supertest'; -import { AuthInfo } from '../../../../src/server/auth/types.js'; -import { InvalidTokenError } from '../../../../src/server/auth/errors.js'; +import { AuthInfo } from '@modelcontextprotocol/sdk-core'; +import { InvalidTokenError } from '@modelcontextprotocol/sdk-core'; import { MockInstance } from 'vitest'; describe('Revocation Handler', () => { diff --git a/test/server/auth/handlers/token.test.ts b/packages/server/test/server/auth/handlers/token.test.ts similarity index 98% rename from test/server/auth/handlers/token.test.ts rename to packages/server/test/server/auth/handlers/token.test.ts index 658142b4b..dc7a2f813 100644 --- a/test/server/auth/handlers/token.test.ts +++ b/packages/server/test/server/auth/handlers/token.test.ts @@ -1,12 +1,12 @@ import { tokenHandler, TokenHandlerOptions } from '../../../../src/server/auth/handlers/token.js'; import { OAuthServerProvider, AuthorizationParams } from '../../../../src/server/auth/provider.js'; import { OAuthRegisteredClientsStore } from '../../../../src/server/auth/clients.js'; -import { OAuthClientInformationFull, OAuthTokenRevocationRequest, OAuthTokens } from '../../../../src/shared/auth.js'; +import { OAuthClientInformationFull, OAuthTokenRevocationRequest, OAuthTokens } from '@modelcontextprotocol/sdk-core'; import express, { Response } from 'express'; import supertest from 'supertest'; import * as pkceChallenge from 'pkce-challenge'; -import { InvalidGrantError, InvalidTokenError } from '../../../../src/server/auth/errors.js'; -import { AuthInfo } from '../../../../src/server/auth/types.js'; +import { InvalidGrantError, InvalidTokenError } from '@modelcontextprotocol/sdk-core'; +import { AuthInfo } from '@modelcontextprotocol/sdk-core'; import { ProxyOAuthServerProvider } from '../../../../src/server/auth/providers/proxyProvider.js'; import { type Mock } from 'vitest'; diff --git a/test/server/auth/middleware/allowedMethods.test.ts b/packages/server/test/server/auth/middleware/allowedMethods.test.ts similarity index 100% rename from test/server/auth/middleware/allowedMethods.test.ts rename to packages/server/test/server/auth/middleware/allowedMethods.test.ts diff --git a/test/server/auth/middleware/bearerAuth.test.ts b/packages/server/test/server/auth/middleware/bearerAuth.test.ts similarity index 99% rename from test/server/auth/middleware/bearerAuth.test.ts rename to packages/server/test/server/auth/middleware/bearerAuth.test.ts index 68162be9b..71f575dbb 100644 --- a/test/server/auth/middleware/bearerAuth.test.ts +++ b/packages/server/test/server/auth/middleware/bearerAuth.test.ts @@ -1,10 +1,10 @@ import { Request, Response } from 'express'; import { Mock } from 'vitest'; import { requireBearerAuth } from '../../../../src/server/auth/middleware/bearerAuth.js'; -import { AuthInfo } from '../../../../src/server/auth/types.js'; -import { InsufficientScopeError, InvalidTokenError, CustomOAuthError, ServerError } from '../../../../src/server/auth/errors.js'; +import { AuthInfo } from '@modelcontextprotocol/sdk-core'; +import { InsufficientScopeError, InvalidTokenError, CustomOAuthError, ServerError } from '@modelcontextprotocol/sdk-core'; import { OAuthTokenVerifier } from '../../../../src/server/auth/provider.js'; -import { createExpressResponseMock } from '../../../helpers/http.js'; +import { createExpressResponseMock } from '../../../../../integration/test/helpers/http.js'; // Mock verifier const mockVerifyAccessToken = vi.fn(); diff --git a/test/server/auth/middleware/clientAuth.test.ts b/packages/server/test/server/auth/middleware/clientAuth.test.ts similarity index 98% rename from test/server/auth/middleware/clientAuth.test.ts rename to packages/server/test/server/auth/middleware/clientAuth.test.ts index 50cc1d907..48eb82d32 100644 --- a/test/server/auth/middleware/clientAuth.test.ts +++ b/packages/server/test/server/auth/middleware/clientAuth.test.ts @@ -1,6 +1,6 @@ import { authenticateClient, ClientAuthenticationMiddlewareOptions } from '../../../../src/server/auth/middleware/clientAuth.js'; import { OAuthRegisteredClientsStore } from '../../../../src/server/auth/clients.js'; -import { OAuthClientInformationFull } from '../../../../src/shared/auth.js'; +import type { OAuthClientInformationFull } from '@modelcontextprotocol/sdk-core'; import express from 'express'; import supertest from 'supertest'; diff --git a/test/server/auth/providers/proxyProvider.test.ts b/packages/server/test/server/auth/providers/proxyProvider.test.ts similarity index 96% rename from test/server/auth/providers/proxyProvider.test.ts rename to packages/server/test/server/auth/providers/proxyProvider.test.ts index 40fb55d57..9ae4aab1b 100644 --- a/test/server/auth/providers/proxyProvider.test.ts +++ b/packages/server/test/server/auth/providers/proxyProvider.test.ts @@ -1,10 +1,10 @@ import { Response } from 'express'; import { ProxyOAuthServerProvider, ProxyOptions } from '../../../../src/server/auth/providers/proxyProvider.js'; -import { AuthInfo } from '../../../../src/server/auth/types.js'; -import { OAuthClientInformationFull, OAuthTokens } from '../../../../src/shared/auth.js'; -import { ServerError } from '../../../../src/server/auth/errors.js'; -import { InvalidTokenError } from '../../../../src/server/auth/errors.js'; -import { InsufficientScopeError } from '../../../../src/server/auth/errors.js'; +import { AuthInfo } from '@modelcontextprotocol/sdk-core'; +import { OAuthClientInformationFull, OAuthTokens } from '@modelcontextprotocol/sdk-core'; +import { ServerError } from '@modelcontextprotocol/sdk-core'; +import { InvalidTokenError } from '@modelcontextprotocol/sdk-core'; +import { InsufficientScopeError } from '@modelcontextprotocol/sdk-core'; import { type Mock } from 'vitest'; describe('Proxy OAuth Server Provider', () => { @@ -184,7 +184,7 @@ describe('Proxy OAuth Server Provider', () => { const tokens = await provider.exchangeAuthorizationCode(validClient, 'test-code', 'test-verifier'); const fetchCall = (global.fetch as Mock).mock.calls[0]; - const body = fetchCall[1].body as string; + const body = fetchCall![1].body as string; expect(body).not.toContain('resource='); expect(tokens).toEqual(mockTokenResponse); }); diff --git a/test/server/auth/router.test.ts b/packages/server/test/server/auth/router.test.ts similarity index 98% rename from test/server/auth/router.test.ts rename to packages/server/test/server/auth/router.test.ts index 521c650c4..41f14ba8f 100644 --- a/test/server/auth/router.test.ts +++ b/packages/server/test/server/auth/router.test.ts @@ -1,11 +1,11 @@ import { mcpAuthRouter, AuthRouterOptions, mcpAuthMetadataRouter, AuthMetadataOptions } from '../../../src/server/auth/router.js'; import { OAuthServerProvider, AuthorizationParams } from '../../../src/server/auth/provider.js'; import { OAuthRegisteredClientsStore } from '../../../src/server/auth/clients.js'; -import { OAuthClientInformationFull, OAuthMetadata, OAuthTokenRevocationRequest, OAuthTokens } from '../../../src/shared/auth.js'; +import { OAuthClientInformationFull, OAuthMetadata, OAuthTokenRevocationRequest, OAuthTokens } from '@modelcontextprotocol/sdk-core'; import express, { Response } from 'express'; import supertest from 'supertest'; -import { AuthInfo } from '../../../src/server/auth/types.js'; -import { InvalidTokenError } from '../../../src/server/auth/errors.js'; +import { AuthInfo } from '@modelcontextprotocol/sdk-core'; +import { InvalidTokenError } from '@modelcontextprotocol/sdk-core'; describe('MCP Auth Router', () => { // Setup mock provider with full capabilities @@ -295,7 +295,7 @@ describe('MCP Auth Router', () => { }); expect(response.status).toBe(302); - const location = new URL(response.header.location); + const location = new URL(response.header.location!); expect(location.searchParams.has('code')).toBe(true); }); diff --git a/test/server/completable.test.ts b/packages/server/test/server/completable.test.ts similarity index 95% rename from test/server/completable.test.ts rename to packages/server/test/server/completable.test.ts index 3f917a492..aed952d98 100644 --- a/test/server/completable.test.ts +++ b/packages/server/test/server/completable.test.ts @@ -1,5 +1,5 @@ import { completable, getCompleter } from '../../src/server/completable.js'; -import { zodTestMatrix, type ZodMatrixEntry } from '../../src/__fixtures__/zodTestMatrix.js'; +import { zodTestMatrix, type ZodMatrixEntry } from './__fixtures__/zodTestMatrix.js'; describe.each(zodTestMatrix)('completable with $zodVersionLabel', (entry: ZodMatrixEntry) => { const { z } = entry; diff --git a/test/server/sse.test.ts b/packages/server/test/server/sse.test.ts similarity index 99% rename from test/server/sse.test.ts rename to packages/server/test/server/sse.test.ts index 4686f2ba9..b6f474074 100644 --- a/test/server/sse.test.ts +++ b/packages/server/test/server/sse.test.ts @@ -4,9 +4,9 @@ import { type Mocked } from 'vitest'; import { SSEServerTransport } from '../../src/server/sse.js'; import { McpServer } from '../../src/server/mcp.js'; import { createServer, type Server } from 'node:http'; -import { CallToolResult, JSONRPCMessage } from '../../src/types.js'; -import { zodTestMatrix, type ZodMatrixEntry } from '../../src/__fixtures__/zodTestMatrix.js'; -import { listenOnRandomPort } from '../helpers/http.js'; +import { CallToolResult, JSONRPCMessage } from '@modelcontextprotocol/sdk-core'; +import { zodTestMatrix, type ZodMatrixEntry } from './__fixtures__/zodTestMatrix.js'; +import { listenOnRandomPort } from '../../../integration/test/helpers/http.js'; const createMockResponse = () => { const res = { @@ -142,7 +142,7 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => { const baseUrl = await listenOnRandomPort(server); const addr = server.address(); - const port = typeof addr === 'string' ? new URL(baseUrl).port : (addr as any).port; + const port = typeof addr === 'string' ? new URL(baseUrl).port : (addr as unknown as { port: number }).port; return { server, transport, mcpServer, baseUrl, sessionId, serverPort: Number(port) }; } diff --git a/test/server/stdio.test.ts b/packages/server/test/server/stdio.test.ts similarity index 90% rename from test/server/stdio.test.ts rename to packages/server/test/server/stdio.test.ts index 86379c8a6..8a173600e 100644 --- a/test/server/stdio.test.ts +++ b/packages/server/test/server/stdio.test.ts @@ -1,6 +1,6 @@ import { Readable, Writable } from 'node:stream'; -import { ReadBuffer, serializeMessage } from '../../src/shared/stdio.js'; -import { JSONRPCMessage } from '../../src/types.js'; +import { ReadBuffer, serializeMessage } from '@modelcontextprotocol/sdk-core'; +import { JSONRPCMessage } from '@modelcontextprotocol/sdk-core'; import { StdioServerTransport } from '../../src/server/stdio.js'; let input: Readable; @@ -93,8 +93,8 @@ test('should read multiple messages', async () => { }; }); - input.push(serializeMessage(messages[0])); - input.push(serializeMessage(messages[1])); + input.push(serializeMessage(messages[0]!)); + input.push(serializeMessage(messages[1]!)); await server.start(); await finished; diff --git a/test/server/streamableHttp.test.ts b/packages/server/test/server/streamableHttp.test.ts similarity index 99% rename from test/server/streamableHttp.test.ts rename to packages/server/test/server/streamableHttp.test.ts index 0161d82fb..c64fd7313 100644 --- a/test/server/streamableHttp.test.ts +++ b/packages/server/test/server/streamableHttp.test.ts @@ -3,10 +3,10 @@ import { AddressInfo, createServer as netCreateServer } from 'node:net'; import { randomUUID } from 'node:crypto'; import { EventStore, StreamableHTTPServerTransport, EventId, StreamId } from '../../src/server/streamableHttp.js'; import { McpServer } from '../../src/server/mcp.js'; -import { CallToolResult, JSONRPCMessage } from '../../src/types.js'; -import { AuthInfo } from '../../src/server/auth/types.js'; -import { zodTestMatrix, type ZodMatrixEntry } from '../../src/__fixtures__/zodTestMatrix.js'; -import { listenOnRandomPort } from '../helpers/http.js'; +import { CallToolResult, JSONRPCMessage } from '@modelcontextprotocol/sdk-core'; +import { AuthInfo } from '@modelcontextprotocol/sdk-core'; +import { zodTestMatrix, type ZodMatrixEntry } from './__fixtures__/zodTestMatrix.js'; +import { listenOnRandomPort } from '../../../integration/test/helpers/http.js'; async function getFreePort() { return new Promise(res => { @@ -1285,7 +1285,7 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => { send: (eventId: EventId, message: JSONRPCMessage) => Promise; } ): Promise { - const streamId = lastEventId.split('_')[0]; + const streamId = lastEventId.split('_')[0]!; // Extract stream ID from the event ID // For test simplicity, just return all events with matching streamId that aren't the lastEventId for (const [eventId, { message }] of storedEvents.entries()) { @@ -1361,7 +1361,7 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => { expect(idMatch).toBeTruthy(); // Verify the event was stored - const eventId = idMatch![1]; + const eventId = idMatch![1]!; expect(storedEvents.has(eventId)).toBe(true); const storedEvent = storedEvents.get(eventId); expect(eventId.startsWith('_GET_stream')).toBe(true); @@ -1395,7 +1395,7 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => { // Extract the event ID const idMatch = text.match(/id: ([^\n]+)/); expect(idMatch).toBeTruthy(); - const firstEventId = idMatch![1]; + const firstEventId = idMatch![1]!; // Send a second notification await mcpServer.server.sendLoggingMessage({ level: 'info', data: 'Second notification from MCP server' }); @@ -1450,7 +1450,7 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => { // Extract the event ID const idMatch = text.match(/id: ([^\n]+)/); expect(idMatch).toBeTruthy(); - const lastEventId = idMatch![1]; + const lastEventId = idMatch![1]!; // Close the SSE stream to simulate a disconnect await reader!.cancel(); @@ -1613,7 +1613,7 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => { { send }: { send: (eventId: EventId, message: JSONRPCMessage) => Promise } ): Promise { const event = storedEvents.get(lastEventId); - const streamId = event?.streamId || lastEventId.split('::')[0]; + const streamId = event?.streamId || lastEventId.split('::')[0]!; const eventsToReplay: Array<[string, { message: JSONRPCMessage }]> = []; for (const [eventId, data] of storedEvents.entries()) { if (data.streamId === streamId && eventId > lastEventId) { @@ -2214,7 +2214,7 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => { const text = new TextDecoder().decode(value); const idMatch = text.match(/id: ([^\n]+)/); expect(idMatch).toBeTruthy(); - const lastEventId = idMatch![1]; + const lastEventId = idMatch![1]!; // Call the tool to close the standalone SSE stream const toolCallRequest: JSONRPCMessage = { @@ -2285,7 +2285,7 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => { // Verify we received the notification that was sent while disconnected expect(allText).toContain('Missed while disconnected'); - }, 10000); + }, 15000); }); // Test onsessionclosed callback diff --git a/tsconfig.prod.json b/packages/server/tsconfig.build.json similarity index 85% rename from tsconfig.prod.json rename to packages/server/tsconfig.build.json index 82710bd6a..15f816be5 100644 --- a/tsconfig.prod.json +++ b/packages/server/tsconfig.build.json @@ -1,7 +1,7 @@ { "extends": "./tsconfig.json", "compilerOptions": { - "outDir": "./dist/esm" + "outDir": "./dist" }, "include": ["src/**/*"], "exclude": ["**/*.test.ts", "src/__mocks__/**/*", "src/__fixtures__/**/*"] diff --git a/packages/server/tsconfig.json b/packages/server/tsconfig.json new file mode 100644 index 000000000..c0986de61 --- /dev/null +++ b/packages/server/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "@modelcontextprotocol/tsconfig", + "include": ["./"], + "exclude": ["node_modules", "dist"], + "compilerOptions": { + "baseUrl": ".", + "paths": { + "*": ["./*"], + "@modelcontextprotocol/sdk-core": ["node_modules/@modelcontextprotocol/sdk-core/src/index.ts"] + } + } +} diff --git a/packages/server/vitest.config.js b/packages/server/vitest.config.js new file mode 100644 index 000000000..496fca320 --- /dev/null +++ b/packages/server/vitest.config.js @@ -0,0 +1,3 @@ +import baseConfig from '@modelcontextprotocol/vitest-config'; + +export default baseConfig; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 000000000..574b4ee3c --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,4851 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +catalogs: + default: + typescript: + specifier: ^5.9.3 + version: 5.9.3 + +overrides: + strip-ansi: 6.0.1 + +importers: + + .: + dependencies: + ajv: + specifier: ^8.17.1 + version: 8.17.1 + ajv-formats: + specifier: ^3.0.1 + version: 3.0.1(ajv@8.17.1) + content-type: + specifier: ^1.0.5 + version: 1.0.5 + cors: + specifier: ^2.8.5 + version: 2.8.5 + cross-spawn: + specifier: ^7.0.5 + version: 7.0.6 + eventsource: + specifier: ^3.0.2 + version: 3.0.7 + eventsource-parser: + specifier: ^3.0.0 + version: 3.0.6 + express: + specifier: ^5.0.1 + version: 5.1.0 + express-rate-limit: + specifier: ^7.5.0 + version: 7.5.1(express@5.1.0) + jose: + specifier: ^6.1.1 + version: 6.1.3 + json-schema-typed: + specifier: ^8.0.2 + version: 8.0.2 + pkce-challenge: + specifier: ^5.0.0 + version: 5.0.0 + raw-body: + specifier: ^3.0.0 + version: 3.0.1 + zod: + specifier: ^3.25 || ^4.0 + version: 3.25.76 + zod-to-json-schema: + specifier: ^3.25.0 + version: 3.25.0(zod@3.25.76) + devDependencies: + '@cfworker/json-schema': + specifier: ^4.1.1 + version: 4.1.1 + '@eslint/js': + specifier: ^9.39.1 + version: 9.39.1 + '@types/content-type': + specifier: ^1.1.8 + version: 1.1.9 + '@types/cors': + specifier: ^2.8.17 + version: 2.8.19 + '@types/cross-spawn': + specifier: ^6.0.6 + version: 6.0.6 + '@types/eventsource': + specifier: ^1.1.15 + version: 1.1.15 + '@types/express': + specifier: ^5.0.0 + version: 5.0.5 + '@types/express-serve-static-core': + specifier: ^5.1.0 + version: 5.1.0 + '@types/node': + specifier: ^24.10.1 + version: 24.10.3 + '@types/supertest': + specifier: ^6.0.2 + version: 6.0.3 + '@types/ws': + specifier: ^8.5.12 + version: 8.18.1 + '@typescript/native-preview': + specifier: ^7.0.0-dev.20251103.1 + version: 7.0.0-dev.20251108.1 + eslint: + specifier: ^9.8.0 + version: 9.39.1 + eslint-config-prettier: + specifier: ^10.1.8 + version: 10.1.8(eslint@9.39.1) + eslint-plugin-n: + specifier: ^17.23.1 + version: 17.23.1(eslint@9.39.1)(typescript@5.9.3) + prettier: + specifier: 3.6.2 + version: 3.6.2 + supertest: + specifier: ^7.0.0 + version: 7.1.4 + tsx: + specifier: ^4.16.5 + version: 4.20.6 + typescript: + specifier: ^5.9.3 + version: 5.9.3 + typescript-eslint: + specifier: ^8.48.1 + version: 8.49.0(eslint@9.39.1)(typescript@5.9.3) + vitest: + specifier: ^4.0.8 + version: 4.0.9(@types/node@24.10.3)(tsx@4.20.6) + ws: + specifier: ^8.18.0 + version: 8.18.3 + + common/eslint-config: + dependencies: + typescript: + specifier: 'catalog:' + version: 5.9.3 + devDependencies: + '@eslint/js': + specifier: ^9.39.1 + version: 9.39.1 + eslint: + specifier: ^9.8.0 + version: 9.39.1 + eslint-config-prettier: + specifier: ^10.1.8 + version: 10.1.8(eslint@9.39.1) + eslint-import-resolver-typescript: + specifier: ^4.4.4 + version: 4.4.4(eslint-plugin-import@2.32.0)(eslint@9.39.1) + eslint-plugin-import: + specifier: ^2.32.0 + version: 2.32.0(@typescript-eslint/parser@8.49.0(eslint@9.39.1)(typescript@5.9.3))(eslint-import-resolver-typescript@4.4.4)(eslint@9.39.1) + eslint-plugin-n: + specifier: ^17.23.1 + version: 17.23.1(eslint@9.39.1)(typescript@5.9.3) + eslint-plugin-simple-import-sort: + specifier: ^12.1.1 + version: 12.1.1(eslint@9.39.1) + prettier: + specifier: 3.6.2 + version: 3.6.2 + typescript-eslint: + specifier: ^8.48.1 + version: 8.49.0(eslint@9.39.1)(typescript@5.9.3) + + common/tsconfig: + dependencies: + typescript: + specifier: 'catalog:' + version: 5.9.3 + + common/vitest-config: + dependencies: + typescript: + specifier: 'catalog:' + version: 5.9.3 + devDependencies: + '@modelcontextprotocol/tsconfig': + specifier: workspace:^ + version: link:../tsconfig + vite-tsconfig-paths: + specifier: ^5.1.4 + version: 5.1.4(typescript@5.9.3)(vite@7.2.2(@types/node@24.10.3)(tsx@4.20.6)) + + packages/client: + dependencies: + '@modelcontextprotocol/sdk-core': + specifier: workspace:^ + version: link:../core + ajv: + specifier: ^8.17.1 + version: 8.17.1 + ajv-formats: + specifier: ^3.0.1 + version: 3.0.1(ajv@8.17.1) + content-type: + specifier: ^1.0.5 + version: 1.0.5 + cors: + specifier: ^2.8.5 + version: 2.8.5 + cross-spawn: + specifier: ^7.0.5 + version: 7.0.6 + eventsource: + specifier: ^3.0.2 + version: 3.0.7 + eventsource-parser: + specifier: ^3.0.0 + version: 3.0.6 + express: + specifier: ^5.0.1 + version: 5.1.0 + express-rate-limit: + specifier: ^7.5.0 + version: 7.5.1(express@5.1.0) + jose: + specifier: ^6.1.1 + version: 6.1.3 + json-schema-typed: + specifier: ^8.0.2 + version: 8.0.2 + pkce-challenge: + specifier: ^5.0.0 + version: 5.0.0 + raw-body: + specifier: ^3.0.0 + version: 3.0.1 + zod: + specifier: ^3.25 || ^4.0 + version: 3.25.76 + zod-to-json-schema: + specifier: ^3.25.0 + version: 3.25.0(zod@3.25.76) + devDependencies: + '@cfworker/json-schema': + specifier: ^4.1.1 + version: 4.1.1 + '@eslint/js': + specifier: ^9.39.1 + version: 9.39.1 + '@modelcontextprotocol/eslint-config': + specifier: workspace:^ + version: link:../../common/eslint-config + '@modelcontextprotocol/tsconfig': + specifier: workspace:^ + version: link:../../common/tsconfig + '@modelcontextprotocol/vitest-config': + specifier: workspace:^ + version: link:../../common/vitest-config + '@types/content-type': + specifier: ^1.1.8 + version: 1.1.9 + '@types/cors': + specifier: ^2.8.17 + version: 2.8.19 + '@types/cross-spawn': + specifier: ^6.0.6 + version: 6.0.6 + '@types/eventsource': + specifier: ^1.1.15 + version: 1.1.15 + '@types/express': + specifier: ^5.0.0 + version: 5.0.5 + '@types/express-serve-static-core': + specifier: ^5.1.0 + version: 5.1.0 + '@types/supertest': + specifier: ^6.0.2 + version: 6.0.3 + '@types/ws': + specifier: ^8.5.12 + version: 8.18.1 + '@typescript/native-preview': + specifier: ^7.0.0-dev.20251103.1 + version: 7.0.0-dev.20251108.1 + eslint: + specifier: ^9.8.0 + version: 9.39.1 + eslint-config-prettier: + specifier: ^10.1.8 + version: 10.1.8(eslint@9.39.1) + eslint-plugin-n: + specifier: ^17.23.1 + version: 17.23.1(eslint@9.39.1)(typescript@5.9.3) + prettier: + specifier: 3.6.2 + version: 3.6.2 + supertest: + specifier: ^7.0.0 + version: 7.1.4 + tsx: + specifier: ^4.16.5 + version: 4.20.6 + typescript: + specifier: ^5.5.4 + version: 5.9.3 + typescript-eslint: + specifier: ^8.48.1 + version: 8.49.0(eslint@9.39.1)(typescript@5.9.3) + vitest: + specifier: ^4.0.8 + version: 4.0.9(@types/node@24.10.3)(tsx@4.20.6) + ws: + specifier: ^8.18.0 + version: 8.18.3 + + packages/client/dist: {} + + packages/core: + dependencies: + ajv: + specifier: ^8.17.1 + version: 8.17.1 + ajv-formats: + specifier: ^3.0.1 + version: 3.0.1(ajv@8.17.1) + content-type: + specifier: ^1.0.5 + version: 1.0.5 + cors: + specifier: ^2.8.5 + version: 2.8.5 + cross-spawn: + specifier: ^7.0.5 + version: 7.0.6 + eventsource: + specifier: ^3.0.2 + version: 3.0.7 + eventsource-parser: + specifier: ^3.0.0 + version: 3.0.6 + express: + specifier: ^5.0.1 + version: 5.1.0 + express-rate-limit: + specifier: ^7.5.0 + version: 7.5.1(express@5.1.0) + jose: + specifier: ^6.1.1 + version: 6.1.3 + json-schema-typed: + specifier: ^8.0.2 + version: 8.0.2 + pkce-challenge: + specifier: ^5.0.0 + version: 5.0.0 + raw-body: + specifier: ^3.0.0 + version: 3.0.1 + zod: + specifier: ^3.25 || ^4.0 + version: 3.25.76 + zod-to-json-schema: + specifier: ^3.25.0 + version: 3.25.0(zod@3.25.76) + devDependencies: + '@cfworker/json-schema': + specifier: ^4.1.1 + version: 4.1.1 + '@eslint/js': + specifier: ^9.39.1 + version: 9.39.1 + '@modelcontextprotocol/eslint-config': + specifier: workspace:^ + version: link:../../common/eslint-config + '@modelcontextprotocol/tsconfig': + specifier: workspace:^ + version: link:../../common/tsconfig + '@modelcontextprotocol/vitest-config': + specifier: workspace:^ + version: link:../../common/vitest-config + '@types/content-type': + specifier: ^1.1.8 + version: 1.1.9 + '@types/cors': + specifier: ^2.8.17 + version: 2.8.19 + '@types/cross-spawn': + specifier: ^6.0.6 + version: 6.0.6 + '@types/eventsource': + specifier: ^1.1.15 + version: 1.1.15 + '@types/express': + specifier: ^5.0.0 + version: 5.0.5 + '@types/express-serve-static-core': + specifier: ^5.1.0 + version: 5.1.0 + '@types/supertest': + specifier: ^6.0.2 + version: 6.0.3 + '@types/ws': + specifier: ^8.5.12 + version: 8.18.1 + '@typescript/native-preview': + specifier: ^7.0.0-dev.20251103.1 + version: 7.0.0-dev.20251108.1 + eslint: + specifier: ^9.8.0 + version: 9.39.1 + eslint-config-prettier: + specifier: ^10.1.8 + version: 10.1.8(eslint@9.39.1) + eslint-plugin-n: + specifier: ^17.23.1 + version: 17.23.1(eslint@9.39.1)(typescript@5.9.3) + prettier: + specifier: 3.6.2 + version: 3.6.2 + supertest: + specifier: ^7.0.0 + version: 7.1.4 + tsx: + specifier: ^4.16.5 + version: 4.20.6 + typescript: + specifier: ^5.5.4 + version: 5.9.3 + typescript-eslint: + specifier: ^8.48.1 + version: 8.49.0(eslint@9.39.1)(typescript@5.9.3) + vitest: + specifier: ^4.0.8 + version: 4.0.9(@types/node@24.10.3)(tsx@4.20.6) + ws: + specifier: ^8.18.0 + version: 8.18.3 + + packages/core/dist: {} + + packages/examples/client: + dependencies: + '@modelcontextprotocol/sdk-client': + specifier: workspace:^ + version: link:../../client + devDependencies: + '@modelcontextprotocol/eslint-config': + specifier: workspace:^ + version: link:../../../common/eslint-config + '@modelcontextprotocol/sdk-examples-shared': + specifier: workspace:^ + version: link:../shared + '@modelcontextprotocol/tsconfig': + specifier: workspace:^ + version: link:../../../common/tsconfig + '@modelcontextprotocol/vitest-config': + specifier: workspace:^ + version: link:../../../common/vitest-config + + packages/examples/server: + dependencies: + '@modelcontextprotocol/sdk-examples-shared': + specifier: workspace:^ + version: link:../shared + '@modelcontextprotocol/sdk-server': + specifier: workspace:^ + version: link:../../server + devDependencies: + '@modelcontextprotocol/eslint-config': + specifier: workspace:^ + version: link:../../../common/eslint-config + '@modelcontextprotocol/tsconfig': + specifier: workspace:^ + version: link:../../../common/tsconfig + '@modelcontextprotocol/vitest-config': + specifier: workspace:^ + version: link:../../../common/vitest-config + + packages/examples/shared: + dependencies: + '@modelcontextprotocol/sdk-server': + specifier: workspace:^ + version: link:../../server + devDependencies: + '@modelcontextprotocol/eslint-config': + specifier: workspace:^ + version: link:../../../common/eslint-config + '@modelcontextprotocol/tsconfig': + specifier: workspace:^ + version: link:../../../common/tsconfig + '@modelcontextprotocol/vitest-config': + specifier: workspace:^ + version: link:../../../common/vitest-config + + packages/integration: + devDependencies: + '@modelcontextprotocol/eslint-config': + specifier: workspace:^ + version: link:../../common/eslint-config + '@modelcontextprotocol/sdk-client': + specifier: workspace:^ + version: link:../client + '@modelcontextprotocol/sdk-core': + specifier: workspace:^ + version: link:../core + '@modelcontextprotocol/sdk-server': + specifier: workspace:^ + version: link:../server + '@modelcontextprotocol/tsconfig': + specifier: workspace:^ + version: link:../../common/tsconfig + '@modelcontextprotocol/vitest-config': + specifier: workspace:^ + version: link:../../common/vitest-config + + packages/server: + dependencies: + '@modelcontextprotocol/sdk-core': + specifier: workspace:^ + version: link:../core + ajv: + specifier: ^8.17.1 + version: 8.17.1 + ajv-formats: + specifier: ^3.0.1 + version: 3.0.1(ajv@8.17.1) + content-type: + specifier: ^1.0.5 + version: 1.0.5 + cors: + specifier: ^2.8.5 + version: 2.8.5 + cross-spawn: + specifier: ^7.0.5 + version: 7.0.6 + eventsource: + specifier: ^3.0.2 + version: 3.0.7 + eventsource-parser: + specifier: ^3.0.0 + version: 3.0.6 + express: + specifier: ^5.0.1 + version: 5.1.0 + express-rate-limit: + specifier: ^7.5.0 + version: 7.5.1(express@5.1.0) + jose: + specifier: ^6.1.1 + version: 6.1.3 + json-schema-typed: + specifier: ^8.0.2 + version: 8.0.2 + pkce-challenge: + specifier: ^5.0.0 + version: 5.0.0 + raw-body: + specifier: ^3.0.0 + version: 3.0.1 + zod: + specifier: ^3.25 || ^4.0 + version: 3.25.76 + zod-to-json-schema: + specifier: ^3.25.0 + version: 3.25.0(zod@3.25.76) + devDependencies: + '@cfworker/json-schema': + specifier: ^4.1.1 + version: 4.1.1 + '@eslint/js': + specifier: ^9.39.1 + version: 9.39.1 + '@modelcontextprotocol/eslint-config': + specifier: workspace:^ + version: link:../../common/eslint-config + '@modelcontextprotocol/tsconfig': + specifier: workspace:^ + version: link:../../common/tsconfig + '@modelcontextprotocol/vitest-config': + specifier: workspace:^ + version: link:../../common/vitest-config + '@types/content-type': + specifier: ^1.1.8 + version: 1.1.9 + '@types/cors': + specifier: ^2.8.17 + version: 2.8.19 + '@types/cross-spawn': + specifier: ^6.0.6 + version: 6.0.6 + '@types/eventsource': + specifier: ^1.1.15 + version: 1.1.15 + '@types/express': + specifier: ^5.0.0 + version: 5.0.5 + '@types/express-serve-static-core': + specifier: ^5.1.0 + version: 5.1.0 + '@types/supertest': + specifier: ^6.0.2 + version: 6.0.3 + '@types/ws': + specifier: ^8.5.12 + version: 8.18.1 + '@typescript/native-preview': + specifier: ^7.0.0-dev.20251103.1 + version: 7.0.0-dev.20251108.1 + eslint: + specifier: ^9.8.0 + version: 9.39.1 + eslint-config-prettier: + specifier: ^10.1.8 + version: 10.1.8(eslint@9.39.1) + eslint-plugin-n: + specifier: ^17.23.1 + version: 17.23.1(eslint@9.39.1)(typescript@5.9.3) + prettier: + specifier: 3.6.2 + version: 3.6.2 + supertest: + specifier: ^7.0.0 + version: 7.1.4 + tsx: + specifier: ^4.16.5 + version: 4.20.6 + typescript: + specifier: ^5.5.4 + version: 5.9.3 + typescript-eslint: + specifier: ^8.48.1 + version: 8.49.0(eslint@9.39.1)(typescript@5.9.3) + vitest: + specifier: ^4.0.8 + version: 4.0.9(@types/node@24.10.3)(tsx@4.20.6) + ws: + specifier: ^8.18.0 + version: 8.18.3 + + packages/server/dist: {} + +packages: + + '@cfworker/json-schema@4.1.1': + resolution: {integrity: sha512-gAmrUZSGtKc3AiBL71iNWxDsyUC5uMaKKGdvzYsBoTW/xi42JQHl7eKV2OYzCUqvc+D2RCcf7EXY2iCyFIk6og==} + + '@emnapi/core@1.7.1': + resolution: {integrity: sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==} + + '@emnapi/runtime@1.7.1': + resolution: {integrity: sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==} + + '@emnapi/wasi-threads@1.1.0': + resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} + + '@esbuild/aix-ppc64@0.25.12': + resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.25.12': + resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.25.12': + resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.25.12': + resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.25.12': + resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.25.12': + resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.25.12': + resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.25.12': + resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.25.12': + resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.25.12': + resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.25.12': + resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.25.12': + resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.25.12': + resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.25.12': + resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.25.12': + resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.25.12': + resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.25.12': + resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.25.12': + resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.25.12': + resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.25.12': + resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.25.12': + resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.25.12': + resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.25.12': + resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.25.12': + resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.25.12': + resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.25.12': + resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@eslint-community/eslint-utils@4.9.0': + resolution: {integrity: sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + '@eslint-community/regexpp@4.12.2': + resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + '@eslint/config-array@0.21.1': + resolution: {integrity: sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/config-helpers@0.4.2': + resolution: {integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/core@0.17.0': + resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/eslintrc@3.3.1': + resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/js@9.39.1': + resolution: {integrity: sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/object-schema@2.1.7': + resolution: {integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/plugin-kit@0.4.1': + resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@humanfs/core@0.19.1': + resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} + engines: {node: '>=18.18.0'} + + '@humanfs/node@0.16.7': + resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==} + engines: {node: '>=18.18.0'} + + '@humanwhocodes/module-importer@1.0.1': + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + + '@humanwhocodes/retry@0.4.3': + resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} + engines: {node: '>=18.18'} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@napi-rs/wasm-runtime@0.2.12': + resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} + + '@noble/hashes@1.8.0': + resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==} + engines: {node: ^14.21.3 || >=16} + + '@paralleldrive/cuid2@2.3.1': + resolution: {integrity: sha512-XO7cAxhnTZl0Yggq6jOgjiOHhbgcO4NqFqwSmQpjK3b6TEE6Uj/jfSk6wzYyemh3+I0sHirKSetjQwn5cZktFw==} + + '@rollup/rollup-android-arm-eabi@4.53.2': + resolution: {integrity: sha512-yDPzwsgiFO26RJA4nZo8I+xqzh7sJTZIWQOxn+/XOdPE31lAvLIYCKqjV+lNH/vxE2L2iH3plKxDCRK6i+CwhA==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.53.2': + resolution: {integrity: sha512-k8FontTxIE7b0/OGKeSN5B6j25EuppBcWM33Z19JoVT7UTXFSo3D9CdU39wGTeb29NO3XxpMNauh09B+Ibw+9g==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.53.2': + resolution: {integrity: sha512-A6s4gJpomNBtJ2yioj8bflM2oogDwzUiMl2yNJ2v9E7++sHrSrsQ29fOfn5DM/iCzpWcebNYEdXpaK4tr2RhfQ==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.53.2': + resolution: {integrity: sha512-e6XqVmXlHrBlG56obu9gDRPW3O3hLxpwHpLsBJvuI8qqnsrtSZ9ERoWUXtPOkY8c78WghyPHZdmPhHLWNdAGEw==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.53.2': + resolution: {integrity: sha512-v0E9lJW8VsrwPux5Qe5CwmH/CF/2mQs6xU1MF3nmUxmZUCHazCjLgYvToOk+YuuUqLQBio1qkkREhxhc656ViA==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.53.2': + resolution: {integrity: sha512-ClAmAPx3ZCHtp6ysl4XEhWU69GUB1D+s7G9YjHGhIGCSrsg00nEGRRZHmINYxkdoJehde8VIsDC5t9C0gb6yqA==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.53.2': + resolution: {integrity: sha512-EPlb95nUsz6Dd9Qy13fI5kUPXNSljaG9FiJ4YUGU1O/Q77i5DYFW5KR8g1OzTcdZUqQQ1KdDqsTohdFVwCwjqg==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.53.2': + resolution: {integrity: sha512-BOmnVW+khAUX+YZvNfa0tGTEMVVEerOxN0pDk2E6N6DsEIa2Ctj48FOMfNDdrwinocKaC7YXUZ1pHlKpnkja/Q==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.53.2': + resolution: {integrity: sha512-Xt2byDZ+6OVNuREgBXr4+CZDJtrVso5woFtpKdGPhpTPHcNG7D8YXeQzpNbFRxzTVqJf7kvPMCub/pcGUWgBjA==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.53.2': + resolution: {integrity: sha512-+LdZSldy/I9N8+klim/Y1HsKbJ3BbInHav5qE9Iy77dtHC/pibw1SR/fXlWyAk0ThnpRKoODwnAuSjqxFRDHUQ==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-loong64-gnu@4.53.2': + resolution: {integrity: sha512-8ms8sjmyc1jWJS6WdNSA23rEfdjWB30LH8Wqj0Cqvv7qSHnvw6kgMMXRdop6hkmGPlyYBdRPkjJnj3KCUHV/uQ==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-ppc64-gnu@4.53.2': + resolution: {integrity: sha512-3HRQLUQbpBDMmzoxPJYd3W6vrVHOo2cVW8RUo87Xz0JPJcBLBr5kZ1pGcQAhdZgX9VV7NbGNipah1omKKe23/g==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.53.2': + resolution: {integrity: sha512-fMjKi+ojnmIvhk34gZP94vjogXNNUKMEYs+EDaB/5TG/wUkoeua7p7VCHnE6T2Tx+iaghAqQX8teQzcvrYpaQA==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-riscv64-musl@4.53.2': + resolution: {integrity: sha512-XuGFGU+VwUUV5kLvoAdi0Wz5Xbh2SrjIxCtZj6Wq8MDp4bflb/+ThZsVxokM7n0pcbkEr2h5/pzqzDYI7cCgLQ==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.53.2': + resolution: {integrity: sha512-w6yjZF0P+NGzWR3AXWX9zc0DNEGdtvykB03uhonSHMRa+oWA6novflo2WaJr6JZakG2ucsyb+rvhrKac6NIy+w==} + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.53.2': + resolution: {integrity: sha512-yo8d6tdfdeBArzC7T/PnHd7OypfI9cbuZzPnzLJIyKYFhAQ8SvlkKtKBMbXDxe1h03Rcr7u++nFS7tqXz87Gtw==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-musl@4.53.2': + resolution: {integrity: sha512-ah59c1YkCxKExPP8O9PwOvs+XRLKwh/mV+3YdKqQ5AMQ0r4M4ZDuOrpWkUaqO7fzAHdINzV9tEVu8vNw48z0lA==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-openharmony-arm64@4.53.2': + resolution: {integrity: sha512-4VEd19Wmhr+Zy7hbUsFZ6YXEiP48hE//KPLCSVNY5RMGX2/7HZ+QkN55a3atM1C/BZCGIgqN+xrVgtdak2S9+A==} + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-win32-arm64-msvc@4.53.2': + resolution: {integrity: sha512-IlbHFYc/pQCgew/d5fslcy1KEaYVCJ44G8pajugd8VoOEI8ODhtb/j8XMhLpwHCMB3yk2J07ctup10gpw2nyMA==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.53.2': + resolution: {integrity: sha512-lNlPEGgdUfSzdCWU176ku/dQRnA7W+Gp8d+cWv73jYrb8uT7HTVVxq62DUYxjbaByuf1Yk0RIIAbDzp+CnOTFg==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-gnu@4.53.2': + resolution: {integrity: sha512-S6YojNVrHybQis2lYov1sd+uj7K0Q05NxHcGktuMMdIQ2VixGwAfbJ23NnlvvVV1bdpR2m5MsNBViHJKcA4ADw==} + cpu: [x64] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.53.2': + resolution: {integrity: sha512-k+/Rkcyx//P6fetPoLMb8pBeqJBNGx81uuf7iljX9++yNBVRDQgD04L+SVXmXmh5ZP4/WOp4mWF0kmi06PW2tA==} + cpu: [x64] + os: [win32] + + '@rtsao/scc@1.1.0': + resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} + + '@standard-schema/spec@1.0.0': + resolution: {integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==} + + '@tybys/wasm-util@0.10.1': + resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} + + '@types/body-parser@1.19.6': + resolution: {integrity: sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==} + + '@types/chai@5.2.3': + resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} + + '@types/connect@3.4.38': + resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} + + '@types/content-type@1.1.9': + resolution: {integrity: sha512-Hq9IMnfekuOCsEmYl4QX2HBrT+XsfXiupfrLLY8Dcf3Puf4BkBOxSbWYTITSOQAhJoYPBez+b4MJRpIYL65z8A==} + + '@types/cookiejar@2.1.5': + resolution: {integrity: sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q==} + + '@types/cors@2.8.19': + resolution: {integrity: sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==} + + '@types/cross-spawn@6.0.6': + resolution: {integrity: sha512-fXRhhUkG4H3TQk5dBhQ7m/JDdSNHKwR2BBia62lhwEIq9xGiQKLxd6LymNhn47SjXhsUEPmxi+PKw2OkW4LLjA==} + + '@types/deep-eql@4.0.2': + resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} + + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + + '@types/eventsource@1.1.15': + resolution: {integrity: sha512-XQmGcbnxUNa06HR3VBVkc9+A2Vpi9ZyLJcdS5dwaQQ/4ZMWFO+5c90FnMUpbtMZwB/FChoYHwuVg8TvkECacTA==} + + '@types/express-serve-static-core@5.1.0': + resolution: {integrity: sha512-jnHMsrd0Mwa9Cf4IdOzbz543y4XJepXrbia2T4b6+spXC2We3t1y6K44D3mR8XMFSXMCf3/l7rCgddfx7UNVBA==} + + '@types/express@5.0.5': + resolution: {integrity: sha512-LuIQOcb6UmnF7C1PCFmEU1u2hmiHL43fgFQX67sN3H4Z+0Yk0Neo++mFsBjhOAuLzvlQeqAAkeDOZrJs9rzumQ==} + + '@types/http-errors@2.0.5': + resolution: {integrity: sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==} + + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + + '@types/json5@0.0.29': + resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} + + '@types/methods@1.1.4': + resolution: {integrity: sha512-ymXWVrDiCxTBE3+RIrrP533E70eA+9qu7zdWoHuOmGujkYtzf4HQF96b8nwHLqhuf4ykX61IGRIB38CC6/sImQ==} + + '@types/mime@1.3.5': + resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==} + + '@types/node@24.10.3': + resolution: {integrity: sha512-gqkrWUsS8hcm0r44yn7/xZeV1ERva/nLgrLxFRUGb7aoNMIJfZJ3AC261zDQuOAKC7MiXai1WCpYc48jAHoShQ==} + + '@types/qs@6.14.0': + resolution: {integrity: sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==} + + '@types/range-parser@1.2.7': + resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==} + + '@types/send@0.17.6': + resolution: {integrity: sha512-Uqt8rPBE8SY0RK8JB1EzVOIZ32uqy8HwdxCnoCOsYrvnswqmFZ/k+9Ikidlk/ImhsdvBsloHbAlewb2IEBV/Og==} + + '@types/send@1.2.1': + resolution: {integrity: sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==} + + '@types/serve-static@1.15.10': + resolution: {integrity: sha512-tRs1dB+g8Itk72rlSI2ZrW6vZg0YrLI81iQSTkMmOqnqCaNr/8Ek4VwWcN5vZgCYWbg/JJSGBlUaYGAOP73qBw==} + + '@types/superagent@8.1.9': + resolution: {integrity: sha512-pTVjI73witn+9ILmoJdajHGW2jkSaOzhiFYF1Rd3EQ94kymLqB9PjD9ISg7WaALC7+dCHT0FGe9T2LktLq/3GQ==} + + '@types/supertest@6.0.3': + resolution: {integrity: sha512-8WzXq62EXFhJ7QsH3Ocb/iKQ/Ty9ZVWnVzoTKc9tyyFRRF3a74Tk2+TLFgaFFw364Ere+npzHKEJ6ga2LzIL7w==} + + '@types/ws@8.18.1': + resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} + + '@typescript-eslint/eslint-plugin@8.49.0': + resolution: {integrity: sha512-JXij0vzIaTtCwu6SxTh8qBc66kmf1xs7pI4UOiMDFVct6q86G0Zs7KRcEoJgY3Cav3x5Tq0MF5jwgpgLqgKG3A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.49.0 + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/parser@8.49.0': + resolution: {integrity: sha512-N9lBGA9o9aqb1hVMc9hzySbhKibHmB+N3IpoShyV6HyQYRGIhlrO5rQgttypi+yEeKsKI4idxC8Jw6gXKD4THA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/project-service@8.49.0': + resolution: {integrity: sha512-/wJN0/DKkmRUMXjZUXYZpD1NEQzQAAn9QWfGwo+Ai8gnzqH7tvqS7oNVdTjKqOcPyVIdZdyCMoqN66Ia789e7g==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/scope-manager@8.49.0': + resolution: {integrity: sha512-npgS3zi+/30KSOkXNs0LQXtsg9ekZ8OISAOLGWA/ZOEn0ZH74Ginfl7foziV8DT+D98WfQ5Kopwqb/PZOaIJGg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/tsconfig-utils@8.49.0': + resolution: {integrity: sha512-8prixNi1/6nawsRYxet4YOhnbW+W9FK/bQPxsGB1D3ZrDzbJ5FXw5XmzxZv82X3B+ZccuSxo/X8q9nQ+mFecWA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/type-utils@8.49.0': + resolution: {integrity: sha512-KTExJfQ+svY8I10P4HdxKzWsvtVnsuCifU5MvXrRwoP2KOlNZ9ADNEWWsQTJgMxLzS5VLQKDjkCT/YzgsnqmZg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/types@8.49.0': + resolution: {integrity: sha512-e9k/fneezorUo6WShlQpMxXh8/8wfyc+biu6tnAqA81oWrEic0k21RHzP9uqqpyBBeBKu4T+Bsjy9/b8u7obXQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/typescript-estree@8.49.0': + resolution: {integrity: sha512-jrLdRuAbPfPIdYNppHJ/D0wN+wwNfJ32YTAm10eJVsFmrVpXQnDWBn8niCSMlWjvml8jsce5E/O+86IQtTbJWA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/utils@8.49.0': + resolution: {integrity: sha512-N3W7rJw7Rw+z1tRsHZbK395TWSYvufBXumYtEGzypgMUthlg0/hmCImeA8hgO2d2G4pd7ftpxxul2J8OdtdaFA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/visitor-keys@8.49.0': + resolution: {integrity: sha512-LlKaciDe3GmZFphXIc79THF/YYBugZ7FS1pO581E/edlVVNbZKDy93evqmrfQ9/Y4uN0vVhX4iuchq26mK/iiA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript/native-preview-darwin-arm64@7.0.0-dev.20251108.1': + resolution: {integrity: sha512-zdD59CWlvJum9hu7Rrb7xntGfkeTlki7Pql/s+Ls0sNSEGimjuJmU88ookUt2UMPLZ9S+RyGfjNbS7duhKuCIw==} + cpu: [arm64] + os: [darwin] + + '@typescript/native-preview-darwin-x64@7.0.0-dev.20251108.1': + resolution: {integrity: sha512-nxs1vOm6jkwZoA56d6E2pllhYbxK2xNtspG2Yx9kswdp0aqh2jcja1EjMilHv4tnvNixRQvRWhoOz/BgWrxTig==} + cpu: [x64] + os: [darwin] + + '@typescript/native-preview-linux-arm64@7.0.0-dev.20251108.1': + resolution: {integrity: sha512-Er0P4Dt6fBM6MZidGBKGZs5PS2QHunRPNeIKCATJRcBMn8ymSBdi/IJK/wYVU62HW8CLb1Dt3FbueW5UptSAKA==} + cpu: [arm64] + os: [linux] + + '@typescript/native-preview-linux-arm@7.0.0-dev.20251108.1': + resolution: {integrity: sha512-+1UuKod2SJZODnArwHViJEhZxgM1aHK5KCGlHJU61htq3jgNtRfouw4UEJRPTALCnGLun8ZpYuMsJUMeDFFIUQ==} + cpu: [arm] + os: [linux] + + '@typescript/native-preview-linux-x64@7.0.0-dev.20251108.1': + resolution: {integrity: sha512-3ijz+Uo8unENgq22nlyThf1JqhLVOwN881gomoAykALmspXX13aQwnDtbscnQRr1iQqMIrEyyRMwxfVevQkl9w==} + cpu: [x64] + os: [linux] + + '@typescript/native-preview-win32-arm64@7.0.0-dev.20251108.1': + resolution: {integrity: sha512-Aeyrj7sdc6GBnLIw9o5dQPzEqrfsJodDYsi7RePm0QLvGVyxOeZVd9CcfdXqPKnD2goEJNOzFoTRyvvi7DjNUg==} + cpu: [arm64] + os: [win32] + + '@typescript/native-preview-win32-x64@7.0.0-dev.20251108.1': + resolution: {integrity: sha512-rgfq7AZ7IFfE5EyDuHdpDEPUH3LEesyOVuIHE6YWOSqGOFnlzYbOf37VUYxQTIxFrR7IopgvM4pSDR3KeDcMjQ==} + cpu: [x64] + os: [win32] + + '@typescript/native-preview@7.0.0-dev.20251108.1': + resolution: {integrity: sha512-v1SNmHbuTYMEIAAJZ5OgKY5kMIgDnS/aVTsP9FdR9FgqyZqgUbA2eHOjjMQHVw/XBLS5ZA32kkGt7cH8RzMlOA==} + hasBin: true + + '@unrs/resolver-binding-android-arm-eabi@1.11.1': + resolution: {integrity: sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==} + cpu: [arm] + os: [android] + + '@unrs/resolver-binding-android-arm64@1.11.1': + resolution: {integrity: sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==} + cpu: [arm64] + os: [android] + + '@unrs/resolver-binding-darwin-arm64@1.11.1': + resolution: {integrity: sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==} + cpu: [arm64] + os: [darwin] + + '@unrs/resolver-binding-darwin-x64@1.11.1': + resolution: {integrity: sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==} + cpu: [x64] + os: [darwin] + + '@unrs/resolver-binding-freebsd-x64@1.11.1': + resolution: {integrity: sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==} + cpu: [x64] + os: [freebsd] + + '@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1': + resolution: {integrity: sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==} + cpu: [arm] + os: [linux] + + '@unrs/resolver-binding-linux-arm-musleabihf@1.11.1': + resolution: {integrity: sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==} + cpu: [arm] + os: [linux] + + '@unrs/resolver-binding-linux-arm64-gnu@1.11.1': + resolution: {integrity: sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==} + cpu: [arm64] + os: [linux] + + '@unrs/resolver-binding-linux-arm64-musl@1.11.1': + resolution: {integrity: sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==} + cpu: [arm64] + os: [linux] + + '@unrs/resolver-binding-linux-ppc64-gnu@1.11.1': + resolution: {integrity: sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==} + cpu: [ppc64] + os: [linux] + + '@unrs/resolver-binding-linux-riscv64-gnu@1.11.1': + resolution: {integrity: sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==} + cpu: [riscv64] + os: [linux] + + '@unrs/resolver-binding-linux-riscv64-musl@1.11.1': + resolution: {integrity: sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==} + cpu: [riscv64] + os: [linux] + + '@unrs/resolver-binding-linux-s390x-gnu@1.11.1': + resolution: {integrity: sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==} + cpu: [s390x] + os: [linux] + + '@unrs/resolver-binding-linux-x64-gnu@1.11.1': + resolution: {integrity: sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==} + cpu: [x64] + os: [linux] + + '@unrs/resolver-binding-linux-x64-musl@1.11.1': + resolution: {integrity: sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==} + cpu: [x64] + os: [linux] + + '@unrs/resolver-binding-wasm32-wasi@1.11.1': + resolution: {integrity: sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@unrs/resolver-binding-win32-arm64-msvc@1.11.1': + resolution: {integrity: sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==} + cpu: [arm64] + os: [win32] + + '@unrs/resolver-binding-win32-ia32-msvc@1.11.1': + resolution: {integrity: sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==} + cpu: [ia32] + os: [win32] + + '@unrs/resolver-binding-win32-x64-msvc@1.11.1': + resolution: {integrity: sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==} + cpu: [x64] + os: [win32] + + '@vitest/expect@4.0.9': + resolution: {integrity: sha512-C2vyXf5/Jfj1vl4DQYxjib3jzyuswMi/KHHVN2z+H4v16hdJ7jMZ0OGe3uOVIt6LyJsAofDdaJNIFEpQcrSTFw==} + + '@vitest/mocker@4.0.9': + resolution: {integrity: sha512-PUyaowQFHW+9FKb4dsvvBM4o025rWMlEDXdWRxIOilGaHREYTi5Q2Rt9VCgXgPy/hHZu1LeuXtrA/GdzOatP2g==} + peerDependencies: + msw: ^2.4.9 + vite: ^6.0.0 || ^7.0.0-0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + + '@vitest/pretty-format@4.0.9': + resolution: {integrity: sha512-Hor0IBTwEi/uZqB7pvGepyElaM8J75pYjrrqbC8ZYMB9/4n5QA63KC15xhT+sqHpdGWfdnPo96E8lQUxs2YzSQ==} + + '@vitest/runner@4.0.9': + resolution: {integrity: sha512-aF77tsXdEvIJRkj9uJZnHtovsVIx22Ambft9HudC+XuG/on1NY/bf5dlDti1N35eJT+QZLb4RF/5dTIG18s98w==} + + '@vitest/snapshot@4.0.9': + resolution: {integrity: sha512-r1qR4oYstPbnOjg0Vgd3E8ADJbi4ditCzqr+Z9foUrRhIy778BleNyZMeAJ2EjV+r4ASAaDsdciC9ryMy8xMMg==} + + '@vitest/spy@4.0.9': + resolution: {integrity: sha512-J9Ttsq0hDXmxmT8CUOWUr1cqqAj2FJRGTdyEjSR+NjoOGKEqkEWj+09yC0HhI8t1W6t4Ctqawl1onHgipJve1A==} + + '@vitest/utils@4.0.9': + resolution: {integrity: sha512-cEol6ygTzY4rUPvNZM19sDf7zGa35IYTm9wfzkHoT/f5jX10IOY7QleWSOh5T0e3I3WVozwK5Asom79qW8DiuQ==} + + accepts@2.0.0: + resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} + engines: {node: '>= 0.6'} + + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn@8.15.0: + resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} + engines: {node: '>=0.4.0'} + hasBin: true + + ajv-formats@3.0.1: + resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + + ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + + ajv@8.17.1: + resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + array-buffer-byte-length@1.0.2: + resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} + engines: {node: '>= 0.4'} + + array-includes@3.1.9: + resolution: {integrity: sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==} + engines: {node: '>= 0.4'} + + array.prototype.findlastindex@1.2.6: + resolution: {integrity: sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==} + engines: {node: '>= 0.4'} + + array.prototype.flat@1.3.3: + resolution: {integrity: sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==} + engines: {node: '>= 0.4'} + + array.prototype.flatmap@1.3.3: + resolution: {integrity: sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==} + engines: {node: '>= 0.4'} + + arraybuffer.prototype.slice@1.0.4: + resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} + engines: {node: '>= 0.4'} + + asap@2.0.6: + resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==} + + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} + + async-function@1.0.0: + resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} + engines: {node: '>= 0.4'} + + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + + available-typed-arrays@1.0.7: + resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} + engines: {node: '>= 0.4'} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + body-parser@2.2.0: + resolution: {integrity: sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==} + engines: {node: '>=18'} + + brace-expansion@1.1.12: + resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} + + brace-expansion@2.0.2: + resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + + bytes@3.1.2: + resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} + engines: {node: '>= 0.8'} + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + call-bind@1.0.8: + resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} + engines: {node: '>= 0.4'} + + call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + engines: {node: '>= 0.4'} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + chai@6.2.1: + resolution: {integrity: sha512-p4Z49OGG5W/WBCPSS/dH3jQ73kD6tiMmUM+bckNK6Jr5JHMG3k9bg/BvKR8lKmtVBKmOiuVaV2ws8s9oSbwysg==} + engines: {node: '>=18'} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + + component-emitter@1.3.1: + resolution: {integrity: sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + content-disposition@1.0.0: + resolution: {integrity: sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==} + engines: {node: '>= 0.6'} + + content-type@1.0.5: + resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} + engines: {node: '>= 0.6'} + + cookie-signature@1.2.2: + resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} + engines: {node: '>=6.6.0'} + + cookie@0.7.2: + resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} + engines: {node: '>= 0.6'} + + cookiejar@2.1.4: + resolution: {integrity: sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==} + + cors@2.8.5: + resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==} + engines: {node: '>= 0.10'} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + data-view-buffer@1.0.2: + resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} + engines: {node: '>= 0.4'} + + data-view-byte-length@1.0.2: + resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==} + engines: {node: '>= 0.4'} + + data-view-byte-offset@1.0.1: + resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} + engines: {node: '>= 0.4'} + + debug@3.2.7: + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + + define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} + + define-properties@1.2.1: + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} + engines: {node: '>= 0.4'} + + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + + depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + + dezalgo@1.0.4: + resolution: {integrity: sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==} + + doctrine@2.1.0: + resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} + engines: {node: '>=0.10.0'} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + ee-first@1.1.1: + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + + encodeurl@2.0.0: + resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} + engines: {node: '>= 0.8'} + + enhanced-resolve@5.18.3: + resolution: {integrity: sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==} + engines: {node: '>=10.13.0'} + + es-abstract@1.24.0: + resolution: {integrity: sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==} + engines: {node: '>= 0.4'} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-module-lexer@1.7.0: + resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + + es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + + es-shim-unscopables@1.1.0: + resolution: {integrity: sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==} + engines: {node: '>= 0.4'} + + es-to-primitive@1.3.0: + resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} + engines: {node: '>= 0.4'} + + esbuild@0.25.12: + resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} + engines: {node: '>=18'} + hasBin: true + + escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + eslint-compat-utils@0.5.1: + resolution: {integrity: sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q==} + engines: {node: '>=12'} + peerDependencies: + eslint: '>=6.0.0' + + eslint-config-prettier@10.1.8: + resolution: {integrity: sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==} + hasBin: true + peerDependencies: + eslint: '>=7.0.0' + + eslint-import-context@0.1.9: + resolution: {integrity: sha512-K9Hb+yRaGAGUbwjhFNHvSmmkZs9+zbuoe3kFQ4V1wYjrepUFYM2dZAfNtjbbj3qsPfUfsA68Bx/ICWQMi+C8Eg==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + peerDependencies: + unrs-resolver: ^1.0.0 + peerDependenciesMeta: + unrs-resolver: + optional: true + + eslint-import-resolver-node@0.3.9: + resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} + + eslint-import-resolver-typescript@4.4.4: + resolution: {integrity: sha512-1iM2zeBvrYmUNTj2vSC/90JTHDth+dfOfiNKkxApWRsTJYNrc8rOdxxIf5vazX+BiAXTeOT0UvWpGI/7qIWQOw==} + engines: {node: ^16.17.0 || >=18.6.0} + peerDependencies: + eslint: '*' + eslint-plugin-import: '*' + eslint-plugin-import-x: '*' + peerDependenciesMeta: + eslint-plugin-import: + optional: true + eslint-plugin-import-x: + optional: true + + eslint-module-utils@2.12.1: + resolution: {integrity: sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: '*' + eslint-import-resolver-node: '*' + eslint-import-resolver-typescript: '*' + eslint-import-resolver-webpack: '*' + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint: + optional: true + eslint-import-resolver-node: + optional: true + eslint-import-resolver-typescript: + optional: true + eslint-import-resolver-webpack: + optional: true + + eslint-plugin-es-x@7.8.0: + resolution: {integrity: sha512-7Ds8+wAAoV3T+LAKeu39Y5BzXCrGKrcISfgKEqTS4BDN8SFEDQd0S43jiQ8vIa3wUKD07qitZdfzlenSi8/0qQ==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + eslint: '>=8' + + eslint-plugin-import@2.32.0: + resolution: {integrity: sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9 + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + + eslint-plugin-n@17.23.1: + resolution: {integrity: sha512-68PealUpYoHOBh332JLLD9Sj7OQUDkFpmcfqt8R9sySfFSeuGJjMTJQvCRRB96zO3A/PELRLkPrzsHmzEFQQ5A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: '>=8.23.0' + + eslint-plugin-simple-import-sort@12.1.1: + resolution: {integrity: sha512-6nuzu4xwQtE3332Uz0to+TxDQYRLTKRESSc2hefVT48Zc8JthmN23Gx9lnYhu0FtkRSL1oxny3kJ2aveVhmOVA==} + peerDependencies: + eslint: '>=5.0.0' + + eslint-scope@8.4.0: + resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-visitor-keys@4.2.1: + resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint@9.39.1: + resolution: {integrity: sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true + + espree@10.4.0: + resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + esquery@1.6.0: + resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} + engines: {node: '>=0.10'} + + esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + etag@1.8.1: + resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} + engines: {node: '>= 0.6'} + + eventsource-parser@3.0.6: + resolution: {integrity: sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==} + engines: {node: '>=18.0.0'} + + eventsource@3.0.7: + resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==} + engines: {node: '>=18.0.0'} + + expect-type@1.2.2: + resolution: {integrity: sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==} + engines: {node: '>=12.0.0'} + + express-rate-limit@7.5.1: + resolution: {integrity: sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw==} + engines: {node: '>= 16'} + peerDependencies: + express: '>= 4.11' + + express@5.1.0: + resolution: {integrity: sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==} + engines: {node: '>= 18'} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + + fast-safe-stringify@2.1.1: + resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} + + fast-uri@3.1.0: + resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + file-entry-cache@8.0.0: + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} + engines: {node: '>=16.0.0'} + + finalhandler@2.1.0: + resolution: {integrity: sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==} + engines: {node: '>= 0.8'} + + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + flat-cache@4.0.1: + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} + engines: {node: '>=16'} + + flatted@3.3.3: + resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} + + for-each@0.3.5: + resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} + engines: {node: '>= 0.4'} + + form-data@4.0.4: + resolution: {integrity: sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==} + engines: {node: '>= 6'} + + formidable@3.5.4: + resolution: {integrity: sha512-YikH+7CUTOtP44ZTnUhR7Ic2UASBPOqmaRkRKxRbywPTe5VxF7RRCck4af9wutiZ/QKM5nME9Bie2fFaPz5Gug==} + engines: {node: '>=14.0.0'} + + forwarded@0.2.0: + resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} + engines: {node: '>= 0.6'} + + fresh@2.0.0: + resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} + engines: {node: '>= 0.8'} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + function.prototype.name@1.1.8: + resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==} + engines: {node: '>= 0.4'} + + functions-have-names@1.2.3: + resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + + generator-function@2.0.1: + resolution: {integrity: sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==} + engines: {node: '>= 0.4'} + + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + get-symbol-description@1.1.0: + resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} + engines: {node: '>= 0.4'} + + get-tsconfig@4.13.0: + resolution: {integrity: sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==} + + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + globals@14.0.0: + resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} + engines: {node: '>=18'} + + globals@15.15.0: + resolution: {integrity: sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==} + engines: {node: '>=18'} + + globalthis@1.0.4: + resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} + engines: {node: '>= 0.4'} + + globrex@0.1.2: + resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + has-bigints@1.1.0: + resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} + engines: {node: '>= 0.4'} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + + has-proto@1.2.0: + resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==} + engines: {node: '>= 0.4'} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + http-errors@2.0.0: + resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} + engines: {node: '>= 0.8'} + + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + + iconv-lite@0.7.0: + resolution: {integrity: sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==} + engines: {node: '>=0.10.0'} + + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + ignore@7.0.5: + resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} + engines: {node: '>= 4'} + + import-fresh@3.3.1: + resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} + engines: {node: '>=6'} + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + internal-slot@1.1.0: + resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} + engines: {node: '>= 0.4'} + + ipaddr.js@1.9.1: + resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} + engines: {node: '>= 0.10'} + + is-array-buffer@3.0.5: + resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} + engines: {node: '>= 0.4'} + + is-async-function@2.1.1: + resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==} + engines: {node: '>= 0.4'} + + is-bigint@1.1.0: + resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==} + engines: {node: '>= 0.4'} + + is-boolean-object@1.2.2: + resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==} + engines: {node: '>= 0.4'} + + is-bun-module@2.0.0: + resolution: {integrity: sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==} + + is-callable@1.2.7: + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} + engines: {node: '>= 0.4'} + + is-core-module@2.16.1: + resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} + engines: {node: '>= 0.4'} + + is-data-view@1.0.2: + resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==} + engines: {node: '>= 0.4'} + + is-date-object@1.1.0: + resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} + engines: {node: '>= 0.4'} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-finalizationregistry@1.1.1: + resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==} + engines: {node: '>= 0.4'} + + is-generator-function@1.1.2: + resolution: {integrity: sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==} + engines: {node: '>= 0.4'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-map@2.0.3: + resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} + engines: {node: '>= 0.4'} + + is-negative-zero@2.0.3: + resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} + engines: {node: '>= 0.4'} + + is-number-object@1.1.1: + resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==} + engines: {node: '>= 0.4'} + + is-promise@4.0.0: + resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} + + is-regex@1.2.1: + resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} + engines: {node: '>= 0.4'} + + is-set@2.0.3: + resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} + engines: {node: '>= 0.4'} + + is-shared-array-buffer@1.0.4: + resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} + engines: {node: '>= 0.4'} + + is-string@1.1.1: + resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==} + engines: {node: '>= 0.4'} + + is-symbol@1.1.1: + resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==} + engines: {node: '>= 0.4'} + + is-typed-array@1.1.15: + resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} + engines: {node: '>= 0.4'} + + is-weakmap@2.0.2: + resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} + engines: {node: '>= 0.4'} + + is-weakref@1.1.1: + resolution: {integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==} + engines: {node: '>= 0.4'} + + is-weakset@2.0.4: + resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} + engines: {node: '>= 0.4'} + + isarray@2.0.5: + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + jose@6.1.3: + resolution: {integrity: sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==} + + js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + + json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + + json-schema-typed@8.0.2: + resolution: {integrity: sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==} + + json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + + json5@1.0.2: + resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} + hasBin: true + + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + media-typer@1.1.0: + resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} + engines: {node: '>= 0.8'} + + merge-descriptors@2.0.0: + resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} + engines: {node: '>=18'} + + methods@1.1.2: + resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} + engines: {node: '>= 0.6'} + + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-db@1.54.0: + resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + mime-types@3.0.1: + resolution: {integrity: sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==} + engines: {node: '>= 0.6'} + + mime@2.6.0: + resolution: {integrity: sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==} + engines: {node: '>=4.0.0'} + hasBin: true + + minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + + minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + napi-postinstall@0.3.4: + resolution: {integrity: sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + hasBin: true + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + negotiator@1.0.0: + resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} + engines: {node: '>= 0.6'} + + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} + engines: {node: '>= 0.4'} + + object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + + object.assign@4.1.7: + resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} + engines: {node: '>= 0.4'} + + object.fromentries@2.0.8: + resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} + engines: {node: '>= 0.4'} + + object.groupby@1.0.3: + resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==} + engines: {node: '>= 0.4'} + + object.values@1.2.1: + resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} + engines: {node: '>= 0.4'} + + on-finished@2.4.1: + resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} + engines: {node: '>= 0.8'} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} + + own-keys@1.0.1: + resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} + engines: {node: '>= 0.4'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + + parseurl@1.3.3: + resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} + engines: {node: '>= 0.8'} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + path-to-regexp@8.3.0: + resolution: {integrity: sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==} + + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@4.0.3: + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + engines: {node: '>=12'} + + pkce-challenge@5.0.0: + resolution: {integrity: sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ==} + engines: {node: '>=16.20.0'} + + possible-typed-array-names@1.1.0: + resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} + engines: {node: '>= 0.4'} + + postcss@8.5.6: + resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} + engines: {node: ^10 || ^12 || >=14} + + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + + prettier@3.6.2: + resolution: {integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==} + engines: {node: '>=14'} + hasBin: true + + proxy-addr@2.0.7: + resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} + engines: {node: '>= 0.10'} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + qs@6.14.0: + resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} + engines: {node: '>=0.6'} + + range-parser@1.2.1: + resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} + engines: {node: '>= 0.6'} + + raw-body@3.0.1: + resolution: {integrity: sha512-9G8cA+tuMS75+6G/TzW8OtLzmBDMo8p1JRxN5AZ+LAp8uxGA8V8GZm4GQ4/N5QNQEnLmg6SS7wyuSmbKepiKqA==} + engines: {node: '>= 0.10'} + + reflect.getprototypeof@1.0.10: + resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} + engines: {node: '>= 0.4'} + + regexp.prototype.flags@1.5.4: + resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} + engines: {node: '>= 0.4'} + + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + + resolve@1.22.11: + resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==} + engines: {node: '>= 0.4'} + hasBin: true + + rollup@4.53.2: + resolution: {integrity: sha512-MHngMYwGJVi6Fmnk6ISmnk7JAHRNF0UkuucA0CUW3N3a4KnONPEZz+vUanQP/ZC/iY1Qkf3bwPWzyY84wEks1g==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + router@2.2.0: + resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} + engines: {node: '>= 18'} + + safe-array-concat@1.1.3: + resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} + engines: {node: '>=0.4'} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + safe-push-apply@1.0.0: + resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} + engines: {node: '>= 0.4'} + + safe-regex-test@1.1.0: + resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} + engines: {node: '>= 0.4'} + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.7.3: + resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} + engines: {node: '>=10'} + hasBin: true + + send@1.2.0: + resolution: {integrity: sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==} + engines: {node: '>= 18'} + + serve-static@2.2.0: + resolution: {integrity: sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==} + engines: {node: '>= 18'} + + set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} + + set-function-name@2.0.2: + resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} + engines: {node: '>= 0.4'} + + set-proto@1.0.0: + resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} + engines: {node: '>= 0.4'} + + setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + side-channel-list@1.0.0: + resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} + engines: {node: '>= 0.4'} + + side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + + side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + + side-channel@1.1.0: + resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} + engines: {node: '>= 0.4'} + + siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + stable-hash-x@0.2.0: + resolution: {integrity: sha512-o3yWv49B/o4QZk5ZcsALc6t0+eCelPc44zZsLtCQnZPDwFpDYSWcDnrv2TtMmMbQ7uKo3J0HTURCqckw23czNQ==} + engines: {node: '>=12.0.0'} + + stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + + statuses@2.0.1: + resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} + engines: {node: '>= 0.8'} + + statuses@2.0.2: + resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} + engines: {node: '>= 0.8'} + + std-env@3.10.0: + resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} + + stop-iteration-iterator@1.1.0: + resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} + engines: {node: '>= 0.4'} + + string.prototype.trim@1.2.10: + resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==} + engines: {node: '>= 0.4'} + + string.prototype.trimend@1.0.9: + resolution: {integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==} + engines: {node: '>= 0.4'} + + string.prototype.trimstart@1.0.8: + resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} + engines: {node: '>= 0.4'} + + strip-bom@3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + superagent@10.2.3: + resolution: {integrity: sha512-y/hkYGeXAj7wUMjxRbB21g/l6aAEituGXM9Rwl4o20+SX3e8YOSV6BxFXl+dL3Uk0mjSL3kCbNkwURm8/gEDig==} + engines: {node: '>=14.18.0'} + + supertest@7.1.4: + resolution: {integrity: sha512-tjLPs7dVyqgItVFirHYqe2T+MfWc2VOBQ8QFKKbWTA3PU7liZR8zoSpAi/C1k1ilm9RsXIKYf197oap9wXGVYg==} + engines: {node: '>=14.18.0'} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + tapable@2.3.0: + resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} + engines: {node: '>=6'} + + tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + + tinyexec@0.3.2: + resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + + tinyglobby@0.2.15: + resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} + engines: {node: '>=12.0.0'} + + tinyrainbow@3.0.3: + resolution: {integrity: sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==} + engines: {node: '>=14.0.0'} + + toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + + ts-api-utils@2.1.0: + resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==} + engines: {node: '>=18.12'} + peerDependencies: + typescript: '>=4.8.4' + + ts-declaration-location@1.0.7: + resolution: {integrity: sha512-EDyGAwH1gO0Ausm9gV6T2nUvBgXT5kGoCMJPllOaooZ+4VvJiKBdZE7wK18N1deEowhcUptS+5GXZK8U/fvpwA==} + peerDependencies: + typescript: '>=4.0.0' + + tsconfck@3.1.6: + resolution: {integrity: sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==} + engines: {node: ^18 || >=20} + hasBin: true + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + + tsconfig-paths@3.15.0: + resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + tsx@4.20.6: + resolution: {integrity: sha512-ytQKuwgmrrkDTFP4LjR0ToE2nqgy886GpvRSpU0JAnrdBYppuY5rLkRUYPU1yCryb24SsKBTL/hlDQAEFVwtZg==} + engines: {node: '>=18.0.0'} + hasBin: true + + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + + type-is@2.0.1: + resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} + engines: {node: '>= 0.6'} + + typed-array-buffer@1.0.3: + resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} + engines: {node: '>= 0.4'} + + typed-array-byte-length@1.0.3: + resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==} + engines: {node: '>= 0.4'} + + typed-array-byte-offset@1.0.4: + resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==} + engines: {node: '>= 0.4'} + + typed-array-length@1.0.7: + resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} + engines: {node: '>= 0.4'} + + typescript-eslint@8.49.0: + resolution: {integrity: sha512-zRSVH1WXD0uXczCXw+nsdjGPUdx4dfrs5VQoHnUWmv1U3oNlAKv4FUNdLDhVUg+gYn+a5hUESqch//Rv5wVhrg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + + unbox-primitive@1.1.0: + resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} + engines: {node: '>= 0.4'} + + undici-types@7.16.0: + resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} + + unpipe@1.0.0: + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} + engines: {node: '>= 0.8'} + + unrs-resolver@1.11.1: + resolution: {integrity: sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==} + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + vary@1.1.2: + resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} + engines: {node: '>= 0.8'} + + vite-tsconfig-paths@5.1.4: + resolution: {integrity: sha512-cYj0LRuLV2c2sMqhqhGpaO3LretdtMn/BVX4cPLanIZuwwrkVl+lK84E/miEXkCHWXuq65rhNN4rXsBcOB3S4w==} + peerDependencies: + vite: '*' + peerDependenciesMeta: + vite: + optional: true + + vite@7.2.2: + resolution: {integrity: sha512-BxAKBWmIbrDgrokdGZH1IgkIk/5mMHDreLDmCJ0qpyJaAteP8NvMhkwr/ZCQNqNH97bw/dANTE9PDzqwJghfMQ==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + jiti: '>=1.21.0' + less: ^4.0.0 + lightningcss: ^1.21.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vitest@4.0.9: + resolution: {integrity: sha512-E0Ja2AX4th+CG33yAFRC+d1wFx2pzU5r6HtG6LiPSE04flaE0qB6YyjSw9ZcpJAtVPfsvZGtJlKWZpuW7EHRxg==} + engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@types/debug': ^4.1.12 + '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 + '@vitest/browser-playwright': 4.0.9 + '@vitest/browser-preview': 4.0.9 + '@vitest/browser-webdriverio': 4.0.9 + '@vitest/ui': 4.0.9 + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@types/debug': + optional: true + '@types/node': + optional: true + '@vitest/browser-playwright': + optional: true + '@vitest/browser-preview': + optional: true + '@vitest/browser-webdriverio': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + + which-boxed-primitive@1.1.1: + resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} + engines: {node: '>= 0.4'} + + which-builtin-type@1.2.1: + resolution: {integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==} + engines: {node: '>= 0.4'} + + which-collection@1.0.2: + resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} + engines: {node: '>= 0.4'} + + which-typed-array@1.1.19: + resolution: {integrity: sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==} + engines: {node: '>= 0.4'} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true + + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + ws@8.18.3: + resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + + zod-to-json-schema@3.25.0: + resolution: {integrity: sha512-HvWtU2UG41LALjajJrML6uQejQhNJx+JBO9IflpSja4R03iNWfKXrj6W2h7ljuLyc1nKS+9yDyL/9tD1U/yBnQ==} + peerDependencies: + zod: ^3.25 || ^4 + + zod@3.25.76: + resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} + +snapshots: + + '@cfworker/json-schema@4.1.1': {} + + '@emnapi/core@1.7.1': + dependencies: + '@emnapi/wasi-threads': 1.1.0 + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.7.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/wasi-threads@1.1.0': + dependencies: + tslib: 2.8.1 + optional: true + + '@esbuild/aix-ppc64@0.25.12': + optional: true + + '@esbuild/android-arm64@0.25.12': + optional: true + + '@esbuild/android-arm@0.25.12': + optional: true + + '@esbuild/android-x64@0.25.12': + optional: true + + '@esbuild/darwin-arm64@0.25.12': + optional: true + + '@esbuild/darwin-x64@0.25.12': + optional: true + + '@esbuild/freebsd-arm64@0.25.12': + optional: true + + '@esbuild/freebsd-x64@0.25.12': + optional: true + + '@esbuild/linux-arm64@0.25.12': + optional: true + + '@esbuild/linux-arm@0.25.12': + optional: true + + '@esbuild/linux-ia32@0.25.12': + optional: true + + '@esbuild/linux-loong64@0.25.12': + optional: true + + '@esbuild/linux-mips64el@0.25.12': + optional: true + + '@esbuild/linux-ppc64@0.25.12': + optional: true + + '@esbuild/linux-riscv64@0.25.12': + optional: true + + '@esbuild/linux-s390x@0.25.12': + optional: true + + '@esbuild/linux-x64@0.25.12': + optional: true + + '@esbuild/netbsd-arm64@0.25.12': + optional: true + + '@esbuild/netbsd-x64@0.25.12': + optional: true + + '@esbuild/openbsd-arm64@0.25.12': + optional: true + + '@esbuild/openbsd-x64@0.25.12': + optional: true + + '@esbuild/openharmony-arm64@0.25.12': + optional: true + + '@esbuild/sunos-x64@0.25.12': + optional: true + + '@esbuild/win32-arm64@0.25.12': + optional: true + + '@esbuild/win32-ia32@0.25.12': + optional: true + + '@esbuild/win32-x64@0.25.12': + optional: true + + '@eslint-community/eslint-utils@4.9.0(eslint@9.39.1)': + dependencies: + eslint: 9.39.1 + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.12.2': {} + + '@eslint/config-array@0.21.1': + dependencies: + '@eslint/object-schema': 2.1.7 + debug: 4.4.3 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + + '@eslint/config-helpers@0.4.2': + dependencies: + '@eslint/core': 0.17.0 + + '@eslint/core@0.17.0': + dependencies: + '@types/json-schema': 7.0.15 + + '@eslint/eslintrc@3.3.1': + dependencies: + ajv: 6.12.6 + debug: 4.4.3 + espree: 10.4.0 + globals: 14.0.0 + ignore: 5.3.2 + import-fresh: 3.3.1 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + '@eslint/js@9.39.1': {} + + '@eslint/object-schema@2.1.7': {} + + '@eslint/plugin-kit@0.4.1': + dependencies: + '@eslint/core': 0.17.0 + levn: 0.4.1 + + '@humanfs/core@0.19.1': {} + + '@humanfs/node@0.16.7': + dependencies: + '@humanfs/core': 0.19.1 + '@humanwhocodes/retry': 0.4.3 + + '@humanwhocodes/module-importer@1.0.1': {} + + '@humanwhocodes/retry@0.4.3': {} + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@napi-rs/wasm-runtime@0.2.12': + dependencies: + '@emnapi/core': 1.7.1 + '@emnapi/runtime': 1.7.1 + '@tybys/wasm-util': 0.10.1 + optional: true + + '@noble/hashes@1.8.0': {} + + '@paralleldrive/cuid2@2.3.1': + dependencies: + '@noble/hashes': 1.8.0 + + '@rollup/rollup-android-arm-eabi@4.53.2': + optional: true + + '@rollup/rollup-android-arm64@4.53.2': + optional: true + + '@rollup/rollup-darwin-arm64@4.53.2': + optional: true + + '@rollup/rollup-darwin-x64@4.53.2': + optional: true + + '@rollup/rollup-freebsd-arm64@4.53.2': + optional: true + + '@rollup/rollup-freebsd-x64@4.53.2': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.53.2': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.53.2': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.53.2': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.53.2': + optional: true + + '@rollup/rollup-linux-loong64-gnu@4.53.2': + optional: true + + '@rollup/rollup-linux-ppc64-gnu@4.53.2': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.53.2': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.53.2': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.53.2': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.53.2': + optional: true + + '@rollup/rollup-linux-x64-musl@4.53.2': + optional: true + + '@rollup/rollup-openharmony-arm64@4.53.2': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.53.2': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.53.2': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.53.2': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.53.2': + optional: true + + '@rtsao/scc@1.1.0': {} + + '@standard-schema/spec@1.0.0': {} + + '@tybys/wasm-util@0.10.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@types/body-parser@1.19.6': + dependencies: + '@types/connect': 3.4.38 + '@types/node': 24.10.3 + + '@types/chai@5.2.3': + dependencies: + '@types/deep-eql': 4.0.2 + assertion-error: 2.0.1 + + '@types/connect@3.4.38': + dependencies: + '@types/node': 24.10.3 + + '@types/content-type@1.1.9': {} + + '@types/cookiejar@2.1.5': {} + + '@types/cors@2.8.19': + dependencies: + '@types/node': 24.10.3 + + '@types/cross-spawn@6.0.6': + dependencies: + '@types/node': 24.10.3 + + '@types/deep-eql@4.0.2': {} + + '@types/estree@1.0.8': {} + + '@types/eventsource@1.1.15': {} + + '@types/express-serve-static-core@5.1.0': + dependencies: + '@types/node': 24.10.3 + '@types/qs': 6.14.0 + '@types/range-parser': 1.2.7 + '@types/send': 1.2.1 + + '@types/express@5.0.5': + dependencies: + '@types/body-parser': 1.19.6 + '@types/express-serve-static-core': 5.1.0 + '@types/serve-static': 1.15.10 + + '@types/http-errors@2.0.5': {} + + '@types/json-schema@7.0.15': {} + + '@types/json5@0.0.29': {} + + '@types/methods@1.1.4': {} + + '@types/mime@1.3.5': {} + + '@types/node@24.10.3': + dependencies: + undici-types: 7.16.0 + + '@types/qs@6.14.0': {} + + '@types/range-parser@1.2.7': {} + + '@types/send@0.17.6': + dependencies: + '@types/mime': 1.3.5 + '@types/node': 24.10.3 + + '@types/send@1.2.1': + dependencies: + '@types/node': 24.10.3 + + '@types/serve-static@1.15.10': + dependencies: + '@types/http-errors': 2.0.5 + '@types/node': 24.10.3 + '@types/send': 0.17.6 + + '@types/superagent@8.1.9': + dependencies: + '@types/cookiejar': 2.1.5 + '@types/methods': 1.1.4 + '@types/node': 24.10.3 + form-data: 4.0.4 + + '@types/supertest@6.0.3': + dependencies: + '@types/methods': 1.1.4 + '@types/superagent': 8.1.9 + + '@types/ws@8.18.1': + dependencies: + '@types/node': 24.10.3 + + '@typescript-eslint/eslint-plugin@8.49.0(@typescript-eslint/parser@8.49.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3)': + dependencies: + '@eslint-community/regexpp': 4.12.2 + '@typescript-eslint/parser': 8.49.0(eslint@9.39.1)(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.49.0 + '@typescript-eslint/type-utils': 8.49.0(eslint@9.39.1)(typescript@5.9.3) + '@typescript-eslint/utils': 8.49.0(eslint@9.39.1)(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.49.0 + eslint: 9.39.1 + ignore: 7.0.5 + natural-compare: 1.4.0 + ts-api-utils: 2.1.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@8.49.0(eslint@9.39.1)(typescript@5.9.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.49.0 + '@typescript-eslint/types': 8.49.0 + '@typescript-eslint/typescript-estree': 8.49.0(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.49.0 + debug: 4.4.3 + eslint: 9.39.1 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/project-service@8.49.0(typescript@5.9.3)': + dependencies: + '@typescript-eslint/tsconfig-utils': 8.49.0(typescript@5.9.3) + '@typescript-eslint/types': 8.49.0 + debug: 4.4.3 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/scope-manager@8.49.0': + dependencies: + '@typescript-eslint/types': 8.49.0 + '@typescript-eslint/visitor-keys': 8.49.0 + + '@typescript-eslint/tsconfig-utils@8.49.0(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 + + '@typescript-eslint/type-utils@8.49.0(eslint@9.39.1)(typescript@5.9.3)': + dependencies: + '@typescript-eslint/types': 8.49.0 + '@typescript-eslint/typescript-estree': 8.49.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.49.0(eslint@9.39.1)(typescript@5.9.3) + debug: 4.4.3 + eslint: 9.39.1 + ts-api-utils: 2.1.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/types@8.49.0': {} + + '@typescript-eslint/typescript-estree@8.49.0(typescript@5.9.3)': + dependencies: + '@typescript-eslint/project-service': 8.49.0(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.49.0(typescript@5.9.3) + '@typescript-eslint/types': 8.49.0 + '@typescript-eslint/visitor-keys': 8.49.0 + debug: 4.4.3 + minimatch: 9.0.5 + semver: 7.7.3 + tinyglobby: 0.2.15 + ts-api-utils: 2.1.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@8.49.0(eslint@9.39.1)(typescript@5.9.3)': + dependencies: + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1) + '@typescript-eslint/scope-manager': 8.49.0 + '@typescript-eslint/types': 8.49.0 + '@typescript-eslint/typescript-estree': 8.49.0(typescript@5.9.3) + eslint: 9.39.1 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/visitor-keys@8.49.0': + dependencies: + '@typescript-eslint/types': 8.49.0 + eslint-visitor-keys: 4.2.1 + + '@typescript/native-preview-darwin-arm64@7.0.0-dev.20251108.1': + optional: true + + '@typescript/native-preview-darwin-x64@7.0.0-dev.20251108.1': + optional: true + + '@typescript/native-preview-linux-arm64@7.0.0-dev.20251108.1': + optional: true + + '@typescript/native-preview-linux-arm@7.0.0-dev.20251108.1': + optional: true + + '@typescript/native-preview-linux-x64@7.0.0-dev.20251108.1': + optional: true + + '@typescript/native-preview-win32-arm64@7.0.0-dev.20251108.1': + optional: true + + '@typescript/native-preview-win32-x64@7.0.0-dev.20251108.1': + optional: true + + '@typescript/native-preview@7.0.0-dev.20251108.1': + optionalDependencies: + '@typescript/native-preview-darwin-arm64': 7.0.0-dev.20251108.1 + '@typescript/native-preview-darwin-x64': 7.0.0-dev.20251108.1 + '@typescript/native-preview-linux-arm': 7.0.0-dev.20251108.1 + '@typescript/native-preview-linux-arm64': 7.0.0-dev.20251108.1 + '@typescript/native-preview-linux-x64': 7.0.0-dev.20251108.1 + '@typescript/native-preview-win32-arm64': 7.0.0-dev.20251108.1 + '@typescript/native-preview-win32-x64': 7.0.0-dev.20251108.1 + + '@unrs/resolver-binding-android-arm-eabi@1.11.1': + optional: true + + '@unrs/resolver-binding-android-arm64@1.11.1': + optional: true + + '@unrs/resolver-binding-darwin-arm64@1.11.1': + optional: true + + '@unrs/resolver-binding-darwin-x64@1.11.1': + optional: true + + '@unrs/resolver-binding-freebsd-x64@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-arm-musleabihf@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-arm64-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-arm64-musl@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-ppc64-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-riscv64-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-riscv64-musl@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-s390x-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-x64-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-x64-musl@1.11.1': + optional: true + + '@unrs/resolver-binding-wasm32-wasi@1.11.1': + dependencies: + '@napi-rs/wasm-runtime': 0.2.12 + optional: true + + '@unrs/resolver-binding-win32-arm64-msvc@1.11.1': + optional: true + + '@unrs/resolver-binding-win32-ia32-msvc@1.11.1': + optional: true + + '@unrs/resolver-binding-win32-x64-msvc@1.11.1': + optional: true + + '@vitest/expect@4.0.9': + dependencies: + '@standard-schema/spec': 1.0.0 + '@types/chai': 5.2.3 + '@vitest/spy': 4.0.9 + '@vitest/utils': 4.0.9 + chai: 6.2.1 + tinyrainbow: 3.0.3 + + '@vitest/mocker@4.0.9(vite@7.2.2(@types/node@24.10.3)(tsx@4.20.6))': + dependencies: + '@vitest/spy': 4.0.9 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + vite: 7.2.2(@types/node@24.10.3)(tsx@4.20.6) + + '@vitest/pretty-format@4.0.9': + dependencies: + tinyrainbow: 3.0.3 + + '@vitest/runner@4.0.9': + dependencies: + '@vitest/utils': 4.0.9 + pathe: 2.0.3 + + '@vitest/snapshot@4.0.9': + dependencies: + '@vitest/pretty-format': 4.0.9 + magic-string: 0.30.21 + pathe: 2.0.3 + + '@vitest/spy@4.0.9': {} + + '@vitest/utils@4.0.9': + dependencies: + '@vitest/pretty-format': 4.0.9 + tinyrainbow: 3.0.3 + + accepts@2.0.0: + dependencies: + mime-types: 3.0.1 + negotiator: 1.0.0 + + acorn-jsx@5.3.2(acorn@8.15.0): + dependencies: + acorn: 8.15.0 + + acorn@8.15.0: {} + + ajv-formats@3.0.1(ajv@8.17.1): + optionalDependencies: + ajv: 8.17.1 + + ajv@6.12.6: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + ajv@8.17.1: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.1.0 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + argparse@2.0.1: {} + + array-buffer-byte-length@1.0.2: + dependencies: + call-bound: 1.0.4 + is-array-buffer: 3.0.5 + + array-includes@3.1.9: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + is-string: 1.1.1 + math-intrinsics: 1.1.0 + + array.prototype.findlastindex@1.2.6: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + es-shim-unscopables: 1.1.0 + + array.prototype.flat@1.3.3: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-shim-unscopables: 1.1.0 + + array.prototype.flatmap@1.3.3: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-shim-unscopables: 1.1.0 + + arraybuffer.prototype.slice@1.0.4: + dependencies: + array-buffer-byte-length: 1.0.2 + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + is-array-buffer: 3.0.5 + + asap@2.0.6: {} + + assertion-error@2.0.1: {} + + async-function@1.0.0: {} + + asynckit@0.4.0: {} + + available-typed-arrays@1.0.7: + dependencies: + possible-typed-array-names: 1.1.0 + + balanced-match@1.0.2: {} + + body-parser@2.2.0: + dependencies: + bytes: 3.1.2 + content-type: 1.0.5 + debug: 4.4.3 + http-errors: 2.0.0 + iconv-lite: 0.6.3 + on-finished: 2.4.1 + qs: 6.14.0 + raw-body: 3.0.1 + type-is: 2.0.1 + transitivePeerDependencies: + - supports-color + + brace-expansion@1.1.12: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@2.0.2: + dependencies: + balanced-match: 1.0.2 + + bytes@3.1.2: {} + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + call-bind@1.0.8: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + get-intrinsic: 1.3.0 + set-function-length: 1.2.2 + + call-bound@1.0.4: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + + callsites@3.1.0: {} + + chai@6.2.1: {} + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + + component-emitter@1.3.1: {} + + concat-map@0.0.1: {} + + content-disposition@1.0.0: + dependencies: + safe-buffer: 5.2.1 + + content-type@1.0.5: {} + + cookie-signature@1.2.2: {} + + cookie@0.7.2: {} + + cookiejar@2.1.4: {} + + cors@2.8.5: + dependencies: + object-assign: 4.1.1 + vary: 1.1.2 + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + data-view-buffer@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + data-view-byte-length@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + data-view-byte-offset@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + debug@3.2.7: + dependencies: + ms: 2.1.3 + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + deep-is@0.1.4: {} + + define-data-property@1.1.4: + dependencies: + es-define-property: 1.0.1 + es-errors: 1.3.0 + gopd: 1.2.0 + + define-properties@1.2.1: + dependencies: + define-data-property: 1.1.4 + has-property-descriptors: 1.0.2 + object-keys: 1.1.1 + + delayed-stream@1.0.0: {} + + depd@2.0.0: {} + + dezalgo@1.0.4: + dependencies: + asap: 2.0.6 + wrappy: 1.0.2 + + doctrine@2.1.0: + dependencies: + esutils: 2.0.3 + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + ee-first@1.1.1: {} + + encodeurl@2.0.0: {} + + enhanced-resolve@5.18.3: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.3.0 + + es-abstract@1.24.0: + dependencies: + array-buffer-byte-length: 1.0.2 + arraybuffer.prototype.slice: 1.0.4 + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 + data-view-buffer: 1.0.2 + data-view-byte-length: 1.0.2 + data-view-byte-offset: 1.0.1 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + es-set-tostringtag: 2.1.0 + es-to-primitive: 1.3.0 + function.prototype.name: 1.1.8 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + get-symbol-description: 1.1.0 + globalthis: 1.0.4 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + has-proto: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + internal-slot: 1.1.0 + is-array-buffer: 3.0.5 + is-callable: 1.2.7 + is-data-view: 1.0.2 + is-negative-zero: 2.0.3 + is-regex: 1.2.1 + is-set: 2.0.3 + is-shared-array-buffer: 1.0.4 + is-string: 1.1.1 + is-typed-array: 1.1.15 + is-weakref: 1.1.1 + math-intrinsics: 1.1.0 + object-inspect: 1.13.4 + object-keys: 1.1.1 + object.assign: 4.1.7 + own-keys: 1.0.1 + regexp.prototype.flags: 1.5.4 + safe-array-concat: 1.1.3 + safe-push-apply: 1.0.0 + safe-regex-test: 1.1.0 + set-proto: 1.0.0 + stop-iteration-iterator: 1.1.0 + string.prototype.trim: 1.2.10 + string.prototype.trimend: 1.0.9 + string.prototype.trimstart: 1.0.8 + typed-array-buffer: 1.0.3 + typed-array-byte-length: 1.0.3 + typed-array-byte-offset: 1.0.4 + typed-array-length: 1.0.7 + unbox-primitive: 1.1.0 + which-typed-array: 1.1.19 + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-module-lexer@1.7.0: {} + + es-object-atoms@1.1.1: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + es-shim-unscopables@1.1.0: + dependencies: + hasown: 2.0.2 + + es-to-primitive@1.3.0: + dependencies: + is-callable: 1.2.7 + is-date-object: 1.1.0 + is-symbol: 1.1.1 + + esbuild@0.25.12: + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.12 + '@esbuild/android-arm': 0.25.12 + '@esbuild/android-arm64': 0.25.12 + '@esbuild/android-x64': 0.25.12 + '@esbuild/darwin-arm64': 0.25.12 + '@esbuild/darwin-x64': 0.25.12 + '@esbuild/freebsd-arm64': 0.25.12 + '@esbuild/freebsd-x64': 0.25.12 + '@esbuild/linux-arm': 0.25.12 + '@esbuild/linux-arm64': 0.25.12 + '@esbuild/linux-ia32': 0.25.12 + '@esbuild/linux-loong64': 0.25.12 + '@esbuild/linux-mips64el': 0.25.12 + '@esbuild/linux-ppc64': 0.25.12 + '@esbuild/linux-riscv64': 0.25.12 + '@esbuild/linux-s390x': 0.25.12 + '@esbuild/linux-x64': 0.25.12 + '@esbuild/netbsd-arm64': 0.25.12 + '@esbuild/netbsd-x64': 0.25.12 + '@esbuild/openbsd-arm64': 0.25.12 + '@esbuild/openbsd-x64': 0.25.12 + '@esbuild/openharmony-arm64': 0.25.12 + '@esbuild/sunos-x64': 0.25.12 + '@esbuild/win32-arm64': 0.25.12 + '@esbuild/win32-ia32': 0.25.12 + '@esbuild/win32-x64': 0.25.12 + + escape-html@1.0.3: {} + + escape-string-regexp@4.0.0: {} + + eslint-compat-utils@0.5.1(eslint@9.39.1): + dependencies: + eslint: 9.39.1 + semver: 7.7.3 + + eslint-config-prettier@10.1.8(eslint@9.39.1): + dependencies: + eslint: 9.39.1 + + eslint-import-context@0.1.9(unrs-resolver@1.11.1): + dependencies: + get-tsconfig: 4.13.0 + stable-hash-x: 0.2.0 + optionalDependencies: + unrs-resolver: 1.11.1 + + eslint-import-resolver-node@0.3.9: + dependencies: + debug: 3.2.7 + is-core-module: 2.16.1 + resolve: 1.22.11 + transitivePeerDependencies: + - supports-color + + eslint-import-resolver-typescript@4.4.4(eslint-plugin-import@2.32.0)(eslint@9.39.1): + dependencies: + debug: 4.4.3 + eslint: 9.39.1 + eslint-import-context: 0.1.9(unrs-resolver@1.11.1) + get-tsconfig: 4.13.0 + is-bun-module: 2.0.0 + stable-hash-x: 0.2.0 + tinyglobby: 0.2.15 + unrs-resolver: 1.11.1 + optionalDependencies: + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.49.0(eslint@9.39.1)(typescript@5.9.3))(eslint-import-resolver-typescript@4.4.4)(eslint@9.39.1) + transitivePeerDependencies: + - supports-color + + eslint-module-utils@2.12.1(@typescript-eslint/parser@8.49.0(eslint@9.39.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@4.4.4)(eslint@9.39.1): + dependencies: + debug: 3.2.7 + optionalDependencies: + '@typescript-eslint/parser': 8.49.0(eslint@9.39.1)(typescript@5.9.3) + eslint: 9.39.1 + eslint-import-resolver-node: 0.3.9 + eslint-import-resolver-typescript: 4.4.4(eslint-plugin-import@2.32.0)(eslint@9.39.1) + transitivePeerDependencies: + - supports-color + + eslint-plugin-es-x@7.8.0(eslint@9.39.1): + dependencies: + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1) + '@eslint-community/regexpp': 4.12.2 + eslint: 9.39.1 + eslint-compat-utils: 0.5.1(eslint@9.39.1) + + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.49.0(eslint@9.39.1)(typescript@5.9.3))(eslint-import-resolver-typescript@4.4.4)(eslint@9.39.1): + dependencies: + '@rtsao/scc': 1.1.0 + array-includes: 3.1.9 + array.prototype.findlastindex: 1.2.6 + array.prototype.flat: 1.3.3 + array.prototype.flatmap: 1.3.3 + debug: 3.2.7 + doctrine: 2.1.0 + eslint: 9.39.1 + eslint-import-resolver-node: 0.3.9 + eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.49.0(eslint@9.39.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@4.4.4)(eslint@9.39.1) + hasown: 2.0.2 + is-core-module: 2.16.1 + is-glob: 4.0.3 + minimatch: 3.1.2 + object.fromentries: 2.0.8 + object.groupby: 1.0.3 + object.values: 1.2.1 + semver: 6.3.1 + string.prototype.trimend: 1.0.9 + tsconfig-paths: 3.15.0 + optionalDependencies: + '@typescript-eslint/parser': 8.49.0(eslint@9.39.1)(typescript@5.9.3) + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + + eslint-plugin-n@17.23.1(eslint@9.39.1)(typescript@5.9.3): + dependencies: + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1) + enhanced-resolve: 5.18.3 + eslint: 9.39.1 + eslint-plugin-es-x: 7.8.0(eslint@9.39.1) + get-tsconfig: 4.13.0 + globals: 15.15.0 + globrex: 0.1.2 + ignore: 5.3.2 + semver: 7.7.3 + ts-declaration-location: 1.0.7(typescript@5.9.3) + transitivePeerDependencies: + - typescript + + eslint-plugin-simple-import-sort@12.1.1(eslint@9.39.1): + dependencies: + eslint: 9.39.1 + + eslint-scope@8.4.0: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-visitor-keys@3.4.3: {} + + eslint-visitor-keys@4.2.1: {} + + eslint@9.39.1: + dependencies: + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1) + '@eslint-community/regexpp': 4.12.2 + '@eslint/config-array': 0.21.1 + '@eslint/config-helpers': 0.4.2 + '@eslint/core': 0.17.0 + '@eslint/eslintrc': 3.3.1 + '@eslint/js': 9.39.1 + '@eslint/plugin-kit': 0.4.1 + '@humanfs/node': 0.16.7 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.3 + '@types/estree': 1.0.8 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.3 + escape-string-regexp: 4.0.0 + eslint-scope: 8.4.0 + eslint-visitor-keys: 4.2.1 + espree: 10.4.0 + esquery: 1.6.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 8.0.0 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.4 + transitivePeerDependencies: + - supports-color + + espree@10.4.0: + dependencies: + acorn: 8.15.0 + acorn-jsx: 5.3.2(acorn@8.15.0) + eslint-visitor-keys: 4.2.1 + + esquery@1.6.0: + dependencies: + estraverse: 5.3.0 + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@5.3.0: {} + + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.8 + + esutils@2.0.3: {} + + etag@1.8.1: {} + + eventsource-parser@3.0.6: {} + + eventsource@3.0.7: + dependencies: + eventsource-parser: 3.0.6 + + expect-type@1.2.2: {} + + express-rate-limit@7.5.1(express@5.1.0): + dependencies: + express: 5.1.0 + + express@5.1.0: + dependencies: + accepts: 2.0.0 + body-parser: 2.2.0 + content-disposition: 1.0.0 + content-type: 1.0.5 + cookie: 0.7.2 + cookie-signature: 1.2.2 + debug: 4.4.3 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 2.1.0 + fresh: 2.0.0 + http-errors: 2.0.0 + merge-descriptors: 2.0.0 + mime-types: 3.0.1 + on-finished: 2.4.1 + once: 1.4.0 + parseurl: 1.3.3 + proxy-addr: 2.0.7 + qs: 6.14.0 + range-parser: 1.2.1 + router: 2.2.0 + send: 1.2.0 + serve-static: 2.2.0 + statuses: 2.0.2 + type-is: 2.0.1 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + + fast-deep-equal@3.1.3: {} + + fast-json-stable-stringify@2.1.0: {} + + fast-levenshtein@2.0.6: {} + + fast-safe-stringify@2.1.1: {} + + fast-uri@3.1.0: {} + + fdir@6.5.0(picomatch@4.0.3): + optionalDependencies: + picomatch: 4.0.3 + + file-entry-cache@8.0.0: + dependencies: + flat-cache: 4.0.1 + + finalhandler@2.1.0: + dependencies: + debug: 4.4.3 + encodeurl: 2.0.0 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + flat-cache@4.0.1: + dependencies: + flatted: 3.3.3 + keyv: 4.5.4 + + flatted@3.3.3: {} + + for-each@0.3.5: + dependencies: + is-callable: 1.2.7 + + form-data@4.0.4: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + hasown: 2.0.2 + mime-types: 2.1.35 + + formidable@3.5.4: + dependencies: + '@paralleldrive/cuid2': 2.3.1 + dezalgo: 1.0.4 + once: 1.4.0 + + forwarded@0.2.0: {} + + fresh@2.0.0: {} + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + function.prototype.name@1.1.8: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + functions-have-names: 1.2.3 + hasown: 2.0.2 + is-callable: 1.2.7 + + functions-have-names@1.2.3: {} + + generator-function@2.0.1: {} + + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + math-intrinsics: 1.1.0 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + + get-symbol-description@1.1.0: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + + get-tsconfig@4.13.0: + dependencies: + resolve-pkg-maps: 1.0.0 + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + globals@14.0.0: {} + + globals@15.15.0: {} + + globalthis@1.0.4: + dependencies: + define-properties: 1.2.1 + gopd: 1.2.0 + + globrex@0.1.2: {} + + gopd@1.2.0: {} + + graceful-fs@4.2.11: {} + + has-bigints@1.1.0: {} + + has-flag@4.0.0: {} + + has-property-descriptors@1.0.2: + dependencies: + es-define-property: 1.0.1 + + has-proto@1.2.0: + dependencies: + dunder-proto: 1.0.1 + + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + http-errors@2.0.0: + dependencies: + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.1 + toidentifier: 1.0.1 + + iconv-lite@0.6.3: + dependencies: + safer-buffer: 2.1.2 + + iconv-lite@0.7.0: + dependencies: + safer-buffer: 2.1.2 + + ignore@5.3.2: {} + + ignore@7.0.5: {} + + import-fresh@3.3.1: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + imurmurhash@0.1.4: {} + + inherits@2.0.4: {} + + internal-slot@1.1.0: + dependencies: + es-errors: 1.3.0 + hasown: 2.0.2 + side-channel: 1.1.0 + + ipaddr.js@1.9.1: {} + + is-array-buffer@3.0.5: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + + is-async-function@2.1.1: + dependencies: + async-function: 1.0.0 + call-bound: 1.0.4 + get-proto: 1.0.1 + has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 + + is-bigint@1.1.0: + dependencies: + has-bigints: 1.1.0 + + is-boolean-object@1.2.2: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-bun-module@2.0.0: + dependencies: + semver: 7.7.3 + + is-callable@1.2.7: {} + + is-core-module@2.16.1: + dependencies: + hasown: 2.0.2 + + is-data-view@1.0.2: + dependencies: + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + is-typed-array: 1.1.15 + + is-date-object@1.1.0: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-extglob@2.1.1: {} + + is-finalizationregistry@1.1.1: + dependencies: + call-bound: 1.0.4 + + is-generator-function@1.1.2: + dependencies: + call-bound: 1.0.4 + generator-function: 2.0.1 + get-proto: 1.0.1 + has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-map@2.0.3: {} + + is-negative-zero@2.0.3: {} + + is-number-object@1.1.1: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-promise@4.0.0: {} + + is-regex@1.2.1: + dependencies: + call-bound: 1.0.4 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + is-set@2.0.3: {} + + is-shared-array-buffer@1.0.4: + dependencies: + call-bound: 1.0.4 + + is-string@1.1.1: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-symbol@1.1.1: + dependencies: + call-bound: 1.0.4 + has-symbols: 1.1.0 + safe-regex-test: 1.1.0 + + is-typed-array@1.1.15: + dependencies: + which-typed-array: 1.1.19 + + is-weakmap@2.0.2: {} + + is-weakref@1.1.1: + dependencies: + call-bound: 1.0.4 + + is-weakset@2.0.4: + dependencies: + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + + isarray@2.0.5: {} + + isexe@2.0.0: {} + + jose@6.1.3: {} + + js-yaml@4.1.0: + dependencies: + argparse: 2.0.1 + + json-buffer@3.0.1: {} + + json-schema-traverse@0.4.1: {} + + json-schema-traverse@1.0.0: {} + + json-schema-typed@8.0.2: {} + + json-stable-stringify-without-jsonify@1.0.1: {} + + json5@1.0.2: + dependencies: + minimist: 1.2.8 + + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + lodash.merge@4.6.2: {} + + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + math-intrinsics@1.1.0: {} + + media-typer@1.1.0: {} + + merge-descriptors@2.0.0: {} + + methods@1.1.2: {} + + mime-db@1.52.0: {} + + mime-db@1.54.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + mime-types@3.0.1: + dependencies: + mime-db: 1.54.0 + + mime@2.6.0: {} + + minimatch@3.1.2: + dependencies: + brace-expansion: 1.1.12 + + minimatch@9.0.5: + dependencies: + brace-expansion: 2.0.2 + + minimist@1.2.8: {} + + ms@2.1.3: {} + + nanoid@3.3.11: {} + + napi-postinstall@0.3.4: {} + + natural-compare@1.4.0: {} + + negotiator@1.0.0: {} + + object-assign@4.1.1: {} + + object-inspect@1.13.4: {} + + object-keys@1.1.1: {} + + object.assign@4.1.7: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + has-symbols: 1.1.0 + object-keys: 1.1.1 + + object.fromentries@2.0.8: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-object-atoms: 1.1.1 + + object.groupby@1.0.3: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + + object.values@1.2.1: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + + on-finished@2.4.1: + dependencies: + ee-first: 1.1.1 + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + optionator@0.9.4: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.5 + + own-keys@1.0.1: + dependencies: + get-intrinsic: 1.3.0 + object-keys: 1.1.1 + safe-push-apply: 1.0.0 + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + + parseurl@1.3.3: {} + + path-exists@4.0.0: {} + + path-key@3.1.1: {} + + path-parse@1.0.7: {} + + path-to-regexp@8.3.0: {} + + pathe@2.0.3: {} + + picocolors@1.1.1: {} + + picomatch@4.0.3: {} + + pkce-challenge@5.0.0: {} + + possible-typed-array-names@1.1.0: {} + + postcss@8.5.6: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + prelude-ls@1.2.1: {} + + prettier@3.6.2: {} + + proxy-addr@2.0.7: + dependencies: + forwarded: 0.2.0 + ipaddr.js: 1.9.1 + + punycode@2.3.1: {} + + qs@6.14.0: + dependencies: + side-channel: 1.1.0 + + range-parser@1.2.1: {} + + raw-body@3.0.1: + dependencies: + bytes: 3.1.2 + http-errors: 2.0.0 + iconv-lite: 0.7.0 + unpipe: 1.0.0 + + reflect.getprototypeof@1.0.10: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + which-builtin-type: 1.2.1 + + regexp.prototype.flags@1.5.4: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-errors: 1.3.0 + get-proto: 1.0.1 + gopd: 1.2.0 + set-function-name: 2.0.2 + + require-from-string@2.0.2: {} + + resolve-from@4.0.0: {} + + resolve-pkg-maps@1.0.0: {} + + resolve@1.22.11: + dependencies: + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + rollup@4.53.2: + dependencies: + '@types/estree': 1.0.8 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.53.2 + '@rollup/rollup-android-arm64': 4.53.2 + '@rollup/rollup-darwin-arm64': 4.53.2 + '@rollup/rollup-darwin-x64': 4.53.2 + '@rollup/rollup-freebsd-arm64': 4.53.2 + '@rollup/rollup-freebsd-x64': 4.53.2 + '@rollup/rollup-linux-arm-gnueabihf': 4.53.2 + '@rollup/rollup-linux-arm-musleabihf': 4.53.2 + '@rollup/rollup-linux-arm64-gnu': 4.53.2 + '@rollup/rollup-linux-arm64-musl': 4.53.2 + '@rollup/rollup-linux-loong64-gnu': 4.53.2 + '@rollup/rollup-linux-ppc64-gnu': 4.53.2 + '@rollup/rollup-linux-riscv64-gnu': 4.53.2 + '@rollup/rollup-linux-riscv64-musl': 4.53.2 + '@rollup/rollup-linux-s390x-gnu': 4.53.2 + '@rollup/rollup-linux-x64-gnu': 4.53.2 + '@rollup/rollup-linux-x64-musl': 4.53.2 + '@rollup/rollup-openharmony-arm64': 4.53.2 + '@rollup/rollup-win32-arm64-msvc': 4.53.2 + '@rollup/rollup-win32-ia32-msvc': 4.53.2 + '@rollup/rollup-win32-x64-gnu': 4.53.2 + '@rollup/rollup-win32-x64-msvc': 4.53.2 + fsevents: 2.3.3 + + router@2.2.0: + dependencies: + debug: 4.4.3 + depd: 2.0.0 + is-promise: 4.0.0 + parseurl: 1.3.3 + path-to-regexp: 8.3.0 + transitivePeerDependencies: + - supports-color + + safe-array-concat@1.1.3: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + has-symbols: 1.1.0 + isarray: 2.0.5 + + safe-buffer@5.2.1: {} + + safe-push-apply@1.0.0: + dependencies: + es-errors: 1.3.0 + isarray: 2.0.5 + + safe-regex-test@1.1.0: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-regex: 1.2.1 + + safer-buffer@2.1.2: {} + + semver@6.3.1: {} + + semver@7.7.3: {} + + send@1.2.0: + dependencies: + debug: 4.4.3 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 2.0.0 + http-errors: 2.0.0 + mime-types: 3.0.1 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + + serve-static@2.2.0: + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 1.2.0 + transitivePeerDependencies: + - supports-color + + set-function-length@1.2.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.3.0 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + + set-function-name@2.0.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + functions-have-names: 1.2.3 + has-property-descriptors: 1.0.2 + + set-proto@1.0.0: + dependencies: + dunder-proto: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + + setprototypeof@1.2.0: {} + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + side-channel-list@1.0.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + + side-channel-map@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + + side-channel-weakmap@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + side-channel-map: 1.0.1 + + side-channel@1.1.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.0 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + + siginfo@2.0.0: {} + + source-map-js@1.2.1: {} + + stable-hash-x@0.2.0: {} + + stackback@0.0.2: {} + + statuses@2.0.1: {} + + statuses@2.0.2: {} + + std-env@3.10.0: {} + + stop-iteration-iterator@1.1.0: + dependencies: + es-errors: 1.3.0 + internal-slot: 1.1.0 + + string.prototype.trim@1.2.10: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-data-property: 1.1.4 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-object-atoms: 1.1.1 + has-property-descriptors: 1.0.2 + + string.prototype.trimend@1.0.9: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + + string.prototype.trimstart@1.0.8: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + + strip-bom@3.0.0: {} + + strip-json-comments@3.1.1: {} + + superagent@10.2.3: + dependencies: + component-emitter: 1.3.1 + cookiejar: 2.1.4 + debug: 4.4.3 + fast-safe-stringify: 2.1.1 + form-data: 4.0.4 + formidable: 3.5.4 + methods: 1.1.2 + mime: 2.6.0 + qs: 6.14.0 + transitivePeerDependencies: + - supports-color + + supertest@7.1.4: + dependencies: + methods: 1.1.2 + superagent: 10.2.3 + transitivePeerDependencies: + - supports-color + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + supports-preserve-symlinks-flag@1.0.0: {} + + tapable@2.3.0: {} + + tinybench@2.9.0: {} + + tinyexec@0.3.2: {} + + tinyglobby@0.2.15: + dependencies: + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + + tinyrainbow@3.0.3: {} + + toidentifier@1.0.1: {} + + ts-api-utils@2.1.0(typescript@5.9.3): + dependencies: + typescript: 5.9.3 + + ts-declaration-location@1.0.7(typescript@5.9.3): + dependencies: + picomatch: 4.0.3 + typescript: 5.9.3 + + tsconfck@3.1.6(typescript@5.9.3): + optionalDependencies: + typescript: 5.9.3 + + tsconfig-paths@3.15.0: + dependencies: + '@types/json5': 0.0.29 + json5: 1.0.2 + minimist: 1.2.8 + strip-bom: 3.0.0 + + tslib@2.8.1: + optional: true + + tsx@4.20.6: + dependencies: + esbuild: 0.25.12 + get-tsconfig: 4.13.0 + optionalDependencies: + fsevents: 2.3.3 + + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + + type-is@2.0.1: + dependencies: + content-type: 1.0.5 + media-typer: 1.1.0 + mime-types: 3.0.1 + + typed-array-buffer@1.0.3: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-typed-array: 1.1.15 + + typed-array-byte-length@1.0.3: + dependencies: + call-bind: 1.0.8 + for-each: 0.3.5 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + + typed-array-byte-offset@1.0.4: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + for-each: 0.3.5 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + reflect.getprototypeof: 1.0.10 + + typed-array-length@1.0.7: + dependencies: + call-bind: 1.0.8 + for-each: 0.3.5 + gopd: 1.2.0 + is-typed-array: 1.1.15 + possible-typed-array-names: 1.1.0 + reflect.getprototypeof: 1.0.10 + + typescript-eslint@8.49.0(eslint@9.39.1)(typescript@5.9.3): + dependencies: + '@typescript-eslint/eslint-plugin': 8.49.0(@typescript-eslint/parser@8.49.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3) + '@typescript-eslint/parser': 8.49.0(eslint@9.39.1)(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.49.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.49.0(eslint@9.39.1)(typescript@5.9.3) + eslint: 9.39.1 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + typescript@5.9.3: {} + + unbox-primitive@1.1.0: + dependencies: + call-bound: 1.0.4 + has-bigints: 1.1.0 + has-symbols: 1.1.0 + which-boxed-primitive: 1.1.1 + + undici-types@7.16.0: {} + + unpipe@1.0.0: {} + + unrs-resolver@1.11.1: + dependencies: + napi-postinstall: 0.3.4 + optionalDependencies: + '@unrs/resolver-binding-android-arm-eabi': 1.11.1 + '@unrs/resolver-binding-android-arm64': 1.11.1 + '@unrs/resolver-binding-darwin-arm64': 1.11.1 + '@unrs/resolver-binding-darwin-x64': 1.11.1 + '@unrs/resolver-binding-freebsd-x64': 1.11.1 + '@unrs/resolver-binding-linux-arm-gnueabihf': 1.11.1 + '@unrs/resolver-binding-linux-arm-musleabihf': 1.11.1 + '@unrs/resolver-binding-linux-arm64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-arm64-musl': 1.11.1 + '@unrs/resolver-binding-linux-ppc64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-riscv64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-riscv64-musl': 1.11.1 + '@unrs/resolver-binding-linux-s390x-gnu': 1.11.1 + '@unrs/resolver-binding-linux-x64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-x64-musl': 1.11.1 + '@unrs/resolver-binding-wasm32-wasi': 1.11.1 + '@unrs/resolver-binding-win32-arm64-msvc': 1.11.1 + '@unrs/resolver-binding-win32-ia32-msvc': 1.11.1 + '@unrs/resolver-binding-win32-x64-msvc': 1.11.1 + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + vary@1.1.2: {} + + vite-tsconfig-paths@5.1.4(typescript@5.9.3)(vite@7.2.2(@types/node@24.10.3)(tsx@4.20.6)): + dependencies: + debug: 4.4.3 + globrex: 0.1.2 + tsconfck: 3.1.6(typescript@5.9.3) + optionalDependencies: + vite: 7.2.2(@types/node@24.10.3)(tsx@4.20.6) + transitivePeerDependencies: + - supports-color + - typescript + + vite@7.2.2(@types/node@24.10.3)(tsx@4.20.6): + dependencies: + esbuild: 0.25.12 + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + postcss: 8.5.6 + rollup: 4.53.2 + tinyglobby: 0.2.15 + optionalDependencies: + '@types/node': 24.10.3 + fsevents: 2.3.3 + tsx: 4.20.6 + + vitest@4.0.9(@types/node@24.10.3)(tsx@4.20.6): + dependencies: + '@vitest/expect': 4.0.9 + '@vitest/mocker': 4.0.9(vite@7.2.2(@types/node@24.10.3)(tsx@4.20.6)) + '@vitest/pretty-format': 4.0.9 + '@vitest/runner': 4.0.9 + '@vitest/snapshot': 4.0.9 + '@vitest/spy': 4.0.9 + '@vitest/utils': 4.0.9 + debug: 4.4.3 + es-module-lexer: 1.7.0 + expect-type: 1.2.2 + magic-string: 0.30.21 + pathe: 2.0.3 + picomatch: 4.0.3 + std-env: 3.10.0 + tinybench: 2.9.0 + tinyexec: 0.3.2 + tinyglobby: 0.2.15 + tinyrainbow: 3.0.3 + vite: 7.2.2(@types/node@24.10.3)(tsx@4.20.6) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/node': 24.10.3 + transitivePeerDependencies: + - jiti + - less + - lightningcss + - msw + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml + + which-boxed-primitive@1.1.1: + dependencies: + is-bigint: 1.1.0 + is-boolean-object: 1.2.2 + is-number-object: 1.1.1 + is-string: 1.1.1 + is-symbol: 1.1.1 + + which-builtin-type@1.2.1: + dependencies: + call-bound: 1.0.4 + function.prototype.name: 1.1.8 + has-tostringtag: 1.0.2 + is-async-function: 2.1.1 + is-date-object: 1.1.0 + is-finalizationregistry: 1.1.1 + is-generator-function: 1.1.2 + is-regex: 1.2.1 + is-weakref: 1.1.1 + isarray: 2.0.5 + which-boxed-primitive: 1.1.1 + which-collection: 1.0.2 + which-typed-array: 1.1.19 + + which-collection@1.0.2: + dependencies: + is-map: 2.0.3 + is-set: 2.0.3 + is-weakmap: 2.0.2 + is-weakset: 2.0.4 + + which-typed-array@1.1.19: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 + for-each: 0.3.5 + get-proto: 1.0.1 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + why-is-node-running@2.3.0: + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + + word-wrap@1.2.5: {} + + wrappy@1.0.2: {} + + ws@8.18.3: {} + + yocto-queue@0.1.0: {} + + zod-to-json-schema@3.25.0(zod@3.25.76): + dependencies: + zod: 3.25.76 + + zod@3.25.76: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 000000000..1ce7552be --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1,10 @@ +packages: + - packages/**/* + - common/**/* + +catalog: + typescript: ^5.9.3 + +enableGlobalVirtualStore: false + +linkWorkspacePackages: deep diff --git a/src/__mocks__/pkce-challenge.ts b/src/__mocks__/pkce-challenge.ts deleted file mode 100644 index 3dfec41f9..000000000 --- a/src/__mocks__/pkce-challenge.ts +++ /dev/null @@ -1,6 +0,0 @@ -export default function pkceChallenge() { - return { - code_verifier: 'test_verifier', - code_challenge: 'test_challenge' - }; -} diff --git a/src/experimental/tasks/index.ts b/src/experimental/tasks/index.ts deleted file mode 100644 index 398d34393..000000000 --- a/src/experimental/tasks/index.ts +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Experimental task features for MCP SDK. - * WARNING: These APIs are experimental and may change without notice. - * - * @experimental - */ - -// Re-export spec types for convenience -export * from './types.js'; - -// SDK implementation interfaces -export * from './interfaces.js'; - -// Assertion helpers -export * from './helpers.js'; - -// Wrapper classes -export * from './client.js'; -export * from './server.js'; -export * from './mcp-server.js'; - -// Store implementations -export * from './stores/in-memory.js'; - -// Re-export response message types for task streaming -export type { - ResponseMessage, - TaskStatusMessage, - TaskCreatedMessage, - ResultMessage, - ErrorMessage, - BaseResponseMessage -} from '../../shared/responseMessage.js'; -export { takeResult, toArrayAsync } from '../../shared/responseMessage.js'; diff --git a/src/experimental/tasks/types.ts b/src/experimental/tasks/types.ts deleted file mode 100644 index a3845bae1..000000000 --- a/src/experimental/tasks/types.ts +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Re-exports of task-related types from the MCP protocol spec. - * WARNING: These APIs are experimental and may change without notice. - * - * These types are defined in types.ts (matching the protocol spec) and - * re-exported here for convenience when working with experimental task features. - */ - -// Task schemas (Zod) -export { - TaskCreationParamsSchema, - RelatedTaskMetadataSchema, - TaskSchema, - CreateTaskResultSchema, - TaskStatusNotificationParamsSchema, - TaskStatusNotificationSchema, - GetTaskRequestSchema, - GetTaskResultSchema, - GetTaskPayloadRequestSchema, - ListTasksRequestSchema, - ListTasksResultSchema, - CancelTaskRequestSchema, - CancelTaskResultSchema, - ClientTasksCapabilitySchema, - ServerTasksCapabilitySchema -} from '../../types.js'; - -// Task types (inferred from schemas) -export type { - Task, - TaskCreationParams, - RelatedTaskMetadata, - CreateTaskResult, - TaskStatusNotificationParams, - TaskStatusNotification, - GetTaskRequest, - GetTaskResult, - GetTaskPayloadRequest, - ListTasksRequest, - ListTasksResult, - CancelTaskRequest, - CancelTaskResult -} from '../../types.js'; diff --git a/src/server/auth/types.ts b/src/server/auth/types.ts deleted file mode 100644 index a38a7e750..000000000 --- a/src/server/auth/types.ts +++ /dev/null @@ -1,36 +0,0 @@ -/** - * Information about a validated access token, provided to request handlers. - */ -export interface AuthInfo { - /** - * The access token. - */ - token: string; - - /** - * The client ID associated with this token. - */ - clientId: string; - - /** - * Scopes associated with this token. - */ - scopes: string[]; - - /** - * When the token expires (in seconds since epoch). - */ - expiresAt?: number; - - /** - * The RFC 8707 resource server identifier for which this token is valid. - * If set, this MUST match the MCP server's resource identifier (minus hash fragment). - */ - resource?: URL; - - /** - * Additional data associated with the token. - * This field should be used for any additional data that needs to be attached to the auth info. - */ - extra?: Record; -} diff --git a/src/spec.types.ts b/src/spec.types.ts deleted file mode 100644 index 07a1cceff..000000000 --- a/src/spec.types.ts +++ /dev/null @@ -1,2587 +0,0 @@ -/** - * This file is automatically generated from the Model Context Protocol specification. - * - * Source: https://github.com/modelcontextprotocol/modelcontextprotocol - * Pulled from: https://raw.githubusercontent.com/modelcontextprotocol/modelcontextprotocol/main/schema/draft/schema.ts - * Last updated from commit: 35fa160caf287a9c48696e3ae452c0645c713669 - * - * DO NOT EDIT THIS FILE MANUALLY. Changes will be overwritten by automated updates. - * To update this file, run: npm run fetch:spec-types - *//* JSON-RPC types */ - -/** - * Refers to any valid JSON-RPC object that can be decoded off the wire, or encoded to be sent. - * - * @category JSON-RPC - */ -export type JSONRPCMessage = - | JSONRPCRequest - | JSONRPCNotification - | JSONRPCResponse; - -/** @internal */ -export const LATEST_PROTOCOL_VERSION = "DRAFT-2026-v1"; -/** @internal */ -export const JSONRPC_VERSION = "2.0"; - -/** - * A progress token, used to associate progress notifications with the original request. - * - * @category Common Types - */ -export type ProgressToken = string | number; - -/** - * An opaque token used to represent a cursor for pagination. - * - * @category Common Types - */ -export type Cursor = string; - -/** - * Common params for any task-augmented request. - * - * @internal - */ -export interface TaskAugmentedRequestParams extends RequestParams { - /** - * If specified, the caller is requesting task-augmented execution for this request. - * The request will return a CreateTaskResult immediately, and the actual result can be - * retrieved later via tasks/result. - * - * Task augmentation is subject to capability negotiation - receivers MUST declare support - * for task augmentation of specific request types in their capabilities. - */ - task?: TaskMetadata; -} -/** - * Common params for any request. - * - * @internal - */ -export interface RequestParams { - /** - * See [General fields: `_meta`](/specification/draft/basic/index#meta) for notes on `_meta` usage. - */ - _meta?: { - /** - * If specified, the caller is requesting out-of-band progress notifications for this request (as represented by notifications/progress). The value of this parameter is an opaque token that will be attached to any subsequent notifications. The receiver is not obligated to provide these notifications. - */ - progressToken?: ProgressToken; - [key: string]: unknown; - }; -} - -/** @internal */ -export interface Request { - method: string; - // Allow unofficial extensions of `Request.params` without impacting `RequestParams`. - // eslint-disable-next-line @typescript-eslint/no-explicit-any - params?: { [key: string]: any }; -} - -/** @internal */ -export interface NotificationParams { - /** - * See [General fields: `_meta`](/specification/draft/basic/index#meta) for notes on `_meta` usage. - */ - _meta?: { [key: string]: unknown }; -} - -/** @internal */ -export interface Notification { - method: string; - // Allow unofficial extensions of `Notification.params` without impacting `NotificationParams`. - // eslint-disable-next-line @typescript-eslint/no-explicit-any - params?: { [key: string]: any }; -} - -/** - * @category Common Types - */ -export interface Result { - /** - * See [General fields: `_meta`](/specification/draft/basic/index#meta) for notes on `_meta` usage. - */ - _meta?: { [key: string]: unknown }; - [key: string]: unknown; -} - -/** - * @category Common Types - */ -export interface Error { - /** - * The error type that occurred. - */ - code: number; - /** - * A short description of the error. The message SHOULD be limited to a concise single sentence. - */ - message: string; - /** - * Additional information about the error. The value of this member is defined by the sender (e.g. detailed error information, nested errors etc.). - */ - data?: unknown; -} - -/** - * A uniquely identifying ID for a request in JSON-RPC. - * - * @category Common Types - */ -export type RequestId = string | number; - -/** - * A request that expects a response. - * - * @category JSON-RPC - */ -export interface JSONRPCRequest extends Request { - jsonrpc: typeof JSONRPC_VERSION; - id: RequestId; -} - -/** - * A notification which does not expect a response. - * - * @category JSON-RPC - */ -export interface JSONRPCNotification extends Notification { - jsonrpc: typeof JSONRPC_VERSION; -} - -/** - * A successful (non-error) response to a request. - * - * @category JSON-RPC - */ -export interface JSONRPCResultResponse { - jsonrpc: typeof JSONRPC_VERSION; - id: RequestId; - result: Result; -} - -/** - * A response to a request that indicates an error occurred. - * - * @category JSON-RPC - */ -export interface JSONRPCErrorResponse { - jsonrpc: typeof JSONRPC_VERSION; - id?: RequestId; - error: Error; -} - -/** - * A response to a request, containing either the result or error. - */ -export type JSONRPCResponse = JSONRPCResultResponse | JSONRPCErrorResponse; - -// Standard JSON-RPC error codes -export const PARSE_ERROR = -32700; -export const INVALID_REQUEST = -32600; -export const METHOD_NOT_FOUND = -32601; -export const INVALID_PARAMS = -32602; -export const INTERNAL_ERROR = -32603; - -// Implementation-specific JSON-RPC error codes [-32000, -32099] -/** @internal */ -export const URL_ELICITATION_REQUIRED = -32042; - -/** - * An error response that indicates that the server requires the client to provide additional information via an elicitation request. - * - * @internal - */ -export interface URLElicitationRequiredError - extends Omit { - error: Error & { - code: typeof URL_ELICITATION_REQUIRED; - data: { - elicitations: ElicitRequestURLParams[]; - [key: string]: unknown; - }; - }; -} - -/* Empty result */ -/** - * A response that indicates success but carries no data. - * - * @category Common Types - */ -export type EmptyResult = Result; - -/* Cancellation */ -/** - * Parameters for a `notifications/cancelled` notification. - * - * @category `notifications/cancelled` - */ -export interface CancelledNotificationParams extends NotificationParams { - /** - * The ID of the request to cancel. - * - * This MUST correspond to the ID of a request previously issued in the same direction. - * This MUST be provided for cancelling non-task requests. - * This MUST NOT be used for cancelling tasks (use the `tasks/cancel` request instead). - */ - requestId?: RequestId; - - /** - * An optional string describing the reason for the cancellation. This MAY be logged or presented to the user. - */ - reason?: string; -} - -/** - * This notification can be sent by either side to indicate that it is cancelling a previously-issued request. - * - * The request SHOULD still be in-flight, but due to communication latency, it is always possible that this notification MAY arrive after the request has already finished. - * - * This notification indicates that the result will be unused, so any associated processing SHOULD cease. - * - * A client MUST NOT attempt to cancel its `initialize` request. - * - * For task cancellation, use the `tasks/cancel` request instead of this notification. - * - * @category `notifications/cancelled` - */ -export interface CancelledNotification extends JSONRPCNotification { - method: "notifications/cancelled"; - params: CancelledNotificationParams; -} - -/* Initialization */ -/** - * Parameters for an `initialize` request. - * - * @category `initialize` - */ -export interface InitializeRequestParams extends RequestParams { - /** - * The latest version of the Model Context Protocol that the client supports. The client MAY decide to support older versions as well. - */ - protocolVersion: string; - capabilities: ClientCapabilities; - clientInfo: Implementation; -} - -/** - * This request is sent from the client to the server when it first connects, asking it to begin initialization. - * - * @category `initialize` - */ -export interface InitializeRequest extends JSONRPCRequest { - method: "initialize"; - params: InitializeRequestParams; -} - -/** - * After receiving an initialize request from the client, the server sends this response. - * - * @category `initialize` - */ -export interface InitializeResult extends Result { - /** - * The version of the Model Context Protocol that the server wants to use. This may not match the version that the client requested. If the client cannot support this version, it MUST disconnect. - */ - protocolVersion: string; - capabilities: ServerCapabilities; - serverInfo: Implementation; - - /** - * Instructions describing how to use the server and its features. - * - * This can be used by clients to improve the LLM's understanding of available tools, resources, etc. It can be thought of like a "hint" to the model. For example, this information MAY be added to the system prompt. - */ - instructions?: string; -} - -/** - * This notification is sent from the client to the server after initialization has finished. - * - * @category `notifications/initialized` - */ -export interface InitializedNotification extends JSONRPCNotification { - method: "notifications/initialized"; - params?: NotificationParams; -} - -/** - * Capabilities a client may support. Known capabilities are defined here, in this schema, but this is not a closed set: any client can define its own, additional capabilities. - * - * @category `initialize` - */ -export interface ClientCapabilities { - /** - * Experimental, non-standard capabilities that the client supports. - */ - experimental?: { [key: string]: object }; - /** - * Present if the client supports listing roots. - */ - roots?: { - /** - * Whether the client supports notifications for changes to the roots list. - */ - listChanged?: boolean; - }; - /** - * Present if the client supports sampling from an LLM. - */ - sampling?: { - /** - * Whether the client supports context inclusion via includeContext parameter. - * If not declared, servers SHOULD only use `includeContext: "none"` (or omit it). - */ - context?: object; - /** - * Whether the client supports tool use via tools and toolChoice parameters. - */ - tools?: object; - }; - /** - * Present if the client supports elicitation from the server. - */ - elicitation?: { form?: object; url?: object }; - - /** - * Present if the client supports task-augmented requests. - */ - tasks?: { - /** - * Whether this client supports tasks/list. - */ - list?: object; - /** - * Whether this client supports tasks/cancel. - */ - cancel?: object; - /** - * Specifies which request types can be augmented with tasks. - */ - requests?: { - /** - * Task support for sampling-related requests. - */ - sampling?: { - /** - * Whether the client supports task-augmented sampling/createMessage requests. - */ - createMessage?: object; - }; - /** - * Task support for elicitation-related requests. - */ - elicitation?: { - /** - * Whether the client supports task-augmented elicitation/create requests. - */ - create?: object; - }; - }; - }; -} - -/** - * Capabilities that a server may support. Known capabilities are defined here, in this schema, but this is not a closed set: any server can define its own, additional capabilities. - * - * @category `initialize` - */ -export interface ServerCapabilities { - /** - * Experimental, non-standard capabilities that the server supports. - */ - experimental?: { [key: string]: object }; - /** - * Present if the server supports sending log messages to the client. - */ - logging?: object; - /** - * Present if the server supports argument autocompletion suggestions. - */ - completions?: object; - /** - * Present if the server offers any prompt templates. - */ - prompts?: { - /** - * Whether this server supports notifications for changes to the prompt list. - */ - listChanged?: boolean; - }; - /** - * Present if the server offers any resources to read. - */ - resources?: { - /** - * Whether this server supports subscribing to resource updates. - */ - subscribe?: boolean; - /** - * Whether this server supports notifications for changes to the resource list. - */ - listChanged?: boolean; - }; - /** - * Present if the server offers any tools to call. - */ - tools?: { - /** - * Whether this server supports notifications for changes to the tool list. - */ - listChanged?: boolean; - }; - /** - * Present if the server supports task-augmented requests. - */ - tasks?: { - /** - * Whether this server supports tasks/list. - */ - list?: object; - /** - * Whether this server supports tasks/cancel. - */ - cancel?: object; - /** - * Specifies which request types can be augmented with tasks. - */ - requests?: { - /** - * Task support for tool-related requests. - */ - tools?: { - /** - * Whether the server supports task-augmented tools/call requests. - */ - call?: object; - }; - }; - }; -} - -/** - * An optionally-sized icon that can be displayed in a user interface. - * - * @category Common Types - */ -export interface Icon { - /** - * A standard URI pointing to an icon resource. May be an HTTP/HTTPS URL or a - * `data:` URI with Base64-encoded image data. - * - * Consumers SHOULD takes steps to ensure URLs serving icons are from the - * same domain as the client/server or a trusted domain. - * - * Consumers SHOULD take appropriate precautions when consuming SVGs as they can contain - * executable JavaScript. - * - * @format uri - */ - src: string; - - /** - * Optional MIME type override if the source MIME type is missing or generic. - * For example: `"image/png"`, `"image/jpeg"`, or `"image/svg+xml"`. - */ - mimeType?: string; - - /** - * Optional array of strings that specify sizes at which the icon can be used. - * Each string should be in WxH format (e.g., `"48x48"`, `"96x96"`) or `"any"` for scalable formats like SVG. - * - * If not provided, the client should assume that the icon can be used at any size. - */ - sizes?: string[]; - - /** - * Optional specifier for the theme this icon is designed for. `light` indicates - * the icon is designed to be used with a light background, and `dark` indicates - * the icon is designed to be used with a dark background. - * - * If not provided, the client should assume the icon can be used with any theme. - */ - theme?: "light" | "dark"; -} - -/** - * Base interface to add `icons` property. - * - * @internal - */ -export interface Icons { - /** - * Optional set of sized icons that the client can display in a user interface. - * - * Clients that support rendering icons MUST support at least the following MIME types: - * - `image/png` - PNG images (safe, universal compatibility) - * - `image/jpeg` (and `image/jpg`) - JPEG images (safe, universal compatibility) - * - * Clients that support rendering icons SHOULD also support: - * - `image/svg+xml` - SVG images (scalable but requires security precautions) - * - `image/webp` - WebP images (modern, efficient format) - */ - icons?: Icon[]; -} - -/** - * Base interface for metadata with name (identifier) and title (display name) properties. - * - * @internal - */ -export interface BaseMetadata { - /** - * Intended for programmatic or logical use, but used as a display name in past specs or fallback (if title isn't present). - */ - name: string; - - /** - * Intended for UI and end-user contexts — optimized to be human-readable and easily understood, - * even by those unfamiliar with domain-specific terminology. - * - * If not provided, the name should be used for display (except for Tool, - * where `annotations.title` should be given precedence over using `name`, - * if present). - */ - title?: string; -} - -/** - * Describes the MCP implementation. - * - * @category `initialize` - */ -export interface Implementation extends BaseMetadata, Icons { - version: string; - - /** - * An optional human-readable description of what this implementation does. - * - * This can be used by clients or servers to provide context about their purpose - * and capabilities. For example, a server might describe the types of resources - * or tools it provides, while a client might describe its intended use case. - */ - description?: string; - - /** - * An optional URL of the website for this implementation. - * - * @format uri - */ - websiteUrl?: string; -} - -/* Ping */ -/** - * A ping, issued by either the server or the client, to check that the other party is still alive. The receiver must promptly respond, or else may be disconnected. - * - * @category `ping` - */ -export interface PingRequest extends JSONRPCRequest { - method: "ping"; - params?: RequestParams; -} - -/* Progress notifications */ - -/** - * Parameters for a `notifications/progress` notification. - * - * @category `notifications/progress` - */ -export interface ProgressNotificationParams extends NotificationParams { - /** - * The progress token which was given in the initial request, used to associate this notification with the request that is proceeding. - */ - progressToken: ProgressToken; - /** - * The progress thus far. This should increase every time progress is made, even if the total is unknown. - * - * @TJS-type number - */ - progress: number; - /** - * Total number of items to process (or total progress required), if known. - * - * @TJS-type number - */ - total?: number; - /** - * An optional message describing the current progress. - */ - message?: string; -} - -/** - * An out-of-band notification used to inform the receiver of a progress update for a long-running request. - * - * @category `notifications/progress` - */ -export interface ProgressNotification extends JSONRPCNotification { - method: "notifications/progress"; - params: ProgressNotificationParams; -} - -/* Pagination */ -/** - * Common parameters for paginated requests. - * - * @internal - */ -export interface PaginatedRequestParams extends RequestParams { - /** - * An opaque token representing the current pagination position. - * If provided, the server should return results starting after this cursor. - */ - cursor?: Cursor; -} - -/** @internal */ -export interface PaginatedRequest extends JSONRPCRequest { - params?: PaginatedRequestParams; -} - -/** @internal */ -export interface PaginatedResult extends Result { - /** - * An opaque token representing the pagination position after the last returned result. - * If present, there may be more results available. - */ - nextCursor?: Cursor; -} - -/* Resources */ -/** - * Sent from the client to request a list of resources the server has. - * - * @category `resources/list` - */ -export interface ListResourcesRequest extends PaginatedRequest { - method: "resources/list"; -} - -/** - * The server's response to a resources/list request from the client. - * - * @category `resources/list` - */ -export interface ListResourcesResult extends PaginatedResult { - resources: Resource[]; -} - -/** - * Sent from the client to request a list of resource templates the server has. - * - * @category `resources/templates/list` - */ -export interface ListResourceTemplatesRequest extends PaginatedRequest { - method: "resources/templates/list"; -} - -/** - * The server's response to a resources/templates/list request from the client. - * - * @category `resources/templates/list` - */ -export interface ListResourceTemplatesResult extends PaginatedResult { - resourceTemplates: ResourceTemplate[]; -} - -/** - * Common parameters when working with resources. - * - * @internal - */ -export interface ResourceRequestParams extends RequestParams { - /** - * The URI of the resource. The URI can use any protocol; it is up to the server how to interpret it. - * - * @format uri - */ - uri: string; -} - -/** - * Parameters for a `resources/read` request. - * - * @category `resources/read` - */ -// eslint-disable-next-line @typescript-eslint/no-empty-object-type -export interface ReadResourceRequestParams extends ResourceRequestParams {} - -/** - * Sent from the client to the server, to read a specific resource URI. - * - * @category `resources/read` - */ -export interface ReadResourceRequest extends JSONRPCRequest { - method: "resources/read"; - params: ReadResourceRequestParams; -} - -/** - * The server's response to a resources/read request from the client. - * - * @category `resources/read` - */ -export interface ReadResourceResult extends Result { - contents: (TextResourceContents | BlobResourceContents)[]; -} - -/** - * An optional notification from the server to the client, informing it that the list of resources it can read from has changed. This may be issued by servers without any previous subscription from the client. - * - * @category `notifications/resources/list_changed` - */ -export interface ResourceListChangedNotification extends JSONRPCNotification { - method: "notifications/resources/list_changed"; - params?: NotificationParams; -} - -/** - * Parameters for a `resources/subscribe` request. - * - * @category `resources/subscribe` - */ -// eslint-disable-next-line @typescript-eslint/no-empty-object-type -export interface SubscribeRequestParams extends ResourceRequestParams {} - -/** - * Sent from the client to request resources/updated notifications from the server whenever a particular resource changes. - * - * @category `resources/subscribe` - */ -export interface SubscribeRequest extends JSONRPCRequest { - method: "resources/subscribe"; - params: SubscribeRequestParams; -} - -/** - * Parameters for a `resources/unsubscribe` request. - * - * @category `resources/unsubscribe` - */ -// eslint-disable-next-line @typescript-eslint/no-empty-object-type -export interface UnsubscribeRequestParams extends ResourceRequestParams {} - -/** - * Sent from the client to request cancellation of resources/updated notifications from the server. This should follow a previous resources/subscribe request. - * - * @category `resources/unsubscribe` - */ -export interface UnsubscribeRequest extends JSONRPCRequest { - method: "resources/unsubscribe"; - params: UnsubscribeRequestParams; -} - -/** - * Parameters for a `notifications/resources/updated` notification. - * - * @category `notifications/resources/updated` - */ -export interface ResourceUpdatedNotificationParams extends NotificationParams { - /** - * The URI of the resource that has been updated. This might be a sub-resource of the one that the client actually subscribed to. - * - * @format uri - */ - uri: string; -} - -/** - * A notification from the server to the client, informing it that a resource has changed and may need to be read again. This should only be sent if the client previously sent a resources/subscribe request. - * - * @category `notifications/resources/updated` - */ -export interface ResourceUpdatedNotification extends JSONRPCNotification { - method: "notifications/resources/updated"; - params: ResourceUpdatedNotificationParams; -} - -/** - * A known resource that the server is capable of reading. - * - * @category `resources/list` - */ -export interface Resource extends BaseMetadata, Icons { - /** - * The URI of this resource. - * - * @format uri - */ - uri: string; - - /** - * A description of what this resource represents. - * - * This can be used by clients to improve the LLM's understanding of available resources. It can be thought of like a "hint" to the model. - */ - description?: string; - - /** - * The MIME type of this resource, if known. - */ - mimeType?: string; - - /** - * Optional annotations for the client. - */ - annotations?: Annotations; - - /** - * The size of the raw resource content, in bytes (i.e., before base64 encoding or any tokenization), if known. - * - * This can be used by Hosts to display file sizes and estimate context window usage. - */ - size?: number; - - /** - * See [General fields: `_meta`](/specification/draft/basic/index#meta) for notes on `_meta` usage. - */ - _meta?: { [key: string]: unknown }; -} - -/** - * A template description for resources available on the server. - * - * @category `resources/templates/list` - */ -export interface ResourceTemplate extends BaseMetadata, Icons { - /** - * A URI template (according to RFC 6570) that can be used to construct resource URIs. - * - * @format uri-template - */ - uriTemplate: string; - - /** - * A description of what this template is for. - * - * This can be used by clients to improve the LLM's understanding of available resources. It can be thought of like a "hint" to the model. - */ - description?: string; - - /** - * The MIME type for all resources that match this template. This should only be included if all resources matching this template have the same type. - */ - mimeType?: string; - - /** - * Optional annotations for the client. - */ - annotations?: Annotations; - - /** - * See [General fields: `_meta`](/specification/draft/basic/index#meta) for notes on `_meta` usage. - */ - _meta?: { [key: string]: unknown }; -} - -/** - * The contents of a specific resource or sub-resource. - * - * @internal - */ -export interface ResourceContents { - /** - * The URI of this resource. - * - * @format uri - */ - uri: string; - /** - * The MIME type of this resource, if known. - */ - mimeType?: string; - - /** - * See [General fields: `_meta`](/specification/draft/basic/index#meta) for notes on `_meta` usage. - */ - _meta?: { [key: string]: unknown }; -} - -/** - * @category Content - */ -export interface TextResourceContents extends ResourceContents { - /** - * The text of the item. This must only be set if the item can actually be represented as text (not binary data). - */ - text: string; -} - -/** - * @category Content - */ -export interface BlobResourceContents extends ResourceContents { - /** - * A base64-encoded string representing the binary data of the item. - * - * @format byte - */ - blob: string; -} - -/* Prompts */ -/** - * Sent from the client to request a list of prompts and prompt templates the server has. - * - * @category `prompts/list` - */ -export interface ListPromptsRequest extends PaginatedRequest { - method: "prompts/list"; -} - -/** - * The server's response to a prompts/list request from the client. - * - * @category `prompts/list` - */ -export interface ListPromptsResult extends PaginatedResult { - prompts: Prompt[]; -} - -/** - * Parameters for a `prompts/get` request. - * - * @category `prompts/get` - */ -export interface GetPromptRequestParams extends RequestParams { - /** - * The name of the prompt or prompt template. - */ - name: string; - /** - * Arguments to use for templating the prompt. - */ - arguments?: { [key: string]: string }; -} - -/** - * Used by the client to get a prompt provided by the server. - * - * @category `prompts/get` - */ -export interface GetPromptRequest extends JSONRPCRequest { - method: "prompts/get"; - params: GetPromptRequestParams; -} - -/** - * The server's response to a prompts/get request from the client. - * - * @category `prompts/get` - */ -export interface GetPromptResult extends Result { - /** - * An optional description for the prompt. - */ - description?: string; - messages: PromptMessage[]; -} - -/** - * A prompt or prompt template that the server offers. - * - * @category `prompts/list` - */ -export interface Prompt extends BaseMetadata, Icons { - /** - * An optional description of what this prompt provides - */ - description?: string; - - /** - * A list of arguments to use for templating the prompt. - */ - arguments?: PromptArgument[]; - - /** - * See [General fields: `_meta`](/specification/draft/basic/index#meta) for notes on `_meta` usage. - */ - _meta?: { [key: string]: unknown }; -} - -/** - * Describes an argument that a prompt can accept. - * - * @category `prompts/list` - */ -export interface PromptArgument extends BaseMetadata { - /** - * A human-readable description of the argument. - */ - description?: string; - /** - * Whether this argument must be provided. - */ - required?: boolean; -} - -/** - * The sender or recipient of messages and data in a conversation. - * - * @category Common Types - */ -export type Role = "user" | "assistant"; - -/** - * Describes a message returned as part of a prompt. - * - * This is similar to `SamplingMessage`, but also supports the embedding of - * resources from the MCP server. - * - * @category `prompts/get` - */ -export interface PromptMessage { - role: Role; - content: ContentBlock; -} - -/** - * A resource that the server is capable of reading, included in a prompt or tool call result. - * - * Note: resource links returned by tools are not guaranteed to appear in the results of `resources/list` requests. - * - * @category Content - */ -export interface ResourceLink extends Resource { - type: "resource_link"; -} - -/** - * The contents of a resource, embedded into a prompt or tool call result. - * - * It is up to the client how best to render embedded resources for the benefit - * of the LLM and/or the user. - * - * @category Content - */ -export interface EmbeddedResource { - type: "resource"; - resource: TextResourceContents | BlobResourceContents; - - /** - * Optional annotations for the client. - */ - annotations?: Annotations; - - /** - * See [General fields: `_meta`](/specification/draft/basic/index#meta) for notes on `_meta` usage. - */ - _meta?: { [key: string]: unknown }; -} -/** - * An optional notification from the server to the client, informing it that the list of prompts it offers has changed. This may be issued by servers without any previous subscription from the client. - * - * @category `notifications/prompts/list_changed` - */ -export interface PromptListChangedNotification extends JSONRPCNotification { - method: "notifications/prompts/list_changed"; - params?: NotificationParams; -} - -/* Tools */ -/** - * Sent from the client to request a list of tools the server has. - * - * @category `tools/list` - */ -export interface ListToolsRequest extends PaginatedRequest { - method: "tools/list"; -} - -/** - * The server's response to a tools/list request from the client. - * - * @category `tools/list` - */ -export interface ListToolsResult extends PaginatedResult { - tools: Tool[]; -} - -/** - * The server's response to a tool call. - * - * @category `tools/call` - */ -export interface CallToolResult extends Result { - /** - * A list of content objects that represent the unstructured result of the tool call. - */ - content: ContentBlock[]; - - /** - * An optional JSON object that represents the structured result of the tool call. - */ - structuredContent?: { [key: string]: unknown }; - - /** - * Whether the tool call ended in an error. - * - * If not set, this is assumed to be false (the call was successful). - * - * Any errors that originate from the tool SHOULD be reported inside the result - * object, with `isError` set to true, _not_ as an MCP protocol-level error - * response. Otherwise, the LLM would not be able to see that an error occurred - * and self-correct. - * - * However, any errors in _finding_ the tool, an error indicating that the - * server does not support tool calls, or any other exceptional conditions, - * should be reported as an MCP error response. - */ - isError?: boolean; -} - -/** - * Parameters for a `tools/call` request. - * - * @category `tools/call` - */ -export interface CallToolRequestParams extends TaskAugmentedRequestParams { - /** - * The name of the tool. - */ - name: string; - /** - * Arguments to use for the tool call. - */ - arguments?: { [key: string]: unknown }; -} - -/** - * Used by the client to invoke a tool provided by the server. - * - * @category `tools/call` - */ -export interface CallToolRequest extends JSONRPCRequest { - method: "tools/call"; - params: CallToolRequestParams; -} - -/** - * An optional notification from the server to the client, informing it that the list of tools it offers has changed. This may be issued by servers without any previous subscription from the client. - * - * @category `notifications/tools/list_changed` - */ -export interface ToolListChangedNotification extends JSONRPCNotification { - method: "notifications/tools/list_changed"; - params?: NotificationParams; -} - -/** - * Additional properties describing a Tool to clients. - * - * NOTE: all properties in ToolAnnotations are **hints**. - * They are not guaranteed to provide a faithful description of - * tool behavior (including descriptive properties like `title`). - * - * Clients should never make tool use decisions based on ToolAnnotations - * received from untrusted servers. - * - * @category `tools/list` - */ -export interface ToolAnnotations { - /** - * A human-readable title for the tool. - */ - title?: string; - - /** - * If true, the tool does not modify its environment. - * - * Default: false - */ - readOnlyHint?: boolean; - - /** - * If true, the tool may perform destructive updates to its environment. - * If false, the tool performs only additive updates. - * - * (This property is meaningful only when `readOnlyHint == false`) - * - * Default: true - */ - destructiveHint?: boolean; - - /** - * If true, calling the tool repeatedly with the same arguments - * will have no additional effect on its environment. - * - * (This property is meaningful only when `readOnlyHint == false`) - * - * Default: false - */ - idempotentHint?: boolean; - - /** - * If true, this tool may interact with an "open world" of external - * entities. If false, the tool's domain of interaction is closed. - * For example, the world of a web search tool is open, whereas that - * of a memory tool is not. - * - * Default: true - */ - openWorldHint?: boolean; -} - -/** - * Execution-related properties for a tool. - * - * @category `tools/list` - */ -export interface ToolExecution { - /** - * Indicates whether this tool supports task-augmented execution. - * This allows clients to handle long-running operations through polling - * the task system. - * - * - "forbidden": Tool does not support task-augmented execution (default when absent) - * - "optional": Tool may support task-augmented execution - * - "required": Tool requires task-augmented execution - * - * Default: "forbidden" - */ - taskSupport?: "forbidden" | "optional" | "required"; -} - -/** - * Definition for a tool the client can call. - * - * @category `tools/list` - */ -export interface Tool extends BaseMetadata, Icons { - /** - * A human-readable description of the tool. - * - * This can be used by clients to improve the LLM's understanding of available tools. It can be thought of like a "hint" to the model. - */ - description?: string; - - /** - * A JSON Schema object defining the expected parameters for the tool. - */ - inputSchema: { - $schema?: string; - type: "object"; - properties?: { [key: string]: object }; - required?: string[]; - }; - - /** - * Execution-related properties for this tool. - */ - execution?: ToolExecution; - - /** - * An optional JSON Schema object defining the structure of the tool's output returned in - * the structuredContent field of a CallToolResult. - * - * Defaults to JSON Schema 2020-12 when no explicit $schema is provided. - * Currently restricted to type: "object" at the root level. - */ - outputSchema?: { - $schema?: string; - type: "object"; - properties?: { [key: string]: object }; - required?: string[]; - }; - - /** - * Optional additional tool information. - * - * Display name precedence order is: title, annotations.title, then name. - */ - annotations?: ToolAnnotations; - - /** - * See [General fields: `_meta`](/specification/draft/basic/index#meta) for notes on `_meta` usage. - */ - _meta?: { [key: string]: unknown }; -} - -/* Tasks */ - -/** - * The status of a task. - * - * @category `tasks` - */ -export type TaskStatus = - | "working" // The request is currently being processed - | "input_required" // The task is waiting for input (e.g., elicitation or sampling) - | "completed" // The request completed successfully and results are available - | "failed" // The associated request did not complete successfully. For tool calls specifically, this includes cases where the tool call result has `isError` set to true. - | "cancelled"; // The request was cancelled before completion - -/** - * Metadata for augmenting a request with task execution. - * Include this in the `task` field of the request parameters. - * - * @category `tasks` - */ -export interface TaskMetadata { - /** - * Requested duration in milliseconds to retain task from creation. - */ - ttl?: number; -} - -/** - * Metadata for associating messages with a task. - * Include this in the `_meta` field under the key `io.modelcontextprotocol/related-task`. - * - * @category `tasks` - */ -export interface RelatedTaskMetadata { - /** - * The task identifier this message is associated with. - */ - taskId: string; -} - -/** - * Data associated with a task. - * - * @category `tasks` - */ -export interface Task { - /** - * The task identifier. - */ - taskId: string; - - /** - * Current task state. - */ - status: TaskStatus; - - /** - * Optional human-readable message describing the current task state. - * This can provide context for any status, including: - * - Reasons for "cancelled" status - * - Summaries for "completed" status - * - Diagnostic information for "failed" status (e.g., error details, what went wrong) - */ - statusMessage?: string; - - /** - * ISO 8601 timestamp when the task was created. - */ - createdAt: string; - - /** - * ISO 8601 timestamp when the task was last updated. - */ - lastUpdatedAt: string; - - /** - * Actual retention duration from creation in milliseconds, null for unlimited. - */ - ttl: number | null; - - /** - * Suggested polling interval in milliseconds. - */ - pollInterval?: number; -} - -/** - * A response to a task-augmented request. - * - * @category `tasks` - */ -export interface CreateTaskResult extends Result { - task: Task; -} - -/** - * A request to retrieve the state of a task. - * - * @category `tasks/get` - */ -export interface GetTaskRequest extends JSONRPCRequest { - method: "tasks/get"; - params: { - /** - * The task identifier to query. - */ - taskId: string; - }; -} - -/** - * The response to a tasks/get request. - * - * @category `tasks/get` - */ -export type GetTaskResult = Result & Task; - -/** - * A request to retrieve the result of a completed task. - * - * @category `tasks/result` - */ -export interface GetTaskPayloadRequest extends JSONRPCRequest { - method: "tasks/result"; - params: { - /** - * The task identifier to retrieve results for. - */ - taskId: string; - }; -} - -/** - * The response to a tasks/result request. - * The structure matches the result type of the original request. - * For example, a tools/call task would return the CallToolResult structure. - * - * @category `tasks/result` - */ -export interface GetTaskPayloadResult extends Result { - [key: string]: unknown; -} - -/** - * A request to cancel a task. - * - * @category `tasks/cancel` - */ -export interface CancelTaskRequest extends JSONRPCRequest { - method: "tasks/cancel"; - params: { - /** - * The task identifier to cancel. - */ - taskId: string; - }; -} - -/** - * The response to a tasks/cancel request. - * - * @category `tasks/cancel` - */ -export type CancelTaskResult = Result & Task; - -/** - * A request to retrieve a list of tasks. - * - * @category `tasks/list` - */ -export interface ListTasksRequest extends PaginatedRequest { - method: "tasks/list"; -} - -/** - * The response to a tasks/list request. - * - * @category `tasks/list` - */ -export interface ListTasksResult extends PaginatedResult { - tasks: Task[]; -} - -/** - * Parameters for a `notifications/tasks/status` notification. - * - * @category `notifications/tasks/status` - */ -export type TaskStatusNotificationParams = NotificationParams & Task; - -/** - * An optional notification from the receiver to the requestor, informing them that a task's status has changed. Receivers are not required to send these notifications. - * - * @category `notifications/tasks/status` - */ -export interface TaskStatusNotification extends JSONRPCNotification { - method: "notifications/tasks/status"; - params: TaskStatusNotificationParams; -} - -/* Logging */ - -/** - * Parameters for a `logging/setLevel` request. - * - * @category `logging/setLevel` - */ -export interface SetLevelRequestParams extends RequestParams { - /** - * The level of logging that the client wants to receive from the server. The server should send all logs at this level and higher (i.e., more severe) to the client as notifications/message. - */ - level: LoggingLevel; -} - -/** - * A request from the client to the server, to enable or adjust logging. - * - * @category `logging/setLevel` - */ -export interface SetLevelRequest extends JSONRPCRequest { - method: "logging/setLevel"; - params: SetLevelRequestParams; -} - -/** - * Parameters for a `notifications/message` notification. - * - * @category `notifications/message` - */ -export interface LoggingMessageNotificationParams extends NotificationParams { - /** - * The severity of this log message. - */ - level: LoggingLevel; - /** - * An optional name of the logger issuing this message. - */ - logger?: string; - /** - * The data to be logged, such as a string message or an object. Any JSON serializable type is allowed here. - */ - data: unknown; -} - -/** - * JSONRPCNotification of a log message passed from server to client. If no logging/setLevel request has been sent from the client, the server MAY decide which messages to send automatically. - * - * @category `notifications/message` - */ -export interface LoggingMessageNotification extends JSONRPCNotification { - method: "notifications/message"; - params: LoggingMessageNotificationParams; -} - -/** - * The severity of a log message. - * - * These map to syslog message severities, as specified in RFC-5424: - * https://datatracker.ietf.org/doc/html/rfc5424#section-6.2.1 - * - * @category Common Types - */ -export type LoggingLevel = - | "debug" - | "info" - | "notice" - | "warning" - | "error" - | "critical" - | "alert" - | "emergency"; - -/* Sampling */ -/** - * Parameters for a `sampling/createMessage` request. - * - * @category `sampling/createMessage` - */ -export interface CreateMessageRequestParams extends TaskAugmentedRequestParams { - messages: SamplingMessage[]; - /** - * The server's preferences for which model to select. The client MAY ignore these preferences. - */ - modelPreferences?: ModelPreferences; - /** - * An optional system prompt the server wants to use for sampling. The client MAY modify or omit this prompt. - */ - systemPrompt?: string; - /** - * A request to include context from one or more MCP servers (including the caller), to be attached to the prompt. - * The client MAY ignore this request. - * - * Default is "none". Values "thisServer" and "allServers" are soft-deprecated. Servers SHOULD only use these values if the client - * declares ClientCapabilities.sampling.context. These values may be removed in future spec releases. - */ - includeContext?: "none" | "thisServer" | "allServers"; - /** - * @TJS-type number - */ - temperature?: number; - /** - * The requested maximum number of tokens to sample (to prevent runaway completions). - * - * The client MAY choose to sample fewer tokens than the requested maximum. - */ - maxTokens: number; - stopSequences?: string[]; - /** - * Optional metadata to pass through to the LLM provider. The format of this metadata is provider-specific. - */ - metadata?: object; - /** - * Tools that the model may use during generation. - * The client MUST return an error if this field is provided but ClientCapabilities.sampling.tools is not declared. - */ - tools?: Tool[]; - /** - * Controls how the model uses tools. - * The client MUST return an error if this field is provided but ClientCapabilities.sampling.tools is not declared. - * Default is `{ mode: "auto" }`. - */ - toolChoice?: ToolChoice; -} - -/** - * Controls tool selection behavior for sampling requests. - * - * @category `sampling/createMessage` - */ -export interface ToolChoice { - /** - * Controls the tool use ability of the model: - * - "auto": Model decides whether to use tools (default) - * - "required": Model MUST use at least one tool before completing - * - "none": Model MUST NOT use any tools - */ - mode?: "auto" | "required" | "none"; -} - -/** - * A request from the server to sample an LLM via the client. The client has full discretion over which model to select. The client should also inform the user before beginning sampling, to allow them to inspect the request (human in the loop) and decide whether to approve it. - * - * @category `sampling/createMessage` - */ -export interface CreateMessageRequest extends JSONRPCRequest { - method: "sampling/createMessage"; - params: CreateMessageRequestParams; -} - -/** - * The client's response to a sampling/createMessage request from the server. - * The client should inform the user before returning the sampled message, to allow them - * to inspect the response (human in the loop) and decide whether to allow the server to see it. - * - * @category `sampling/createMessage` - */ -export interface CreateMessageResult extends Result, SamplingMessage { - /** - * The name of the model that generated the message. - */ - model: string; - - /** - * The reason why sampling stopped, if known. - * - * Standard values: - * - "endTurn": Natural end of the assistant's turn - * - "stopSequence": A stop sequence was encountered - * - "maxTokens": Maximum token limit was reached - * - "toolUse": The model wants to use one or more tools - * - * This field is an open string to allow for provider-specific stop reasons. - */ - stopReason?: "endTurn" | "stopSequence" | "maxTokens" | "toolUse" | string; -} - -/** - * Describes a message issued to or received from an LLM API. - * - * @category `sampling/createMessage` - */ -export interface SamplingMessage { - role: Role; - content: SamplingMessageContentBlock | SamplingMessageContentBlock[]; - /** - * See [General fields: `_meta`](/specification/draft/basic/index#meta) for notes on `_meta` usage. - */ - _meta?: { [key: string]: unknown }; -} -export type SamplingMessageContentBlock = - | TextContent - | ImageContent - | AudioContent - | ToolUseContent - | ToolResultContent; - -/** - * Optional annotations for the client. The client can use annotations to inform how objects are used or displayed - * - * @category Common Types - */ -export interface Annotations { - /** - * Describes who the intended audience of this object or data is. - * - * It can include multiple entries to indicate content useful for multiple audiences (e.g., `["user", "assistant"]`). - */ - audience?: Role[]; - - /** - * Describes how important this data is for operating the server. - * - * A value of 1 means "most important," and indicates that the data is - * effectively required, while 0 means "least important," and indicates that - * the data is entirely optional. - * - * @TJS-type number - * @minimum 0 - * @maximum 1 - */ - priority?: number; - - /** - * The moment the resource was last modified, as an ISO 8601 formatted string. - * - * Should be an ISO 8601 formatted string (e.g., "2025-01-12T15:00:58Z"). - * - * Examples: last activity timestamp in an open file, timestamp when the resource - * was attached, etc. - */ - lastModified?: string; -} - -/** - * @category Content - */ -export type ContentBlock = - | TextContent - | ImageContent - | AudioContent - | ResourceLink - | EmbeddedResource; - -/** - * Text provided to or from an LLM. - * - * @category Content - */ -export interface TextContent { - type: "text"; - - /** - * The text content of the message. - */ - text: string; - - /** - * Optional annotations for the client. - */ - annotations?: Annotations; - - /** - * See [General fields: `_meta`](/specification/draft/basic/index#meta) for notes on `_meta` usage. - */ - _meta?: { [key: string]: unknown }; -} - -/** - * An image provided to or from an LLM. - * - * @category Content - */ -export interface ImageContent { - type: "image"; - - /** - * The base64-encoded image data. - * - * @format byte - */ - data: string; - - /** - * The MIME type of the image. Different providers may support different image types. - */ - mimeType: string; - - /** - * Optional annotations for the client. - */ - annotations?: Annotations; - - /** - * See [General fields: `_meta`](/specification/draft/basic/index#meta) for notes on `_meta` usage. - */ - _meta?: { [key: string]: unknown }; -} - -/** - * Audio provided to or from an LLM. - * - * @category Content - */ -export interface AudioContent { - type: "audio"; - - /** - * The base64-encoded audio data. - * - * @format byte - */ - data: string; - - /** - * The MIME type of the audio. Different providers may support different audio types. - */ - mimeType: string; - - /** - * Optional annotations for the client. - */ - annotations?: Annotations; - - /** - * See [General fields: `_meta`](/specification/draft/basic/index#meta) for notes on `_meta` usage. - */ - _meta?: { [key: string]: unknown }; -} - -/** - * A request from the assistant to call a tool. - * - * @category `sampling/createMessage` - */ -export interface ToolUseContent { - type: "tool_use"; - - /** - * A unique identifier for this tool use. - * - * This ID is used to match tool results to their corresponding tool uses. - */ - id: string; - - /** - * The name of the tool to call. - */ - name: string; - - /** - * The arguments to pass to the tool, conforming to the tool's input schema. - */ - input: { [key: string]: unknown }; - - /** - * Optional metadata about the tool use. Clients SHOULD preserve this field when - * including tool uses in subsequent sampling requests to enable caching optimizations. - * - * See [General fields: `_meta`](/specification/draft/basic/index#meta) for notes on `_meta` usage. - */ - _meta?: { [key: string]: unknown }; -} - -/** - * The result of a tool use, provided by the user back to the assistant. - * - * @category `sampling/createMessage` - */ -export interface ToolResultContent { - type: "tool_result"; - - /** - * The ID of the tool use this result corresponds to. - * - * This MUST match the ID from a previous ToolUseContent. - */ - toolUseId: string; - - /** - * The unstructured result content of the tool use. - * - * This has the same format as CallToolResult.content and can include text, images, - * audio, resource links, and embedded resources. - */ - content: ContentBlock[]; - - /** - * An optional structured result object. - * - * If the tool defined an outputSchema, this SHOULD conform to that schema. - */ - structuredContent?: { [key: string]: unknown }; - - /** - * Whether the tool use resulted in an error. - * - * If true, the content typically describes the error that occurred. - * Default: false - */ - isError?: boolean; - - /** - * Optional metadata about the tool result. Clients SHOULD preserve this field when - * including tool results in subsequent sampling requests to enable caching optimizations. - * - * See [General fields: `_meta`](/specification/draft/basic/index#meta) for notes on `_meta` usage. - */ - _meta?: { [key: string]: unknown }; -} - -/** - * The server's preferences for model selection, requested of the client during sampling. - * - * Because LLMs can vary along multiple dimensions, choosing the "best" model is - * rarely straightforward. Different models excel in different areas—some are - * faster but less capable, others are more capable but more expensive, and so - * on. This interface allows servers to express their priorities across multiple - * dimensions to help clients make an appropriate selection for their use case. - * - * These preferences are always advisory. The client MAY ignore them. It is also - * up to the client to decide how to interpret these preferences and how to - * balance them against other considerations. - * - * @category `sampling/createMessage` - */ -export interface ModelPreferences { - /** - * Optional hints to use for model selection. - * - * If multiple hints are specified, the client MUST evaluate them in order - * (such that the first match is taken). - * - * The client SHOULD prioritize these hints over the numeric priorities, but - * MAY still use the priorities to select from ambiguous matches. - */ - hints?: ModelHint[]; - - /** - * How much to prioritize cost when selecting a model. A value of 0 means cost - * is not important, while a value of 1 means cost is the most important - * factor. - * - * @TJS-type number - * @minimum 0 - * @maximum 1 - */ - costPriority?: number; - - /** - * How much to prioritize sampling speed (latency) when selecting a model. A - * value of 0 means speed is not important, while a value of 1 means speed is - * the most important factor. - * - * @TJS-type number - * @minimum 0 - * @maximum 1 - */ - speedPriority?: number; - - /** - * How much to prioritize intelligence and capabilities when selecting a - * model. A value of 0 means intelligence is not important, while a value of 1 - * means intelligence is the most important factor. - * - * @TJS-type number - * @minimum 0 - * @maximum 1 - */ - intelligencePriority?: number; -} - -/** - * Hints to use for model selection. - * - * Keys not declared here are currently left unspecified by the spec and are up - * to the client to interpret. - * - * @category `sampling/createMessage` - */ -export interface ModelHint { - /** - * A hint for a model name. - * - * The client SHOULD treat this as a substring of a model name; for example: - * - `claude-3-5-sonnet` should match `claude-3-5-sonnet-20241022` - * - `sonnet` should match `claude-3-5-sonnet-20241022`, `claude-3-sonnet-20240229`, etc. - * - `claude` should match any Claude model - * - * The client MAY also map the string to a different provider's model name or a different model family, as long as it fills a similar niche; for example: - * - `gemini-1.5-flash` could match `claude-3-haiku-20240307` - */ - name?: string; -} - -/* Autocomplete */ -/** - * Parameters for a `completion/complete` request. - * - * @category `completion/complete` - */ -export interface CompleteRequestParams extends RequestParams { - ref: PromptReference | ResourceTemplateReference; - /** - * The argument's information - */ - argument: { - /** - * The name of the argument - */ - name: string; - /** - * The value of the argument to use for completion matching. - */ - value: string; - }; - - /** - * Additional, optional context for completions - */ - context?: { - /** - * Previously-resolved variables in a URI template or prompt. - */ - arguments?: { [key: string]: string }; - }; -} - -/** - * A request from the client to the server, to ask for completion options. - * - * @category `completion/complete` - */ -export interface CompleteRequest extends JSONRPCRequest { - method: "completion/complete"; - params: CompleteRequestParams; -} - -/** - * The server's response to a completion/complete request - * - * @category `completion/complete` - */ -export interface CompleteResult extends Result { - completion: { - /** - * An array of completion values. Must not exceed 100 items. - */ - values: string[]; - /** - * The total number of completion options available. This can exceed the number of values actually sent in the response. - */ - total?: number; - /** - * Indicates whether there are additional completion options beyond those provided in the current response, even if the exact total is unknown. - */ - hasMore?: boolean; - }; -} - -/** - * A reference to a resource or resource template definition. - * - * @category `completion/complete` - */ -export interface ResourceTemplateReference { - type: "ref/resource"; - /** - * The URI or URI template of the resource. - * - * @format uri-template - */ - uri: string; -} - -/** - * Identifies a prompt. - * - * @category `completion/complete` - */ -export interface PromptReference extends BaseMetadata { - type: "ref/prompt"; -} - -/* Roots */ -/** - * Sent from the server to request a list of root URIs from the client. Roots allow - * servers to ask for specific directories or files to operate on. A common example - * for roots is providing a set of repositories or directories a server should operate - * on. - * - * This request is typically used when the server needs to understand the file system - * structure or access specific locations that the client has permission to read from. - * - * @category `roots/list` - */ -export interface ListRootsRequest extends JSONRPCRequest { - method: "roots/list"; - params?: RequestParams; -} - -/** - * The client's response to a roots/list request from the server. - * This result contains an array of Root objects, each representing a root directory - * or file that the server can operate on. - * - * @category `roots/list` - */ -export interface ListRootsResult extends Result { - roots: Root[]; -} - -/** - * Represents a root directory or file that the server can operate on. - * - * @category `roots/list` - */ -export interface Root { - /** - * The URI identifying the root. This *must* start with file:// for now. - * This restriction may be relaxed in future versions of the protocol to allow - * other URI schemes. - * - * @format uri - */ - uri: string; - /** - * An optional name for the root. This can be used to provide a human-readable - * identifier for the root, which may be useful for display purposes or for - * referencing the root in other parts of the application. - */ - name?: string; - - /** - * See [General fields: `_meta`](/specification/draft/basic/index#meta) for notes on `_meta` usage. - */ - _meta?: { [key: string]: unknown }; -} - -/** - * A notification from the client to the server, informing it that the list of roots has changed. - * This notification should be sent whenever the client adds, removes, or modifies any root. - * The server should then request an updated list of roots using the ListRootsRequest. - * - * @category `notifications/roots/list_changed` - */ -export interface RootsListChangedNotification extends JSONRPCNotification { - method: "notifications/roots/list_changed"; - params?: NotificationParams; -} - -/** - * The parameters for a request to elicit non-sensitive information from the user via a form in the client. - * - * @category `elicitation/create` - */ -export interface ElicitRequestFormParams extends TaskAugmentedRequestParams { - /** - * The elicitation mode. - */ - mode?: "form"; - - /** - * The message to present to the user describing what information is being requested. - */ - message: string; - - /** - * A restricted subset of JSON Schema. - * Only top-level properties are allowed, without nesting. - */ - requestedSchema: { - $schema?: string; - type: "object"; - properties: { - [key: string]: PrimitiveSchemaDefinition; - }; - required?: string[]; - }; -} - -/** - * The parameters for a request to elicit information from the user via a URL in the client. - * - * @category `elicitation/create` - */ -export interface ElicitRequestURLParams extends TaskAugmentedRequestParams { - /** - * The elicitation mode. - */ - mode: "url"; - - /** - * The message to present to the user explaining why the interaction is needed. - */ - message: string; - - /** - * The ID of the elicitation, which must be unique within the context of the server. - * The client MUST treat this ID as an opaque value. - */ - elicitationId: string; - - /** - * The URL that the user should navigate to. - * - * @format uri - */ - url: string; -} - -/** - * The parameters for a request to elicit additional information from the user via the client. - * - * @category `elicitation/create` - */ -export type ElicitRequestParams = - | ElicitRequestFormParams - | ElicitRequestURLParams; - -/** - * A request from the server to elicit additional information from the user via the client. - * - * @category `elicitation/create` - */ -export interface ElicitRequest extends JSONRPCRequest { - method: "elicitation/create"; - params: ElicitRequestParams; -} - -/** - * Restricted schema definitions that only allow primitive types - * without nested objects or arrays. - * - * @category `elicitation/create` - */ -export type PrimitiveSchemaDefinition = - | StringSchema - | NumberSchema - | BooleanSchema - | EnumSchema; - -/** - * @category `elicitation/create` - */ -export interface StringSchema { - type: "string"; - title?: string; - description?: string; - minLength?: number; - maxLength?: number; - format?: "email" | "uri" | "date" | "date-time"; - default?: string; -} - -/** - * @category `elicitation/create` - */ -export interface NumberSchema { - type: "number" | "integer"; - title?: string; - description?: string; - minimum?: number; - maximum?: number; - default?: number; -} - -/** - * @category `elicitation/create` - */ -export interface BooleanSchema { - type: "boolean"; - title?: string; - description?: string; - default?: boolean; -} - -/** - * Schema for single-selection enumeration without display titles for options. - * - * @category `elicitation/create` - */ -export interface UntitledSingleSelectEnumSchema { - type: "string"; - /** - * Optional title for the enum field. - */ - title?: string; - /** - * Optional description for the enum field. - */ - description?: string; - /** - * Array of enum values to choose from. - */ - enum: string[]; - /** - * Optional default value. - */ - default?: string; -} - -/** - * Schema for single-selection enumeration with display titles for each option. - * - * @category `elicitation/create` - */ -export interface TitledSingleSelectEnumSchema { - type: "string"; - /** - * Optional title for the enum field. - */ - title?: string; - /** - * Optional description for the enum field. - */ - description?: string; - /** - * Array of enum options with values and display labels. - */ - oneOf: Array<{ - /** - * The enum value. - */ - const: string; - /** - * Display label for this option. - */ - title: string; - }>; - /** - * Optional default value. - */ - default?: string; -} - -/** - * @category `elicitation/create` - */ -// Combined single selection enumeration -export type SingleSelectEnumSchema = - | UntitledSingleSelectEnumSchema - | TitledSingleSelectEnumSchema; - -/** - * Schema for multiple-selection enumeration without display titles for options. - * - * @category `elicitation/create` - */ -export interface UntitledMultiSelectEnumSchema { - type: "array"; - /** - * Optional title for the enum field. - */ - title?: string; - /** - * Optional description for the enum field. - */ - description?: string; - /** - * Minimum number of items to select. - */ - minItems?: number; - /** - * Maximum number of items to select. - */ - maxItems?: number; - /** - * Schema for the array items. - */ - items: { - type: "string"; - /** - * Array of enum values to choose from. - */ - enum: string[]; - }; - /** - * Optional default value. - */ - default?: string[]; -} - -/** - * Schema for multiple-selection enumeration with display titles for each option. - * - * @category `elicitation/create` - */ -export interface TitledMultiSelectEnumSchema { - type: "array"; - /** - * Optional title for the enum field. - */ - title?: string; - /** - * Optional description for the enum field. - */ - description?: string; - /** - * Minimum number of items to select. - */ - minItems?: number; - /** - * Maximum number of items to select. - */ - maxItems?: number; - /** - * Schema for array items with enum options and display labels. - */ - items: { - /** - * Array of enum options with values and display labels. - */ - anyOf: Array<{ - /** - * The constant enum value. - */ - const: string; - /** - * Display title for this option. - */ - title: string; - }>; - }; - /** - * Optional default value. - */ - default?: string[]; -} - -/** - * @category `elicitation/create` - */ -// Combined multiple selection enumeration -export type MultiSelectEnumSchema = - | UntitledMultiSelectEnumSchema - | TitledMultiSelectEnumSchema; - -/** - * Use TitledSingleSelectEnumSchema instead. - * This interface will be removed in a future version. - * - * @category `elicitation/create` - */ -export interface LegacyTitledEnumSchema { - type: "string"; - title?: string; - description?: string; - enum: string[]; - /** - * (Legacy) Display names for enum values. - * Non-standard according to JSON schema 2020-12. - */ - enumNames?: string[]; - default?: string; -} - -/** - * @category `elicitation/create` - */ -// Union type for all enum schemas -export type EnumSchema = - | SingleSelectEnumSchema - | MultiSelectEnumSchema - | LegacyTitledEnumSchema; - -/** - * The client's response to an elicitation request. - * - * @category `elicitation/create` - */ -export interface ElicitResult extends Result { - /** - * The user action in response to the elicitation. - * - "accept": User submitted the form/confirmed the action - * - "decline": User explicitly decline the action - * - "cancel": User dismissed without making an explicit choice - */ - action: "accept" | "decline" | "cancel"; - - /** - * The submitted form data, only present when action is "accept" and mode was "form". - * Contains values matching the requested schema. - * Omitted for out-of-band mode responses. - */ - content?: { [key: string]: string | number | boolean | string[] }; -} - -/** - * An optional notification from the server to the client, informing it of a completion of a out-of-band elicitation request. - * - * @category `notifications/elicitation/complete` - */ -export interface ElicitationCompleteNotification extends JSONRPCNotification { - method: "notifications/elicitation/complete"; - params: { - /** - * The ID of the elicitation that completed. - */ - elicitationId: string; - }; -} - -/* Client messages */ -/** @internal */ -export type ClientRequest = - | PingRequest - | InitializeRequest - | CompleteRequest - | SetLevelRequest - | GetPromptRequest - | ListPromptsRequest - | ListResourcesRequest - | ListResourceTemplatesRequest - | ReadResourceRequest - | SubscribeRequest - | UnsubscribeRequest - | CallToolRequest - | ListToolsRequest - | GetTaskRequest - | GetTaskPayloadRequest - | ListTasksRequest - | CancelTaskRequest; - -/** @internal */ -export type ClientNotification = - | CancelledNotification - | ProgressNotification - | InitializedNotification - | RootsListChangedNotification - | TaskStatusNotification; - -/** @internal */ -export type ClientResult = - | EmptyResult - | CreateMessageResult - | ListRootsResult - | ElicitResult - | GetTaskResult - | GetTaskPayloadResult - | ListTasksResult - | CancelTaskResult; - -/* Server messages */ -/** @internal */ -export type ServerRequest = - | PingRequest - | CreateMessageRequest - | ListRootsRequest - | ElicitRequest - | GetTaskRequest - | GetTaskPayloadRequest - | ListTasksRequest - | CancelTaskRequest; - -/** @internal */ -export type ServerNotification = - | CancelledNotification - | ProgressNotification - | LoggingMessageNotification - | ResourceUpdatedNotification - | ResourceListChangedNotification - | ToolListChangedNotification - | PromptListChangedNotification - | ElicitationCompleteNotification - | TaskStatusNotification; - -/** @internal */ -export type ServerResult = - | EmptyResult - | InitializeResult - | CompleteResult - | GetPromptResult - | ListPromptsResult - | ListResourceTemplatesResult - | ListResourcesResult - | ReadResourceResult - | CallToolResult - | ListToolsResult - | GetTaskResult - | GetTaskPayloadResult - | ListTasksResult - | CancelTaskResult; diff --git a/test/experimental/tasks/stores/in-memory.test.ts b/test/experimental/tasks/stores/in-memory.test.ts deleted file mode 100644 index ceef6c6d8..000000000 --- a/test/experimental/tasks/stores/in-memory.test.ts +++ /dev/null @@ -1,936 +0,0 @@ -import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; -import { InMemoryTaskStore, InMemoryTaskMessageQueue } from '../../../../src/experimental/tasks/stores/in-memory.js'; -import { TaskCreationParams, Request } from '../../../../src/types.js'; -import { QueuedMessage } from '../../../../src/experimental/tasks/interfaces.js'; - -describe('InMemoryTaskStore', () => { - let store: InMemoryTaskStore; - - beforeEach(() => { - store = new InMemoryTaskStore(); - }); - - afterEach(() => { - store.cleanup(); - }); - - describe('createTask', () => { - it('should create a new task with working status', async () => { - const taskParams: TaskCreationParams = { - ttl: 60000 - }; - const request: Request = { - method: 'tools/call', - params: { name: 'test-tool' } - }; - - const task = await store.createTask(taskParams, 123, request); - - expect(task).toBeDefined(); - expect(task.taskId).toBeDefined(); - expect(typeof task.taskId).toBe('string'); - expect(task.taskId.length).toBeGreaterThan(0); - expect(task.status).toBe('working'); - expect(task.ttl).toBe(60000); - expect(task.pollInterval).toBeDefined(); - expect(task.createdAt).toBeDefined(); - expect(new Date(task.createdAt).getTime()).toBeGreaterThan(0); - }); - - it('should create task without ttl', async () => { - const taskParams: TaskCreationParams = {}; - const request: Request = { - method: 'tools/call', - params: {} - }; - - const task = await store.createTask(taskParams, 456, request); - - expect(task).toBeDefined(); - expect(task.ttl).toBeNull(); - }); - - it('should generate unique taskIds', async () => { - const taskParams: TaskCreationParams = {}; - const request: Request = { - method: 'tools/call', - params: {} - }; - - const task1 = await store.createTask(taskParams, 789, request); - const task2 = await store.createTask(taskParams, 790, request); - - expect(task1.taskId).not.toBe(task2.taskId); - }); - }); - - describe('getTask', () => { - it('should return null for non-existent task', async () => { - const task = await store.getTask('non-existent'); - expect(task).toBeNull(); - }); - - it('should return task state', async () => { - const taskParams: TaskCreationParams = {}; - const request: Request = { - method: 'tools/call', - params: {} - }; - - const createdTask = await store.createTask(taskParams, 111, request); - await store.updateTaskStatus(createdTask.taskId, 'working'); - - const task = await store.getTask(createdTask.taskId); - expect(task).toBeDefined(); - expect(task?.status).toBe('working'); - }); - }); - - describe('updateTaskStatus', () => { - let taskId: string; - - beforeEach(async () => { - const taskParams: TaskCreationParams = {}; - const createdTask = await store.createTask(taskParams, 222, { - method: 'tools/call', - params: {} - }); - taskId = createdTask.taskId; - }); - - it('should keep task status as working', async () => { - const task = await store.getTask(taskId); - expect(task?.status).toBe('working'); - }); - - it('should update task status to input_required', async () => { - await store.updateTaskStatus(taskId, 'input_required'); - - const task = await store.getTask(taskId); - expect(task?.status).toBe('input_required'); - }); - - it('should update task status to completed', async () => { - await store.updateTaskStatus(taskId, 'completed'); - - const task = await store.getTask(taskId); - expect(task?.status).toBe('completed'); - }); - - it('should update task status to failed with error', async () => { - await store.updateTaskStatus(taskId, 'failed', 'Something went wrong'); - - const task = await store.getTask(taskId); - expect(task?.status).toBe('failed'); - expect(task?.statusMessage).toBe('Something went wrong'); - }); - - it('should update task status to cancelled', async () => { - await store.updateTaskStatus(taskId, 'cancelled'); - - const task = await store.getTask(taskId); - expect(task?.status).toBe('cancelled'); - }); - - it('should throw if task not found', async () => { - await expect(store.updateTaskStatus('non-existent', 'working')).rejects.toThrow('Task with ID non-existent not found'); - }); - - describe('status lifecycle validation', () => { - it('should allow transition from working to input_required', async () => { - await store.updateTaskStatus(taskId, 'input_required'); - const task = await store.getTask(taskId); - expect(task?.status).toBe('input_required'); - }); - - it('should allow transition from working to completed', async () => { - await store.updateTaskStatus(taskId, 'completed'); - const task = await store.getTask(taskId); - expect(task?.status).toBe('completed'); - }); - - it('should allow transition from working to failed', async () => { - await store.updateTaskStatus(taskId, 'failed'); - const task = await store.getTask(taskId); - expect(task?.status).toBe('failed'); - }); - - it('should allow transition from working to cancelled', async () => { - await store.updateTaskStatus(taskId, 'cancelled'); - const task = await store.getTask(taskId); - expect(task?.status).toBe('cancelled'); - }); - - it('should allow transition from input_required to working', async () => { - await store.updateTaskStatus(taskId, 'input_required'); - await store.updateTaskStatus(taskId, 'working'); - const task = await store.getTask(taskId); - expect(task?.status).toBe('working'); - }); - - it('should allow transition from input_required to completed', async () => { - await store.updateTaskStatus(taskId, 'input_required'); - await store.updateTaskStatus(taskId, 'completed'); - const task = await store.getTask(taskId); - expect(task?.status).toBe('completed'); - }); - - it('should allow transition from input_required to failed', async () => { - await store.updateTaskStatus(taskId, 'input_required'); - await store.updateTaskStatus(taskId, 'failed'); - const task = await store.getTask(taskId); - expect(task?.status).toBe('failed'); - }); - - it('should allow transition from input_required to cancelled', async () => { - await store.updateTaskStatus(taskId, 'input_required'); - await store.updateTaskStatus(taskId, 'cancelled'); - const task = await store.getTask(taskId); - expect(task?.status).toBe('cancelled'); - }); - - it('should reject transition from completed to any other status', async () => { - await store.updateTaskStatus(taskId, 'completed'); - await expect(store.updateTaskStatus(taskId, 'working')).rejects.toThrow('Cannot update task'); - await expect(store.updateTaskStatus(taskId, 'input_required')).rejects.toThrow('Cannot update task'); - await expect(store.updateTaskStatus(taskId, 'failed')).rejects.toThrow('Cannot update task'); - await expect(store.updateTaskStatus(taskId, 'cancelled')).rejects.toThrow('Cannot update task'); - }); - - it('should reject transition from failed to any other status', async () => { - await store.updateTaskStatus(taskId, 'failed'); - await expect(store.updateTaskStatus(taskId, 'working')).rejects.toThrow('Cannot update task'); - await expect(store.updateTaskStatus(taskId, 'input_required')).rejects.toThrow('Cannot update task'); - await expect(store.updateTaskStatus(taskId, 'completed')).rejects.toThrow('Cannot update task'); - await expect(store.updateTaskStatus(taskId, 'cancelled')).rejects.toThrow('Cannot update task'); - }); - - it('should reject transition from cancelled to any other status', async () => { - await store.updateTaskStatus(taskId, 'cancelled'); - await expect(store.updateTaskStatus(taskId, 'working')).rejects.toThrow('Cannot update task'); - await expect(store.updateTaskStatus(taskId, 'input_required')).rejects.toThrow('Cannot update task'); - await expect(store.updateTaskStatus(taskId, 'completed')).rejects.toThrow('Cannot update task'); - await expect(store.updateTaskStatus(taskId, 'failed')).rejects.toThrow('Cannot update task'); - }); - }); - }); - - describe('storeTaskResult', () => { - let taskId: string; - - beforeEach(async () => { - const taskParams: TaskCreationParams = { - ttl: 60000 - }; - const createdTask = await store.createTask(taskParams, 333, { - method: 'tools/call', - params: {} - }); - taskId = createdTask.taskId; - }); - - it('should store task result and set status to completed', async () => { - const result = { - content: [{ type: 'text' as const, text: 'Success!' }] - }; - - await store.storeTaskResult(taskId, 'completed', result); - - const task = await store.getTask(taskId); - expect(task?.status).toBe('completed'); - - const storedResult = await store.getTaskResult(taskId); - expect(storedResult).toEqual(result); - }); - - it('should throw if task not found', async () => { - await expect(store.storeTaskResult('non-existent', 'completed', {})).rejects.toThrow('Task with ID non-existent not found'); - }); - - it('should reject storing result for task already in completed status', async () => { - // First complete the task - const firstResult = { - content: [{ type: 'text' as const, text: 'First result' }] - }; - await store.storeTaskResult(taskId, 'completed', firstResult); - - // Try to store result again (should fail) - const secondResult = { - content: [{ type: 'text' as const, text: 'Second result' }] - }; - - await expect(store.storeTaskResult(taskId, 'completed', secondResult)).rejects.toThrow('Cannot store result for task'); - }); - - it('should store result with failed status', async () => { - const result = { - content: [{ type: 'text' as const, text: 'Error details' }], - isError: true - }; - - await store.storeTaskResult(taskId, 'failed', result); - - const task = await store.getTask(taskId); - expect(task?.status).toBe('failed'); - - const storedResult = await store.getTaskResult(taskId); - expect(storedResult).toEqual(result); - }); - - it('should reject storing result for task already in failed status', async () => { - // First fail the task - const firstResult = { - content: [{ type: 'text' as const, text: 'First error' }], - isError: true - }; - await store.storeTaskResult(taskId, 'failed', firstResult); - - // Try to store result again (should fail) - const secondResult = { - content: [{ type: 'text' as const, text: 'Second error' }], - isError: true - }; - - await expect(store.storeTaskResult(taskId, 'failed', secondResult)).rejects.toThrow('Cannot store result for task'); - }); - - it('should reject storing result for cancelled task', async () => { - // Mark task as cancelled - await store.updateTaskStatus(taskId, 'cancelled'); - - // Try to store result (should fail) - const result = { - content: [{ type: 'text' as const, text: 'Cancellation result' }] - }; - - await expect(store.storeTaskResult(taskId, 'completed', result)).rejects.toThrow('Cannot store result for task'); - }); - - it('should allow storing result from input_required status', async () => { - await store.updateTaskStatus(taskId, 'input_required'); - - const result = { - content: [{ type: 'text' as const, text: 'Success!' }] - }; - - await store.storeTaskResult(taskId, 'completed', result); - - const task = await store.getTask(taskId); - expect(task?.status).toBe('completed'); - }); - }); - - describe('getTaskResult', () => { - it('should throw if task not found', async () => { - await expect(store.getTaskResult('non-existent')).rejects.toThrow('Task with ID non-existent not found'); - }); - - it('should throw if task has no result stored', async () => { - const taskParams: TaskCreationParams = {}; - const createdTask = await store.createTask(taskParams, 444, { - method: 'tools/call', - params: {} - }); - - await expect(store.getTaskResult(createdTask.taskId)).rejects.toThrow(`Task ${createdTask.taskId} has no result stored`); - }); - - it('should return stored result', async () => { - const taskParams: TaskCreationParams = {}; - const createdTask = await store.createTask(taskParams, 555, { - method: 'tools/call', - params: {} - }); - - const result = { - content: [{ type: 'text' as const, text: 'Result data' }] - }; - await store.storeTaskResult(createdTask.taskId, 'completed', result); - - const retrieved = await store.getTaskResult(createdTask.taskId); - expect(retrieved).toEqual(result); - }); - }); - - describe('ttl cleanup', () => { - beforeEach(() => { - vi.useFakeTimers(); - }); - - afterEach(() => { - vi.useRealTimers(); - }); - - it('should cleanup task after ttl duration', async () => { - const taskParams: TaskCreationParams = { - ttl: 1000 - }; - const createdTask = await store.createTask(taskParams, 666, { - method: 'tools/call', - params: {} - }); - - // Task should exist initially - let task = await store.getTask(createdTask.taskId); - expect(task).toBeDefined(); - - // Fast-forward past ttl - vi.advanceTimersByTime(1001); - - // Task should be cleaned up - task = await store.getTask(createdTask.taskId); - expect(task).toBeNull(); - }); - - it('should reset cleanup timer when result is stored', async () => { - const taskParams: TaskCreationParams = { - ttl: 1000 - }; - const createdTask = await store.createTask(taskParams, 777, { - method: 'tools/call', - params: {} - }); - - // Fast-forward 500ms - vi.advanceTimersByTime(500); - - // Store result (should reset timer) - await store.storeTaskResult(createdTask.taskId, 'completed', { - content: [{ type: 'text' as const, text: 'Done' }] - }); - - // Fast-forward another 500ms (total 1000ms since creation, but timer was reset) - vi.advanceTimersByTime(500); - - // Task should still exist - const task = await store.getTask(createdTask.taskId); - expect(task).toBeDefined(); - - // Fast-forward remaining time - vi.advanceTimersByTime(501); - - // Now task should be cleaned up - const cleanedTask = await store.getTask(createdTask.taskId); - expect(cleanedTask).toBeNull(); - }); - - it('should not cleanup tasks without ttl', async () => { - const taskParams: TaskCreationParams = {}; - const createdTask = await store.createTask(taskParams, 888, { - method: 'tools/call', - params: {} - }); - - // Fast-forward a long time - vi.advanceTimersByTime(100000); - - // Task should still exist - const task = await store.getTask(createdTask.taskId); - expect(task).toBeDefined(); - }); - - it('should start cleanup timer when task reaches terminal state', async () => { - const taskParams: TaskCreationParams = { - ttl: 1000 - }; - const createdTask = await store.createTask(taskParams, 999, { - method: 'tools/call', - params: {} - }); - - // Task in non-terminal state, fast-forward - vi.advanceTimersByTime(1001); - - // Task should be cleaned up - let task = await store.getTask(createdTask.taskId); - expect(task).toBeNull(); - - // Create another task - const taskParams2: TaskCreationParams = { - ttl: 2000 - }; - const createdTask2 = await store.createTask(taskParams2, 1000, { - method: 'tools/call', - params: {} - }); - - // Update to terminal state - await store.updateTaskStatus(createdTask2.taskId, 'completed'); - - // Fast-forward past original ttl - vi.advanceTimersByTime(2001); - - // Task should be cleaned up - task = await store.getTask(createdTask2.taskId); - expect(task).toBeNull(); - }); - - it('should return actual TTL in task response', async () => { - // Test that the TaskStore returns the actual TTL it will use - // This implementation uses the requested TTL as-is, but implementations - // MAY override it (e.g., enforce maximum TTL limits) - const requestedTtl = 5000; - const taskParams: TaskCreationParams = { - ttl: requestedTtl - }; - const createdTask = await store.createTask(taskParams, 1111, { - method: 'tools/call', - params: {} - }); - - // The returned task should include the actual TTL that will be used - expect(createdTask.ttl).toBe(requestedTtl); - - // Verify the task is cleaned up after the actual TTL - vi.advanceTimersByTime(requestedTtl + 1); - const task = await store.getTask(createdTask.taskId); - expect(task).toBeNull(); - }); - - it('should support null TTL for unlimited lifetime', async () => { - // Test that null TTL means unlimited lifetime - const taskParams: TaskCreationParams = { - ttl: null - }; - const createdTask = await store.createTask(taskParams, 2222, { - method: 'tools/call', - params: {} - }); - - // The returned task should have null TTL - expect(createdTask.ttl).toBeNull(); - - // Task should not be cleaned up even after a long time - vi.advanceTimersByTime(100000); - const task = await store.getTask(createdTask.taskId); - expect(task).toBeDefined(); - expect(task?.taskId).toBe(createdTask.taskId); - }); - - it('should cleanup tasks regardless of status', async () => { - // Test that TTL cleanup happens regardless of task status - const taskParams: TaskCreationParams = { - ttl: 1000 - }; - - // Create tasks in different statuses - const workingTask = await store.createTask(taskParams, 3333, { - method: 'tools/call', - params: {} - }); - - const completedTask = await store.createTask(taskParams, 4444, { - method: 'tools/call', - params: {} - }); - await store.storeTaskResult(completedTask.taskId, 'completed', { - content: [{ type: 'text' as const, text: 'Done' }] - }); - - const failedTask = await store.createTask(taskParams, 5555, { - method: 'tools/call', - params: {} - }); - await store.storeTaskResult(failedTask.taskId, 'failed', { - content: [{ type: 'text' as const, text: 'Error' }] - }); - - // Fast-forward past TTL - vi.advanceTimersByTime(1001); - - // All tasks should be cleaned up regardless of status - expect(await store.getTask(workingTask.taskId)).toBeNull(); - expect(await store.getTask(completedTask.taskId)).toBeNull(); - expect(await store.getTask(failedTask.taskId)).toBeNull(); - }); - }); - - describe('getAllTasks', () => { - it('should return all tasks', async () => { - await store.createTask({}, 1, { - method: 'tools/call', - params: {} - }); - await store.createTask({}, 2, { - method: 'tools/call', - params: {} - }); - await store.createTask({}, 3, { - method: 'tools/call', - params: {} - }); - - const tasks = store.getAllTasks(); - expect(tasks).toHaveLength(3); - // Verify all tasks have unique IDs - const taskIds = tasks.map(t => t.taskId); - expect(new Set(taskIds).size).toBe(3); - }); - - it('should return empty array when no tasks', () => { - const tasks = store.getAllTasks(); - expect(tasks).toEqual([]); - }); - }); - - describe('listTasks', () => { - it('should return empty list when no tasks', async () => { - const result = await store.listTasks(); - expect(result.tasks).toEqual([]); - expect(result.nextCursor).toBeUndefined(); - }); - - it('should return all tasks when less than page size', async () => { - await store.createTask({}, 1, { - method: 'tools/call', - params: {} - }); - await store.createTask({}, 2, { - method: 'tools/call', - params: {} - }); - await store.createTask({}, 3, { - method: 'tools/call', - params: {} - }); - - const result = await store.listTasks(); - expect(result.tasks).toHaveLength(3); - expect(result.nextCursor).toBeUndefined(); - }); - - it('should paginate when more than page size', async () => { - // Create 15 tasks (page size is 10) - for (let i = 1; i <= 15; i++) { - await store.createTask({}, i, { - method: 'tools/call', - params: {} - }); - } - - // Get first page - const page1 = await store.listTasks(); - expect(page1.tasks).toHaveLength(10); - expect(page1.nextCursor).toBeDefined(); - - // Get second page using cursor - const page2 = await store.listTasks(page1.nextCursor); - expect(page2.tasks).toHaveLength(5); - expect(page2.nextCursor).toBeUndefined(); - }); - - it('should throw error for invalid cursor', async () => { - await store.createTask({}, 1, { - method: 'tools/call', - params: {} - }); - - await expect(store.listTasks('non-existent-cursor')).rejects.toThrow('Invalid cursor: non-existent-cursor'); - }); - - it('should continue from cursor correctly', async () => { - // Create 5 tasks - for (let i = 1; i <= 5; i++) { - await store.createTask({}, i, { - method: 'tools/call', - params: {} - }); - } - - // Get first 3 tasks - const allTaskIds = Array.from(store.getAllTasks().map(t => t.taskId)); - const result = await store.listTasks(allTaskIds[2]); - - // Should get tasks after the third task - expect(result.tasks).toHaveLength(2); - }); - }); - - describe('cleanup', () => { - it('should clear all timers and tasks', async () => { - await store.createTask({ ttl: 1000 }, 1, { - method: 'tools/call', - params: {} - }); - await store.createTask({ ttl: 2000 }, 2, { - method: 'tools/call', - params: {} - }); - - expect(store.getAllTasks()).toHaveLength(2); - - store.cleanup(); - - expect(store.getAllTasks()).toHaveLength(0); - }); - }); -}); - -describe('InMemoryTaskMessageQueue', () => { - let queue: InMemoryTaskMessageQueue; - - beforeEach(() => { - queue = new InMemoryTaskMessageQueue(); - }); - - describe('enqueue and dequeue', () => { - it('should enqueue and dequeue request messages', async () => { - const requestMessage: QueuedMessage = { - type: 'request', - message: { - jsonrpc: '2.0', - id: 1, - method: 'tools/call', - params: { name: 'test-tool', arguments: {} } - }, - timestamp: Date.now() - }; - - await queue.enqueue('task-1', requestMessage); - const dequeued = await queue.dequeue('task-1'); - - expect(dequeued).toEqual(requestMessage); - }); - - it('should enqueue and dequeue notification messages', async () => { - const notificationMessage: QueuedMessage = { - type: 'notification', - message: { - jsonrpc: '2.0', - method: 'notifications/progress', - params: { progress: 50, total: 100 } - }, - timestamp: Date.now() - }; - - await queue.enqueue('task-2', notificationMessage); - const dequeued = await queue.dequeue('task-2'); - - expect(dequeued).toEqual(notificationMessage); - }); - - it('should enqueue and dequeue response messages', async () => { - const responseMessage: QueuedMessage = { - type: 'response', - message: { - jsonrpc: '2.0', - id: 42, - result: { content: [{ type: 'text', text: 'Success' }] } - }, - timestamp: Date.now() - }; - - await queue.enqueue('task-3', responseMessage); - const dequeued = await queue.dequeue('task-3'); - - expect(dequeued).toEqual(responseMessage); - }); - - it('should return undefined when dequeuing from empty queue', async () => { - const dequeued = await queue.dequeue('task-empty'); - expect(dequeued).toBeUndefined(); - }); - - it('should maintain FIFO order for mixed message types', async () => { - const request: QueuedMessage = { - type: 'request', - message: { - jsonrpc: '2.0', - id: 1, - method: 'tools/call', - params: {} - }, - timestamp: 1000 - }; - - const notification: QueuedMessage = { - type: 'notification', - message: { - jsonrpc: '2.0', - method: 'notifications/progress', - params: {} - }, - timestamp: 2000 - }; - - const response: QueuedMessage = { - type: 'response', - message: { - jsonrpc: '2.0', - id: 1, - result: {} - }, - timestamp: 3000 - }; - - await queue.enqueue('task-fifo', request); - await queue.enqueue('task-fifo', notification); - await queue.enqueue('task-fifo', response); - - expect(await queue.dequeue('task-fifo')).toEqual(request); - expect(await queue.dequeue('task-fifo')).toEqual(notification); - expect(await queue.dequeue('task-fifo')).toEqual(response); - expect(await queue.dequeue('task-fifo')).toBeUndefined(); - }); - }); - - describe('dequeueAll', () => { - it('should dequeue all messages including responses', async () => { - const request: QueuedMessage = { - type: 'request', - message: { - jsonrpc: '2.0', - id: 1, - method: 'tools/call', - params: {} - }, - timestamp: 1000 - }; - - const response: QueuedMessage = { - type: 'response', - message: { - jsonrpc: '2.0', - id: 1, - result: {} - }, - timestamp: 2000 - }; - - const notification: QueuedMessage = { - type: 'notification', - message: { - jsonrpc: '2.0', - method: 'notifications/progress', - params: {} - }, - timestamp: 3000 - }; - - await queue.enqueue('task-all', request); - await queue.enqueue('task-all', response); - await queue.enqueue('task-all', notification); - - const all = await queue.dequeueAll('task-all'); - - expect(all).toHaveLength(3); - expect(all[0]).toEqual(request); - expect(all[1]).toEqual(response); - expect(all[2]).toEqual(notification); - }); - - it('should return empty array for non-existent task', async () => { - const all = await queue.dequeueAll('non-existent'); - expect(all).toEqual([]); - }); - - it('should clear the queue after dequeueAll', async () => { - const message: QueuedMessage = { - type: 'request', - message: { - jsonrpc: '2.0', - id: 1, - method: 'test', - params: {} - }, - timestamp: Date.now() - }; - - await queue.enqueue('task-clear', message); - await queue.dequeueAll('task-clear'); - - const dequeued = await queue.dequeue('task-clear'); - expect(dequeued).toBeUndefined(); - }); - }); - - describe('queue size limits', () => { - it('should throw when maxSize is exceeded', async () => { - const message: QueuedMessage = { - type: 'request', - message: { - jsonrpc: '2.0', - id: 1, - method: 'test', - params: {} - }, - timestamp: Date.now() - }; - - await queue.enqueue('task-limit', message, undefined, 2); - await queue.enqueue('task-limit', message, undefined, 2); - - await expect(queue.enqueue('task-limit', message, undefined, 2)).rejects.toThrow('Task message queue overflow'); - }); - - it('should allow enqueue when under maxSize', async () => { - const message: QueuedMessage = { - type: 'response', - message: { - jsonrpc: '2.0', - id: 1, - result: {} - }, - timestamp: Date.now() - }; - - await expect(queue.enqueue('task-ok', message, undefined, 5)).resolves.toBeUndefined(); - }); - }); - - describe('task isolation', () => { - it('should isolate messages between different tasks', async () => { - const message1: QueuedMessage = { - type: 'request', - message: { - jsonrpc: '2.0', - id: 1, - method: 'test1', - params: {} - }, - timestamp: 1000 - }; - - const message2: QueuedMessage = { - type: 'response', - message: { - jsonrpc: '2.0', - id: 2, - result: {} - }, - timestamp: 2000 - }; - - await queue.enqueue('task-a', message1); - await queue.enqueue('task-b', message2); - - expect(await queue.dequeue('task-a')).toEqual(message1); - expect(await queue.dequeue('task-b')).toEqual(message2); - expect(await queue.dequeue('task-a')).toBeUndefined(); - expect(await queue.dequeue('task-b')).toBeUndefined(); - }); - }); - - describe('response message error handling', () => { - it('should handle response messages with errors', async () => { - const errorResponse: QueuedMessage = { - type: 'error', - message: { - jsonrpc: '2.0', - id: 1, - error: { - code: -32600, - message: 'Invalid Request' - } - }, - timestamp: Date.now() - }; - - await queue.enqueue('task-error', errorResponse); - const dequeued = await queue.dequeue('task-error'); - - expect(dequeued).toEqual(errorResponse); - expect(dequeued?.type).toBe('error'); - }); - }); -}); diff --git a/tsconfig.cjs.json b/tsconfig.cjs.json deleted file mode 100644 index 4b712da77..000000000 --- a/tsconfig.cjs.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "module": "commonjs", - "moduleResolution": "node", - "outDir": "./dist/cjs" - }, - "include": ["src/**/*"], - "exclude": ["**/*.test.ts", "src/__mocks__/**/*", "src/__fixtures__/**/*"] -} diff --git a/vitest.config.ts b/vitest.config.ts deleted file mode 100644 index f283689f1..000000000 --- a/vitest.config.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { defineConfig } from 'vitest/config'; - -export default defineConfig({ - test: { - globals: true, - environment: 'node', - setupFiles: ['./vitest.setup.ts'], - include: ['test/**/*.test.ts'] - } -}); diff --git a/vitest.workspace.js b/vitest.workspace.js new file mode 100644 index 000000000..b09f1f1fd --- /dev/null +++ b/vitest.workspace.js @@ -0,0 +1,3 @@ +import { defineWorkspace } from 'vitest/config'; + +export default defineWorkspace(['packages/**/vitest.config.js']);