├── .gitignore ├── tsup.config.ts ├── tsconfig.json ├── .changeset └── config.json ├── src ├── auth │ ├── auth-context.ts │ ├── auth-metadata.ts │ └── auth-wrapper.ts ├── index.ts ├── handler │ ├── index.ts │ ├── server-response-adapter.ts │ └── mcp-api-handler.ts ├── lib │ ├── log-helper.ts │ └── event-emitter.ts └── cli │ └── index.ts ├── examples ├── route.ts └── auth │ └── route.ts ├── .github └── workflows │ ├── release.yml │ └── release-snapshot.yml ├── tests ├── auth.test.ts ├── mcp.test.ts └── e2e.test.ts ├── package.json ├── CHANGELOG.md ├── README.md └── pnpm-lock.yaml /.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules 3 | -------------------------------------------------------------------------------- /tsup.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'tsup'; 2 | 3 | export default defineConfig({ 4 | entry: ['src/index.ts', 'src/next/index.ts', 'src/cli/index.ts'], 5 | format: ['esm', 'cjs'], 6 | dts: true, 7 | splitting: true, 8 | sourcemap: true, 9 | clean: true, 10 | treeshake: true, 11 | }); 12 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2016", 4 | "module": "commonjs", 5 | "declaration": true, 6 | "outDir": "./dist", 7 | "esModuleInterop": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "strict": true, 10 | "skipLibCheck": true 11 | }, 12 | "include": ["src/**/*"], 13 | "exclude": ["node_modules", "**/*.test.ts"] 14 | } 15 | -------------------------------------------------------------------------------- /.changeset/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/@changesets/config@2.3.1/schema.json", 3 | "changelog": "@changesets/cli/changelog", 4 | "commit": false, 5 | "fixed": [], 6 | "linked": [], 7 | "access": "public", 8 | "baseBranch": "main", 9 | "updateInternalDependencies": "patch", 10 | "ignore": [], 11 | "privatePackages": { 12 | "tag": false, 13 | "version": false 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/auth/auth-context.ts: -------------------------------------------------------------------------------- 1 | import { AuthInfo } from "@modelcontextprotocol/sdk/server/auth/types.js"; 2 | import { AsyncLocalStorage } from "node:async_hooks"; 3 | 4 | const authContext = new AsyncLocalStorage(); 5 | 6 | export function getAuthContext(): AuthInfo | undefined { 7 | return authContext.getStore(); 8 | } 9 | 10 | export function withAuthContext(authInfo: AuthInfo, callback: () => T): T { 11 | return authContext.run(authInfo, callback); 12 | } 13 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | // Re-export the Next.js adapter 2 | export { default as createMcpHandler } from "./handler"; 3 | 4 | /** 5 | * @deprecated Use withMcpAuth instead 6 | */ 7 | export { withMcpAuth as experimental_withMcpAuth } from "./auth/auth-wrapper"; 8 | 9 | export { withMcpAuth } from "./auth/auth-wrapper"; 10 | 11 | export { 12 | protectedResourceHandler, 13 | generateProtectedResourceMetadata, 14 | metadataCorsOptionsRequestHandler, 15 | } from "./auth/auth-metadata"; 16 | -------------------------------------------------------------------------------- /examples/route.ts: -------------------------------------------------------------------------------- 1 | import createMcpRouteHandler from '../dist/next/index'; 2 | 3 | const handler = createMcpRouteHandler( 4 | server => { 5 | server.tool('echo', 'Echo a message', {}, async () => { 6 | return { 7 | content: [ 8 | { 9 | type: 'text', 10 | text: 'Hello, world!', 11 | }, 12 | ], 13 | }; 14 | }); 15 | }, 16 | // Optional: Comes from the McpServer.options 17 | { 18 | capabilities: {}, 19 | }, 20 | // Optional: Comes from the createMcpRouteHandler config 21 | { 22 | streamableHttpEndpoint: '/mcp', 23 | sseEndpoint: '/sse', 24 | sseMessageEndpoint: '/message', 25 | basePath: '/api/mcp', 26 | redisUrl: process.env.REDIS_URL, 27 | } 28 | ); 29 | 30 | export { handler as GET, handler as POST }; 31 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | workflow_dispatch: 8 | 9 | concurrency: 10 | group: ${{ github.workflow }}-${{ github.ref }} 11 | 12 | env: 13 | TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} 14 | TURBO_TEAM: ${{ secrets.TURBO_TEAM }} 15 | 16 | jobs: 17 | release: 18 | name: Release 19 | runs-on: ubuntu-latest 20 | permissions: 21 | contents: write 22 | pull-requests: write 23 | id-token: write 24 | steps: 25 | - name: Checkout 26 | uses: actions/checkout@v4 27 | with: 28 | token: ${{ secrets.GH_TOKEN_PULL_REQUESTS }} 29 | 30 | - uses: pnpm/action-setup@v4 31 | name: Install pnpm 32 | id: pnpm-setup 33 | with: 34 | version: 9.4.0 35 | run_install: false 36 | 37 | - name: Install Dependencies 38 | id: pnpm-install 39 | run: pnpm install --frozen-lockfile 40 | 41 | - name: Create Release PR or Publish Packages 42 | uses: changesets/action@v1 43 | with: 44 | publish: pnpm release 45 | version: pnpm version-packages 46 | commit: "chore: update package versions" 47 | title: "chore: update package versions" 48 | env: 49 | GITHUB_TOKEN: ${{ secrets.GH_TOKEN_PULL_REQUESTS }} 50 | NPM_TOKEN: ${{ secrets.NPM_TOKEN_ELEVATED }} 51 | -------------------------------------------------------------------------------- /src/handler/index.ts: -------------------------------------------------------------------------------- 1 | import { type Config, initializeMcpApiHandler } from "./mcp-api-handler"; 2 | import { createServerResponseAdapter } from "./server-response-adapter"; 3 | import type { ServerOptions as McpServerOptions } from "@modelcontextprotocol/sdk/server/index.js"; 4 | import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; 5 | 6 | /** 7 | * Creates a MCP handler that can be used to handle MCP requests. 8 | * @param initializeServer - A function that initializes the MCP server. Use this to access the server instance and register tools, prompts, and resources. 9 | * @param serverOptions - Options for the MCP server. 10 | * @param config - Configuration for the MCP handler. 11 | * @returns A function that can be used to handle MCP requests. 12 | */ 13 | 14 | export type ServerOptions = McpServerOptions & { 15 | serverInfo?: { 16 | name: string; 17 | version: string; 18 | }; 19 | }; 20 | 21 | export default function createMcpRouteHandler( 22 | initializeServer: 23 | | ((server: McpServer) => Promise) 24 | | ((server: McpServer) => void), 25 | serverOptions?: ServerOptions, 26 | config?: Config 27 | ): (request: Request) => Promise { 28 | const mcpHandler = initializeMcpApiHandler( 29 | initializeServer, 30 | serverOptions, 31 | config 32 | ); 33 | return (request: Request) => { 34 | return createServerResponseAdapter(request.signal, (res) => { 35 | mcpHandler(request, res); 36 | }); 37 | }; 38 | } 39 | -------------------------------------------------------------------------------- /src/lib/log-helper.ts: -------------------------------------------------------------------------------- 1 | export type McpEventType = 2 | | "SESSION_STARTED" // When a new client session begins (either HTTP or SSE) 3 | | "SESSION_ENDED" // When a client session ends (SSE disconnection) 4 | | "REQUEST_RECEIVED" // When a request is received from the client 5 | | "REQUEST_COMPLETED" // When a request completes 6 | | "ERROR"; // When an error occurs during any operation 7 | 8 | export interface McpEventBase { 9 | type: McpEventType; 10 | timestamp: number; 11 | sessionId?: string; 12 | requestId?: string; // To track individual requests within a session 13 | } 14 | 15 | export interface McpSessionEvent extends McpEventBase { 16 | type: "SESSION_STARTED" | "SESSION_ENDED"; 17 | transport: "SSE" | "HTTP"; 18 | clientInfo?: { 19 | userAgent?: string; 20 | ip?: string; 21 | }; 22 | } 23 | 24 | export interface McpRequestEvent extends McpEventBase { 25 | type: "REQUEST_RECEIVED" | "REQUEST_COMPLETED"; 26 | method: string; 27 | parameters?: unknown; 28 | result?: unknown; 29 | duration?: number; // For REQUEST_COMPLETED events 30 | status: "success" | "error"; 31 | } 32 | 33 | export interface McpErrorEvent extends McpEventBase { 34 | type: "ERROR"; 35 | error: Error | string; 36 | context?: string; 37 | source: "request" | "session" | "system"; 38 | severity: "warning" | "error" | "fatal"; 39 | } 40 | 41 | export type McpEvent = McpSessionEvent | McpRequestEvent | McpErrorEvent; 42 | 43 | export function createEvent( 44 | event: Omit 45 | ): T { 46 | return { 47 | ...event, 48 | timestamp: Date.now(), 49 | } as T; 50 | } 51 | -------------------------------------------------------------------------------- /.github/workflows/release-snapshot.yml: -------------------------------------------------------------------------------- 1 | name: Release Snapshot 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | concurrency: 7 | group: ${{ github.workflow }}-${{ github.ref }} 8 | 9 | env: 10 | TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} 11 | TURBO_TEAM: ${{ secrets.TURBO_TEAM }} 12 | 13 | jobs: 14 | release-snapshot: 15 | name: Release Snapshot 16 | runs-on: ubuntu-latest 17 | permissions: 18 | contents: write 19 | pull-requests: write 20 | id-token: write 21 | steps: 22 | - name: Checkout 23 | uses: actions/checkout@v4 24 | with: 25 | token: ${{ secrets.GH_TOKEN_PULL_REQUESTS }} 26 | 27 | - uses: pnpm/action-setup@v4 28 | name: Install pnpm 29 | id: pnpm-setup 30 | with: 31 | version: 9.4.0 32 | run_install: false 33 | 34 | - name: Add npm auth token to pnpm 35 | run: pnpm config set '//registry.npmjs.org/:_authToken' "${NPM_TOKEN_ELEVATED}" 36 | env: 37 | NPM_TOKEN_ELEVATED: ${{secrets.NPM_TOKEN_ELEVATED}} 38 | - name: Install Dependencies 39 | id: pnpm-install 40 | run: pnpm install --frozen-lockfile 41 | 42 | - name: Add SHORT_SHA env property with commit short sha 43 | run: echo "SHORT_SHA=`echo ${{ github.sha }} | cut -c1-8`" >> $GITHUB_ENV 44 | 45 | - name: Create Snapshot Release 46 | run: | 47 | pnpm changeset version --snapshot ${SHORT_SHA} 48 | pnpm build 49 | pnpm changeset publish --no-git-tag --tag snapshot 50 | env: 51 | GITHUB_TOKEN: ${{ secrets.GH_TOKEN_PULL_REQUESTS }} 52 | NPM_TOKEN: ${{ secrets.NPM_TOKEN_ELEVATED }} 53 | -------------------------------------------------------------------------------- /tests/auth.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, it, expect } from "vitest"; 2 | import { protectedResourceHandler } from "../src/index"; 3 | 4 | describe("auth", () => { 5 | describe("resource metadata URL to resource identifier mapping", () => { 6 | const handler = protectedResourceHandler({ 7 | authServerUrls: ["https://auth-server.com"], 8 | }); 9 | 10 | const testCases = [ 11 | // Default well-known URI suffix (oauth-protected-resource) 12 | { 13 | resourceMetadata: 'https://resource-server.com/.well-known/oauth-protected-resource', 14 | resource: 'https://resource-server.com', 15 | }, 16 | { 17 | resourceMetadata: 'https://resource-server.com/.well-known/oauth-protected-resource/my-resource', 18 | resource: 'https://resource-server.com/my-resource', 19 | }, 20 | { 21 | resourceMetadata: 'https://resource-server.com/.well-known/oauth-protected-resource/foo/bar', 22 | resource: 'https://resource-server.com/foo/bar', 23 | }, 24 | // Ensure ports work 25 | { 26 | resourceMetadata: 'https://resource-server.com:8443/.well-known/oauth-protected-resource', 27 | resource: 'https://resource-server.com:8443', 28 | }, 29 | // Example well-known URI suffix from RFC 9728 (example-protected-resource) 30 | { 31 | resourceMetadata: 'https://resource-server.com/.well-known/example-protected-resource', 32 | resource: 'https://resource-server.com', 33 | }, 34 | { 35 | resourceMetadata: 'https://resource-server.com/.well-known/example-protected-resource/my-resource', 36 | resource: 'https://resource-server.com/my-resource', 37 | }, 38 | ] as const; 39 | 40 | testCases.forEach(testCase => { 41 | it(`${testCase.resourceMetadata} → ${testCase.resource}`, async () => { 42 | const req = new Request(testCase.resourceMetadata); 43 | const res = handler(req); 44 | const json = await res.json(); 45 | expect(json.resource).toBe(testCase.resource); 46 | }); 47 | }); 48 | }); 49 | }); 50 | 51 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mcp-handler", 3 | "version": "1.0.4", 4 | "description": "Vercel MCP Adapter for Next.js and other frameworks", 5 | "main": "dist/index.js", 6 | "types": "dist/index.d.ts", 7 | "type": "commonjs", 8 | "bin": { 9 | "create-mcp-route": "./dist/cli/index.js", 10 | "mcp-handler": "./dist/cli/index.js", 11 | "@vercel/mcp-adapter": "./dist/cli/index.js" 12 | }, 13 | "exports": { 14 | ".": { 15 | "types": { 16 | "import": "./dist/index.d.mts", 17 | "require": "./dist/index.d.cjs" 18 | }, 19 | "import": "./dist/index.mjs", 20 | "require": "./dist/index.js" 21 | }, 22 | "./next": { 23 | "types": { 24 | "import": "./dist/index.d.mts", 25 | "require": "./dist/index.d.cjs" 26 | }, 27 | "import": "./dist/index.mjs", 28 | "require": "./dist/index.js" 29 | } 30 | }, 31 | "files": [ 32 | "dist" 33 | ], 34 | "repository": { 35 | "type": "git", 36 | "url": "git+https://github.com/vercel/mcp-handler.git" 37 | }, 38 | "bugs": { 39 | "url": "https://github.com/vercel/mcp-handler/issues" 40 | }, 41 | "scripts": { 42 | "build": "tsup", 43 | "dev": "tsup --watch", 44 | "test": "vitest run", 45 | "test:watch": "vitest watch", 46 | "version-packages": "changeset version", 47 | "changeset": "changeset", 48 | "release": "pnpm build && changeset publish" 49 | }, 50 | "keywords": [ 51 | "mcp", 52 | "vercel", 53 | "next.js", 54 | "ai" 55 | ], 56 | "author": "Vercel", 57 | "license": "Apache-2.0", 58 | "dependencies": { 59 | "chalk": "^5.3.0", 60 | "commander": "^11.1.0", 61 | "redis": "^4.6.0" 62 | }, 63 | "devDependencies": { 64 | "@changesets/cli": "^2.27.12", 65 | "@types/node": "^22.15.8", 66 | "tsup": "^8.0.0", 67 | "typescript": "^5.0.0", 68 | "vitest": "^3.2.1", 69 | "zod": "^3.25.50" 70 | }, 71 | "peerDependencies": { 72 | "@modelcontextprotocol/sdk": "^1.22.0", 73 | "next": ">=13.0.0" 74 | }, 75 | "peerDependenciesMeta": { 76 | "@modelcontextprotocol/sdk": { 77 | "optional": false 78 | }, 79 | "next": { 80 | "optional": true 81 | } 82 | }, 83 | "packageManager": "pnpm@9.4.0", 84 | "publishConfig": { 85 | "access": "public", 86 | "provenance": true 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /examples/auth/route.ts: -------------------------------------------------------------------------------- 1 | import { AuthInfo } from "@modelcontextprotocol/sdk/server/auth/types"; 2 | import { 3 | createMcpHandler, 4 | withMcpAuth, 5 | } from "mcp-handler"; 6 | import { z } from "zod"; 7 | 8 | // Define the handler with proper parameter validation 9 | const handler = createMcpHandler( 10 | (server) => { 11 | server.tool( 12 | "echo", 13 | "Echo a message back with authentication info", 14 | { 15 | message: z.string().describe("The message to echo back"), 16 | }, 17 | async ({ message }, extra) => { 18 | return { 19 | content: [ 20 | { 21 | type: "text", 22 | text: `Echo: ${message}${ 23 | extra.authInfo?.token 24 | ? ` (from ${extra.authInfo.clientId})` 25 | : "" 26 | }`, 27 | }, 28 | ], 29 | }; 30 | } 31 | ); 32 | }, 33 | // Server capabilities 34 | { 35 | capabilities: { 36 | auth: { 37 | type: "bearer", 38 | required: true, 39 | }, 40 | }, 41 | }, 42 | // Route configuration 43 | { 44 | streamableHttpEndpoint: "/mcp", 45 | sseEndpoint: "/sse", 46 | sseMessageEndpoint: "/message", 47 | basePath: "/api/mcp", 48 | redisUrl: process.env.REDIS_URL, 49 | } 50 | ); 51 | 52 | /** 53 | * Verify the bearer token and return auth information 54 | * In a real implementation, this would validate against your auth service 55 | */ 56 | const verifyToken = async ( 57 | req: Request, 58 | bearerToken?: string 59 | ): Promise => { 60 | if (!bearerToken) return undefined; 61 | 62 | // TODO: Replace with actual token verification logic 63 | // This is just an example implementation 64 | const isValid = bearerToken.startsWith("__TEST_VALUE__"); 65 | 66 | if (!isValid) return undefined; 67 | 68 | return { 69 | token: bearerToken, 70 | scopes: ["read:messages", "write:messages"], 71 | clientId: "example-client", 72 | extra: { 73 | userId: "user-123", 74 | // Add any additional user/client information here 75 | permissions: ["user"], 76 | timestamp: new Date().toISOString(), 77 | }, 78 | }; 79 | }; 80 | 81 | // Create the auth handler with required scopes 82 | const authHandler = withMcpAuth(handler, verifyToken, { 83 | required: true, 84 | requiredScopes: ["read:messages"], 85 | resourceMetadataPath: "/.well-known/oauth-protected-resource", 86 | }); 87 | 88 | // Export the handler for both GET and POST methods 89 | export { authHandler as GET, authHandler as POST }; 90 | -------------------------------------------------------------------------------- /tests/mcp.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, it, expect } from 'vitest'; 2 | import { calculateEndpoints } from '../src/handler/mcp-api-handler'; 3 | 4 | describe('calculateEndpoints', () => { 5 | it('derives all endpoints from basePath', () => { 6 | const result = calculateEndpoints({ basePath: '/api/foo' }); 7 | expect(result).toEqual({ 8 | streamableHttpEndpoint: '/api/foo/mcp', 9 | sseEndpoint: '/api/foo/sse', 10 | sseMessageEndpoint: '/api/foo/message', 11 | }); 12 | }); 13 | 14 | it('derives endpoints from basePath with trailing slash', () => { 15 | const result = calculateEndpoints({ basePath: '/api/bar/' }); 16 | expect(result).toEqual({ 17 | streamableHttpEndpoint: '/api/bar/mcp', 18 | sseEndpoint: '/api/bar/sse', 19 | sseMessageEndpoint: '/api/bar/message', 20 | }); 21 | }); 22 | 23 | it('uses explicit endpoints if basePath is not provided', () => { 24 | const result = calculateEndpoints({ 25 | streamableHttpEndpoint: '/explicit/mcp', 26 | sseEndpoint: '/explicit/sse', 27 | sseMessageEndpoint: '/explicit/message', 28 | }); 29 | expect(result).toEqual({ 30 | streamableHttpEndpoint: '/explicit/mcp', 31 | sseEndpoint: '/explicit/sse', 32 | sseMessageEndpoint: '/explicit/message', 33 | }); 34 | }); 35 | 36 | it('prefers basePath over explicit endpoints', () => { 37 | const result = calculateEndpoints({ 38 | basePath: '/api/baz', 39 | streamableHttpEndpoint: '/should/not/use/mcp', 40 | sseEndpoint: '/should/not/use/sse', 41 | sseMessageEndpoint: '/should/not/use/message', 42 | }); 43 | expect(result).toEqual({ 44 | streamableHttpEndpoint: '/api/baz/mcp', 45 | sseEndpoint: '/api/baz/sse', 46 | sseMessageEndpoint: '/api/baz/message', 47 | }); 48 | }); 49 | 50 | it('handles missing values gracefully', () => { 51 | const result = calculateEndpoints({}); 52 | expect(result).toEqual({ 53 | streamableHttpEndpoint: '/mcp', 54 | sseEndpoint: '/sse', 55 | sseMessageEndpoint: '/message', 56 | }); 57 | }); 58 | 59 | it('handles empty basePath', () => { 60 | const result = calculateEndpoints({ basePath: '' }); 61 | expect(result).toEqual({ 62 | streamableHttpEndpoint: '/mcp', 63 | sseEndpoint: '/sse', 64 | sseMessageEndpoint: '/message', 65 | }); 66 | }); 67 | 68 | it('handles basePath as just "/"', () => { 69 | const result = calculateEndpoints({ basePath: '/' }); 70 | expect(result).toEqual({ 71 | streamableHttpEndpoint: '/mcp', 72 | sseEndpoint: '/sse', 73 | sseMessageEndpoint: '/message', 74 | }); 75 | }); 76 | 77 | it('falls back to explicit endpoints when basePath is undefined', () => { 78 | const result = calculateEndpoints({ 79 | basePath: undefined, 80 | streamableHttpEndpoint: '/explicit/mcp', 81 | sseEndpoint: '/explicit/sse', 82 | sseMessageEndpoint: '/explicit/message', 83 | }); 84 | expect(result).toEqual({ 85 | streamableHttpEndpoint: '/explicit/mcp', 86 | sseEndpoint: '/explicit/sse', 87 | sseMessageEndpoint: '/explicit/message', 88 | }); 89 | }); 90 | }); 91 | -------------------------------------------------------------------------------- /src/auth/auth-metadata.ts: -------------------------------------------------------------------------------- 1 | import { OAuthProtectedResourceMetadata } from "@modelcontextprotocol/sdk/shared/auth.js"; 2 | 3 | /** 4 | * CORS headers for OAuth Protected Resource Metadata endpoint. 5 | * Configured to allow any origin to make the endpoint accessible to web-based MCP clients. 6 | */ 7 | const corsHeaders = { 8 | "Access-Control-Allow-Origin": "*", 9 | "Access-Control-Allow-Methods": "GET, OPTIONS", 10 | "Access-Control-Allow-Headers": "*", 11 | "Access-Control-Max-Age": "86400", 12 | }; 13 | 14 | /** 15 | * OAuth 2.0 Protected Resource Metadata endpoint based on RFC 9728. 16 | * @see https://datatracker.ietf.org/doc/html/rfc9728 17 | * 18 | * @param authServerUrls - Array of issuer URLs of the OAuth 2.0 Authorization Servers. 19 | * These should match the "issuer" field in the authorization servers' 20 | * OAuth metadata (RFC 8414). 21 | */ 22 | export function protectedResourceHandler({ 23 | authServerUrls, 24 | }: { 25 | authServerUrls: string[]; 26 | }) { 27 | return (req: Request) => { 28 | const resourceUrl = new URL(req.url); 29 | 30 | resourceUrl.pathname = resourceUrl.pathname 31 | .replace(/^\/\.well-known\/[^\/]+/, ""); 32 | 33 | // The URL class does not allow for empty `pathname` and will replace it 34 | // with "/". Here, we correct that. 35 | const resource = resourceUrl.pathname === '/' 36 | ? resourceUrl.toString().replace(/\/$/, '') 37 | : resourceUrl.toString(); 38 | 39 | const metadata = generateProtectedResourceMetadata({ 40 | authServerUrls, 41 | resourceUrl: resource, 42 | }); 43 | 44 | return new Response(JSON.stringify(metadata), { 45 | headers: { 46 | ...corsHeaders, 47 | "Cache-Control": "max-age=3600", 48 | "Content-Type": "application/json", 49 | }, 50 | }); 51 | }; 52 | } 53 | 54 | /** 55 | * Generates protected resource metadata for the given auth server URLs and 56 | * protected resource identifier. The protected resource identifier, as defined 57 | * in RFC 9728, should be a a URL that uses the https scheme and has no fragment 58 | * component. 59 | * 60 | * @param authServerUrls - Array of issuer URLs of the authorization servers. Each URL should 61 | * match the "issuer" field in the respective authorization server's 62 | * OAuth metadata (RFC 8414). 63 | * @param resourceUrl - the protected resource identifier 64 | * @param additionalMetadata - Additional metadata fields to include in the response 65 | * @returns Protected resource metadata, serializable to JSON 66 | */ 67 | export function generateProtectedResourceMetadata({ 68 | authServerUrls, 69 | resourceUrl, 70 | additionalMetadata, 71 | }: { 72 | authServerUrls: string[]; 73 | resourceUrl: string; 74 | additionalMetadata?: Partial; 75 | }): OAuthProtectedResourceMetadata { 76 | return Object.assign( 77 | { 78 | resource: resourceUrl, 79 | authorization_servers: authServerUrls 80 | }, 81 | additionalMetadata 82 | ); 83 | } 84 | 85 | /** 86 | * CORS options request handler for OAuth metadata endpoints. 87 | * Necessary for MCP clients that operate in web browsers. 88 | */ 89 | export function metadataCorsOptionsRequestHandler() { 90 | return () => { 91 | return new Response(null, { 92 | status: 200, 93 | headers: corsHeaders, 94 | }); 95 | }; 96 | } 97 | 98 | -------------------------------------------------------------------------------- /src/lib/event-emitter.ts: -------------------------------------------------------------------------------- 1 | import { ServerResponse, type IncomingMessage } from "node:http"; 2 | import { 3 | type McpErrorEvent, 4 | type McpEvent, 5 | type McpRequestEvent, 6 | type McpSessionEvent, 7 | createEvent, 8 | } from "./log-helper"; 9 | 10 | export class EventEmittingResponse extends ServerResponse { 11 | private onEvent?: (event: McpEvent) => void; 12 | private sessionId?: string; 13 | private requestId: string; 14 | private startTime: number; 15 | 16 | constructor( 17 | req: IncomingMessage, 18 | onEvent?: (event: McpEvent) => void, 19 | sessionId?: string 20 | ) { 21 | super(req); 22 | this.onEvent = onEvent; 23 | this.sessionId = sessionId; 24 | this.requestId = crypto.randomUUID(); 25 | this.startTime = Date.now(); 26 | } 27 | 28 | emitEvent(event: Omit) { 29 | if (this.onEvent) { 30 | this.onEvent( 31 | createEvent({ 32 | ...event, 33 | sessionId: this.sessionId, 34 | requestId: this.requestId, 35 | } as Omit) 36 | ); 37 | } 38 | } 39 | 40 | startSession( 41 | transport: "SSE" | "HTTP", 42 | clientInfo?: { userAgent?: string; ip?: string } 43 | ) { 44 | this.emitEvent({ 45 | type: "SESSION_STARTED", 46 | transport, 47 | clientInfo, 48 | } as Omit); 49 | } 50 | 51 | endSession(transport: "SSE" | "HTTP") { 52 | this.emitEvent({ 53 | type: "SESSION_ENDED", 54 | transport, 55 | } as Omit); 56 | } 57 | 58 | requestReceived(method: string, parameters?: unknown) { 59 | this.emitEvent({ 60 | type: "REQUEST_RECEIVED", 61 | method, 62 | parameters, 63 | status: "success", 64 | } as Omit); 65 | } 66 | 67 | requestCompleted(method: string, result?: unknown, error?: Error | string) { 68 | this.emitEvent({ 69 | type: "REQUEST_COMPLETED", 70 | method, 71 | result, 72 | duration: Date.now() - this.startTime, 73 | status: error ? "error" : "success", 74 | } as Omit); 75 | 76 | if (error) { 77 | this.error(error, `Error executing request ${method}`, "request"); 78 | } 79 | } 80 | 81 | error( 82 | error: Error | string, 83 | context?: string, 84 | source: McpErrorEvent["source"] = "system", 85 | severity: McpErrorEvent["severity"] = "error" 86 | ) { 87 | this.emitEvent({ 88 | type: "ERROR", 89 | error, 90 | context, 91 | source, 92 | severity, 93 | } as Omit); 94 | } 95 | 96 | end( 97 | chunk?: unknown, 98 | encoding?: BufferEncoding | (() => void), 99 | cb?: () => void 100 | ): this { 101 | let finalChunk = chunk; 102 | let finalEncoding = encoding; 103 | let finalCallback = cb; 104 | 105 | if (typeof chunk === "function") { 106 | finalCallback = chunk as () => void; 107 | finalChunk = undefined; 108 | finalEncoding = undefined; 109 | } else if (typeof encoding === "function") { 110 | finalCallback = encoding as () => void; 111 | finalEncoding = undefined; 112 | } 113 | 114 | return super.end( 115 | finalChunk as string | Buffer, 116 | finalEncoding as BufferEncoding, 117 | finalCallback 118 | ); 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /src/cli/index.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import { Command } from "commander"; 4 | import fs from "node:fs/promises"; 5 | import path from "node:path"; 6 | import chalk from "chalk"; 7 | 8 | const program = new Command(); 9 | 10 | const ROUTE_TEMPLATE = `import { createMcpHandler } from 'mcp-handler'; 11 | import { z } from 'zod'; 12 | 13 | const handler = createMcpHandler( 14 | server => { 15 | server.tool( 16 | 'roll_dice', 17 | 'Rolls an N-sided die', 18 | { 19 | sides: z.number().int().min(2) 20 | }, 21 | async ({ sides }) => { 22 | const value = 1 + Math.floor(Math.random() * sides); 23 | return { 24 | content: [{ type: 'text', text: \`🎲 You rolled a \${value}!\` }], 25 | }; 26 | } 27 | ); 28 | }, 29 | { 30 | // Optional server options 31 | }, 32 | { 33 | // Optional redis config 34 | redisUrl: process.env.REDIS_URL, 35 | // You need these endpoints 36 | basePath: '/api', 37 | maxDuration: 60, 38 | verboseLogs: true, 39 | } 40 | ); 41 | 42 | export { handler as GET, handler as POST }; 43 | `; 44 | 45 | async function detectPackageManager(): Promise< 46 | "npm" | "pnpm" | "yarn" | "bun" 47 | > { 48 | const cwd = process.cwd(); 49 | try { 50 | // Check for lock files in order of preference 51 | const files = await fs.readdir(cwd); 52 | 53 | if (files.includes("bun.lockb")) return "bun"; 54 | if (files.includes("pnpm-lock.yaml")) return "pnpm"; 55 | if (files.includes("yarn.lock")) return "yarn"; 56 | if (files.includes("package-lock.json")) return "npm"; 57 | 58 | // Fallback to npm if no lock file found 59 | return "npm"; 60 | } catch (error) { 61 | return "npm"; 62 | } 63 | } 64 | 65 | async function installDependencies( 66 | packageManager: "npm" | "pnpm" | "yarn" | "bun" 67 | ) { 68 | const execSync = (await import("node:child_process")).execSync; 69 | const dependencies = ["mcp-handler", "zod"]; 70 | 71 | const commands = { 72 | npm: `npm install ${dependencies.join(" ")}`, 73 | pnpm: `pnpm add ${dependencies.join(" ")}`, 74 | yarn: `yarn add ${dependencies.join(" ")}`, 75 | bun: `bun add ${dependencies.join(" ")}`, 76 | }; 77 | 78 | try { 79 | console.log( 80 | chalk.blue(`\nInstalling dependencies using ${packageManager}...`) 81 | ); 82 | execSync(commands[packageManager], { stdio: "inherit" }); 83 | console.log(chalk.green("\n✅ Dependencies installed successfully!")); 84 | } catch (error) { 85 | console.error( 86 | chalk.red( 87 | "\n❌ Failed to install dependencies. You can install them manually:" 88 | ) 89 | ); 90 | console.log(chalk.yellow(`\n${commands[packageManager]}`)); 91 | } 92 | } 93 | 94 | async function init() { 95 | try { 96 | // Check if we're in a Next.js project 97 | const packageJson = JSON.parse( 98 | await fs.readFile(path.join(process.cwd(), "package.json"), "utf-8") 99 | ); 100 | 101 | if (!packageJson.dependencies?.next && !packageJson.devDependencies?.next) { 102 | console.error( 103 | chalk.red("❌ This command must be run in a Next.js project") 104 | ); 105 | process.exit(1); 106 | } 107 | 108 | // Create the app/api/[transport] directory structure 109 | const routePath = path.join(process.cwd(), "app", "api", "[transport]"); 110 | await fs.mkdir(routePath, { recursive: true }); 111 | 112 | // Create the route.ts file 113 | const routeFilePath = path.join(routePath, "route.ts"); 114 | await fs.writeFile(routeFilePath, ROUTE_TEMPLATE); 115 | 116 | console.log(chalk.green("✅ Successfully created MCP route handler!")); 117 | 118 | // Detect and use the appropriate package manager 119 | const packageManager = await detectPackageManager(); 120 | await installDependencies(packageManager); 121 | } catch (error) { 122 | console.error(chalk.red("Error creating MCP route handler:"), error); 123 | process.exit(1); 124 | } 125 | } 126 | 127 | program 128 | .name("mcp-handler") 129 | .description("Initialize MCP route handler in your Next.js project") 130 | .action(init); 131 | 132 | program.parse(); 133 | -------------------------------------------------------------------------------- /src/handler/server-response-adapter.ts: -------------------------------------------------------------------------------- 1 | import { EventEmitter } from 'node:events'; 2 | import type { ServerResponse } from 'node:http'; 3 | 4 | type WriteheadArgs = { 5 | statusCode: number; 6 | headers?: Record; 7 | }; 8 | 9 | // biome-ignore lint/suspicious/noExplicitAny: Not deterministic 10 | export type BodyType = string | Buffer | Record | null; 11 | 12 | type EventListener = (...args: unknown[]) => void; 13 | 14 | /** 15 | * Anthropic's MCP API requires a server response object. This function 16 | * creates a fake server response object that can be used to pass to the MCP API. 17 | */ 18 | export function createServerResponseAdapter( 19 | signal: AbortSignal, 20 | fn: (re: ServerResponse) => Promise | void 21 | ): Promise { 22 | let writeHeadResolver: (v: WriteheadArgs) => void; 23 | const writeHeadPromise = new Promise(resolve => { 24 | writeHeadResolver = resolve; 25 | }); 26 | 27 | return new Promise(resolve => { 28 | let controller: ReadableStreamController | undefined; 29 | let shouldClose = false; 30 | let wroteHead = false; 31 | let statusCode = 200; 32 | let headers: Record | undefined; 33 | 34 | const writeHead = (code: number, headersArg?: Record) => { 35 | if (typeof headersArg === 'string') { 36 | throw new Error('Status message of writeHead not supported'); 37 | } 38 | statusCode = code; 39 | headers = headersArg; 40 | wroteHead = true; 41 | writeHeadResolver({ 42 | statusCode, 43 | headers, 44 | }); 45 | return fakeServerResponse; 46 | }; 47 | 48 | const bufferedData: Uint8Array[] = []; 49 | 50 | const write = ( 51 | chunk: Buffer | string, 52 | encoding?: BufferEncoding 53 | ): boolean => { 54 | if (encoding) { 55 | throw new Error('Encoding not supported'); 56 | } 57 | if (chunk instanceof Buffer) { 58 | throw new Error('Buffer not supported'); 59 | } 60 | if (!wroteHead) { 61 | writeHead(statusCode, headers); 62 | } 63 | if (!controller) { 64 | bufferedData.push(new TextEncoder().encode(chunk as string)); 65 | return true; 66 | } 67 | controller.enqueue(new TextEncoder().encode(chunk as string)); 68 | return true; 69 | }; 70 | 71 | const eventEmitter = new EventEmitter(); 72 | 73 | const fakeServerResponse = { 74 | writeHead, 75 | write, 76 | end: (data?: Buffer | string) => { 77 | if (data) { 78 | write(data); 79 | } 80 | 81 | if (!controller) { 82 | shouldClose = true; 83 | return fakeServerResponse; 84 | } 85 | try { 86 | controller.close(); 87 | } catch { 88 | /* May be closed on tcp layer */ 89 | } 90 | return fakeServerResponse; 91 | }, 92 | on: (event: string, listener: EventListener) => { 93 | eventEmitter.on(event, listener); 94 | return fakeServerResponse; 95 | }, 96 | get statusCode() { 97 | return statusCode; 98 | }, 99 | set statusCode(code: number) { 100 | statusCode = code; 101 | 102 | // If the status code is set after writeHead, we need to call 103 | // writeHead again to update the status code. 104 | if (wroteHead) { 105 | writeHeadResolver({ 106 | statusCode, 107 | headers, 108 | }); 109 | } 110 | }, 111 | }; 112 | 113 | signal.addEventListener('abort', () => { 114 | eventEmitter.emit('close'); 115 | }); 116 | 117 | void fn(fakeServerResponse as ServerResponse); 118 | 119 | void (async () => { 120 | const head = await writeHeadPromise; 121 | 122 | const response = new Response( 123 | new ReadableStream({ 124 | start(c) { 125 | controller = c; 126 | for (const chunk of bufferedData) { 127 | controller.enqueue(chunk); 128 | } 129 | if (shouldClose) { 130 | controller.close(); 131 | } 132 | }, 133 | }), 134 | { 135 | status: head.statusCode, 136 | headers: head.headers, 137 | } 138 | ); 139 | 140 | resolve(response); 141 | })(); 142 | }); 143 | } 144 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # mcp-handler 2 | 3 | ## 1.0.4 4 | 5 | ### Patch Changes 6 | 7 | - 1.0.4: update dependencies to use version 1.22.0 of @modelcontextprotocol/sdk 8 | 9 | ## 1.0.3 10 | 11 | ### Patch Changes 12 | 13 | - 639e634: update oauth usage 14 | 15 | ## 1.0.2 16 | 17 | ### Patch Changes 18 | 19 | - 956dc11: Fix memory leak when using SSE connections 20 | 21 | ## 1.0.1 22 | 23 | ### Patch Changes 24 | 25 | - d829aa6: prm resource identifier calculation accounts for paths 26 | 27 | ## 1.0.0 28 | 29 | ### Major Changes 30 | 31 | - 201a1c7: Move package from @vercle/mcp-adapter to mcp-handler 32 | 33 | ### Minor Changes 34 | 35 | - 488dfe4: Refactor packaging and make withMcpAuth stable 36 | - 02df830: Add RFC 9728 OAuth Protected Resource Metadata handler 37 | 38 | ## 0.11.2 39 | 40 | ### Patch Changes 41 | 42 | - c5c4ba5: chore: correctly resolve esm types 43 | 44 | ## 0.11.1 45 | 46 | ### Patch Changes 47 | 48 | - fc2a6d8: Update README during NPM outage 49 | 50 | ## 0.11.0 51 | 52 | ### Minor Changes 53 | 54 | - 7149159: Support adding serverMetadata to name and version the mcp server 55 | 56 | ## 0.10.0 57 | 58 | ### Minor Changes 59 | 60 | - 71c14ea: Fix import error with mcp sdk 61 | 62 | ### Patch Changes 63 | 64 | - 71c14ea: Fix module resolution 65 | 66 | ## 0.9.1 67 | 68 | ### Patch Changes 69 | 70 | - c86da9a: Not optional 71 | 72 | ## 0.9.0 73 | 74 | ### Minor Changes 75 | 76 | - 58efcf0: Add peerDependenciesMeta to fix not packaging the MCP SDK anymore 77 | 78 | ## 0.8.2 79 | 80 | ### Patch Changes 81 | 82 | - 15fded0: Fix mjs module resolution 83 | 84 | ## 0.8.1 85 | 86 | ### Patch Changes 87 | 88 | - 83e6fc7: Move zod to DevDep 89 | - 12b61fd: Add more robust error handling to auth logic 90 | - a522ffd: Move zod to devDep 91 | 92 | ## 0.8.0 93 | 94 | ### Minor Changes 95 | 96 | - 166e5ab: Add option to disable SSE as per MCP spec 97 | 98 | ### Patch Changes 99 | 100 | - 62518f2: Fix timeout scoping bug causing ReferenceError in SSE Handler 101 | - c55c609: Update auth logic to not throw error is missing bearerToken 102 | 103 | ## 0.7.3 104 | 105 | ### Patch Changes 106 | 107 | - 8fd2538: Fix missing non async argument 108 | 109 | ## 0.7.2 110 | 111 | ### Patch Changes 112 | 113 | - 47eff5a: Fix allowing both async and non async handlers 114 | 115 | ## 0.7.1 116 | 117 | ### Patch Changes 118 | 119 | - 13bd4fa: Add in auth handler 120 | 121 | ## 0.7.0 122 | 123 | ### Minor Changes 124 | 125 | - b24064f: Update pinned mcp sdk version to 1.12.0 126 | 127 | ## 0.6.2 128 | 129 | ### Patch Changes 130 | 131 | - 4f7a593: Fix SSE initializeServer 132 | 133 | ## 0.6.1 134 | 135 | ### Patch Changes 136 | 137 | - b46856a: Allow an async initializeServer call 138 | 139 | ## 0.6.0 140 | 141 | ### Minor Changes 142 | 143 | - 74d8a2c: Fix backwards compatibility algorithm with HTTP + SSE 144 | 145 | ## 0.5.1 146 | 147 | ### Patch Changes 148 | 149 | - f48b5d6: Fix HTTP status code for some errors 150 | 151 | ## 0.5.0 152 | 153 | ### Minor Changes 154 | 155 | - 24ce36e: added cli support to auto add the mcp route to a nextjs project 156 | 157 | ### Patch Changes 158 | 159 | - 24ce36e: updated readme 160 | - 48d4d64: fix out of date pnpm lock 161 | 162 | ## 0.4.1 163 | 164 | ### Patch Changes 165 | 166 | - c0d7675: add logging 167 | 168 | ## 0.4.0 169 | 170 | ### Minor Changes 171 | 172 | - 7fe14e6: make redis optional by only init on sse and messages 173 | 174 | ### Patch Changes 175 | 176 | - 99d7837: fix release 177 | 178 | ## 0.2.4 179 | 180 | ### Patch Changes 181 | 182 | - update readme with consistent docs ([#13309](https://github.com/vercel/vercel/pull/13309)) 183 | 184 | - Fix message endpoint not being settable ([#13311](https://github.com/vercel/vercel/pull/13311)) 185 | 186 | ## 0.2.3 187 | 188 | ### Patch Changes 189 | 190 | - Update readme and example ([#13307](https://github.com/vercel/vercel/pull/13307)) 191 | 192 | ## 0.2.2 193 | 194 | ### Patch Changes 195 | 196 | - Correct file output ([#13305](https://github.com/vercel/vercel/pull/13305)) 197 | 198 | ## 0.2.1 199 | 200 | ### Patch Changes 201 | 202 | - add in repository to readme and fix up example ([#13298](https://github.com/vercel/vercel/pull/13298)) 203 | 204 | ## 0.2.0 205 | 206 | ### Minor Changes 207 | 208 | - Publish initial version of mcp adapter ([#13290](https://github.com/vercel/vercel/pull/13290)) 209 | 210 | ### Patch Changes 211 | 212 | - make package public and fix default args passed in ([#13294](https://github.com/vercel/vercel/pull/13294)) 213 | -------------------------------------------------------------------------------- /src/auth/auth-wrapper.ts: -------------------------------------------------------------------------------- 1 | import {AuthInfo} from "@modelcontextprotocol/sdk/server/auth/types.js"; 2 | import { 3 | InvalidTokenError, 4 | InsufficientScopeError, 5 | ServerError, 6 | } from "@modelcontextprotocol/sdk/server/auth/errors.js"; 7 | import {withAuthContext} from "./auth-context"; 8 | 9 | declare global { 10 | interface Request { 11 | auth?: AuthInfo; 12 | } 13 | } 14 | 15 | export function withMcpAuth( 16 | handler: (req: Request) => Response | Promise, 17 | verifyToken: ( 18 | req: Request, 19 | bearerToken?: string 20 | ) => AuthInfo | undefined | Promise, 21 | { 22 | required = false, 23 | resourceMetadataPath = "/.well-known/oauth-protected-resource", 24 | requiredScopes, 25 | }: { 26 | required?: boolean; 27 | resourceMetadataPath?: string; 28 | requiredScopes?: string[]; 29 | } = {} 30 | ) { 31 | return async (req: Request) => { 32 | const origin = new URL(req.url).origin; 33 | const resourceMetadataUrl = `${origin}${resourceMetadataPath}`; 34 | 35 | const authHeader = req.headers.get("Authorization"); 36 | const [type, token] = authHeader?.split(" ") || []; 37 | 38 | // Only support bearer token as per the MCP spec 39 | // https://modelcontextprotocol.io/specification/2025-03-26/basic/authorization#2-6-1-token-requirements 40 | const bearerToken = type?.toLowerCase() === "bearer" ? token : undefined; 41 | 42 | let authInfo: AuthInfo | undefined; 43 | try { 44 | authInfo = await verifyToken(req, bearerToken); 45 | } catch (error) { 46 | console.error("Unexpected error authenticating bearer token:", error); 47 | const publicError = new InvalidTokenError("Invalid token"); 48 | return new Response(JSON.stringify(publicError.toResponseObject()), { 49 | status: 401, 50 | headers: { 51 | "WWW-Authenticate": `Bearer error="${publicError.errorCode}", error_description="${publicError.message}", resource_metadata="${resourceMetadataUrl}"`, 52 | "Content-Type": "application/json", 53 | }, 54 | }); 55 | } 56 | 57 | try { 58 | if (required && !authInfo) { 59 | throw new InvalidTokenError("No authorization provided"); 60 | } 61 | 62 | if (!authInfo) { 63 | return handler(req); 64 | } 65 | 66 | // Check if token has the required scopes (if any) 67 | if (requiredScopes?.length) { 68 | const hasAllScopes = requiredScopes.every((scope) => 69 | authInfo!.scopes.includes(scope) 70 | ); 71 | 72 | if (!hasAllScopes) { 73 | throw new InsufficientScopeError("Insufficient scope"); 74 | } 75 | } 76 | 77 | // Check if the token is expired 78 | if (authInfo.expiresAt && authInfo.expiresAt < Date.now() / 1000) { 79 | throw new InvalidTokenError("Token has expired"); 80 | } 81 | 82 | // Set auth info on the request object after successful verification 83 | req.auth = authInfo; 84 | 85 | return withAuthContext(authInfo, () => handler(req)); 86 | } catch (error) { 87 | if (error instanceof InvalidTokenError) { 88 | return new Response(JSON.stringify(error.toResponseObject()), { 89 | status: 401, 90 | headers: { 91 | "WWW-Authenticate": `Bearer error="${error.errorCode}", error_description="${error.message}", resource_metadata="${resourceMetadataUrl}"`, 92 | "Content-Type": "application/json", 93 | }, 94 | }); 95 | } else if (error instanceof InsufficientScopeError) { 96 | return new Response(JSON.stringify(error.toResponseObject()), { 97 | status: 403, 98 | headers: { 99 | "WWW-Authenticate": `Bearer error="${error.errorCode}", error_description="${error.message}", resource_metadata="${resourceMetadataUrl}"`, 100 | "Content-Type": "application/json", 101 | }, 102 | }); 103 | } else if (error instanceof ServerError) { 104 | return new Response(JSON.stringify(error.toResponseObject()), { 105 | status: 500, 106 | headers: { 107 | "Content-Type": "application/json", 108 | }, 109 | }); 110 | } else { 111 | console.error("Unexpected error authenticating bearer token:", error); 112 | const serverError = new ServerError("Internal Server Error"); 113 | return new Response(JSON.stringify(serverError.toResponseObject()), { 114 | status: 500, 115 | headers: { 116 | "Content-Type": "application/json", 117 | }, 118 | }); 119 | } 120 | } 121 | }; 122 | } 123 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # mcp-handler 2 | 3 | A Vercel adapter for the Model Context Protocol (MCP), enabling real-time communication between your applications and AI models. Currently supports Next.js and Nuxt with more framework adapters coming soon. 4 | 5 | ## Installation 6 | 7 | ```bash 8 | npm install mcp-handler @modelcontextprotocol/sdk zod@^3 9 | # or 10 | yarn add mcp-handler @modelcontextprotocol/sdk zod@^3 11 | # or 12 | pnpm add mcp-handler @modelcontextprotocol/sdk zod@^3 13 | # or 14 | bun add mcp-handler @modelcontextprotocol/sdk zod@^3 15 | ``` 16 | 17 | ## Next.js Usage 18 | 19 | ```typescript 20 | // app/api/[transport]/route.ts 21 | import { createMcpHandler } from "mcp-handler"; 22 | import { z } from "zod"; 23 | const handler = createMcpHandler( 24 | (server) => { 25 | server.tool( 26 | "roll_dice", 27 | "Rolls an N-sided die", 28 | { 29 | sides: z.number().int().min(2), 30 | }, 31 | async ({ sides }) => { 32 | const value = 1 + Math.floor(Math.random() * sides); 33 | return { 34 | content: [{ type: "text", text: `🎲 You rolled a ${value}!` }], 35 | }; 36 | } 37 | ); 38 | }, 39 | { 40 | // Optional server options 41 | }, 42 | { 43 | // Optional redis config 44 | redisUrl: process.env.REDIS_URL, 45 | basePath: "/api", // this needs to match where the [transport] is located. 46 | maxDuration: 60, 47 | verboseLogs: true, 48 | } 49 | ); 50 | export { handler as GET, handler as POST }; 51 | ``` 52 | 53 | ### Advanced Routing 54 | 55 | ```typescript 56 | // app/dynamic/[p]/[transport]/route.ts 57 | 58 | import { createMcpHandler } from "mcp-handler"; 59 | import type { NextRequest } from "next/server"; 60 | import { z } from "zod"; 61 | 62 | const handler = async ( 63 | req: NextRequest, 64 | { params }: { params: Promise<{ p: string; transport: string }> } 65 | ) => { 66 | const { p, transport } = await params; 67 | 68 | return createMcpHandler( 69 | (server) => { 70 | server.tool( 71 | "roll_dice", 72 | "Rolls an N-sided die", 73 | { sides: z.number().int().min(2) }, 74 | async ({ sides }) => { 75 | const value = 1 + Math.floor(Math.random() * sides); 76 | return { 77 | content: [{ type: "text", text: `🎲 You rolled a ${value}!` }], 78 | }; 79 | } 80 | ); 81 | }, 82 | { 83 | capabilities: { 84 | tools: { 85 | roll_dice: { 86 | description: "Roll a dice", 87 | }, 88 | }, 89 | }, 90 | }, 91 | { 92 | redisUrl: process.env.REDIS_URL, 93 | basePath: `/dynamic/${p}`, 94 | verboseLogs: true, 95 | maxDuration: 60, 96 | } 97 | )(req); 98 | }; 99 | export { handler as GET, handler as POST, handler as DELETE }; 100 | ``` 101 | 102 | ## Nuxt Usage 103 | 104 | ```typescript 105 | // server/api/mcp/[transport].ts 106 | 107 | import { createMcpHandler } from "mcp-handler"; 108 | import { getHeader, defineEventHandler, fromWebHandler } from "h3"; 109 | import { z } from "zod"; 110 | 111 | const handler = createMcpHandler((server) => { 112 | server.tool( 113 | "roll_dice", 114 | "Rolls an N-sided die", 115 | { 116 | sides: z.number().int().min(2) 117 | }, 118 | async ({ sides }) => { 119 | const value = 1 + Math.floor(Math.random() * sides) 120 | return { 121 | content: [{ type: "text", text: `🎲 You rolled a ${value}!` }] 122 | } 123 | } 124 | ) 125 | }, { 126 | // Optional server options 127 | }); 128 | 129 | export default fromWebHandler(handler); 130 | ``` 131 | 132 | ## Connecting to your MCP server via stdio 133 | 134 | Depending on the version of your client application, remote MCP's may need to use 135 | [mcp-remote](https://www.npmjs.com/package/mcp-remote) to proxy Streamable HTTP into stdio. 136 | 137 | If your client supports it, it's recommended to connect to the Streamable HTTP endpoint directly such as: 138 | 139 | ```typescript 140 | "remote-example": { 141 | "url": "http://localhost:3000/api/mcp", 142 | } 143 | ``` 144 | 145 | Due to client versions, and varying levels of support, you can list `mcp-remote` as the method for end users to connect to your MCP server. 146 | 147 | The above set up snippet will then look like: 148 | 149 | ```typescript 150 | "remote-example": { 151 | "command": "npx", 152 | "args": [ 153 | "-y", 154 | "mcp-remote", 155 | "http://localhost:3000/api/mcp" // this is your app/api/[transport]/route.ts 156 | ] 157 | } 158 | ``` 159 | 160 | ## Integrating into your client 161 | 162 | When you want to use it in your MCP client of choice: 163 | 164 | Depending on the version of your client application, remote MCP's may need to use 165 | [mcp-remote](https://www.npmjs.com/package/mcp-remote) to proxy Streamable HTTP into Stdio. 166 | 167 | ### Claude Desktop 168 | 169 | [Official Docs](https://modelcontextprotocol.io/quickstart/user) 170 | 171 | In order to add an MCP server to Claude Desktop you need to edit the configuration file located at: 172 | 173 | ```typescript 174 | "remote-example": { 175 | "command": "npx", 176 | "args": [ 177 | "-y", 178 | "mcp-remote", 179 | "http://localhost:3000/api/mcp" // this is your app/api/[transport]/route.ts 180 | ] 181 | } 182 | ``` 183 | 184 | macOS: ~/Library/Application Support/Claude/claude_desktop_config.json 185 | Windows: %APPDATA%\Claude\claude_desktop_config.json 186 | If it does not exist yet, you may need to enable it under Settings > Developer. 187 | 188 | Restart Claude Desktop to pick up the changes in the configuration file. Upon restarting, you should see a hammer icon in the bottom right corner of the input box. 189 | 190 | ### Cursor 191 | 192 | [Official Docs](https://docs.cursor.com/context/model-context-protocol) 193 | 194 | The configuration file is located at ~/.cursor/mcp.json. 195 | 196 | As of version 0.48.0, Cursor supports unauthed SSE servers directly. If your MCP server is using the official MCP OAuth authorization protocol, you still need to add a "command" server and call mcp-remote. 197 | 198 | ### Windsurf 199 | 200 | [Official Docs](https://docs.codeium.com/windsurf/mcp) 201 | 202 | The configuration file is located at ~/.codeium/windsurf/mcp_config.json. 203 | 204 | ## Usage in your app 205 | 206 | 1. Use the MCP client in your application: 207 | 208 | ```typescript 209 | // app/components/YourComponent.tsx 210 | import { McpClient } from "@modelcontextprotocol/sdk/client"; 211 | 212 | const client = new McpClient({ 213 | // When using basePath, the SSE endpoint will be automatically derived 214 | transport: new SSEClientTransport("/api/mcp/mcp"), 215 | }); 216 | 217 | // Use the client to make requests 218 | const result = await client.request("yourMethod", { param: "value" }); 219 | ``` 220 | 221 | ## Configuration Options 222 | 223 | The `initializeMcpApiHandler` function accepts the following configuration options: 224 | 225 | ```typescript 226 | interface Config { 227 | redisUrl?: string; // Redis connection URL for pub/sub 228 | basePath?: string; // Base path for MCP endpoints 229 | maxDuration?: number; // Maximum duration for SSE connections in seconds 230 | verboseLogs?: boolean; // Log debugging information 231 | } 232 | ``` 233 | 234 | ## Authorization 235 | 236 | The MCP adapter supports the [MCP Authorization Specification](https://modelcontextprotocol.io/specification/draft/basic/authorization) per the through the `withMcpAuth` wrapper. This allows you to protect your MCP endpoints and access authentication information in your tools. 237 | 238 | ### Basic Usage 239 | 240 | ```typescript 241 | // app/api/[transport]/route.ts 242 | import type { AuthInfo } from "@modelcontextprotocol/sdk/server/auth/types.js"; 243 | import { createMcpHandler, withMcpAuth } from "mcp-handler"; 244 | import { z } from "zod"; 245 | 246 | // Create your handler as normal 247 | const handler = createMcpHandler( 248 | (server) => { 249 | server.tool( 250 | "echo", 251 | "Echo a message", 252 | { message: z.string() }, 253 | async ({ message }, extra) => { 254 | // Access auth info in your tools via extra.authInfo 255 | return { 256 | content: [ 257 | { 258 | type: "text", 259 | text: `Echo: ${message}${ 260 | extra.authInfo?.token 261 | ? ` for user ${extra.authInfo.clientId}` 262 | : "" 263 | }`, 264 | }, 265 | ], 266 | }; 267 | } 268 | ); 269 | }, 270 | { 271 | // Optional server options 272 | } 273 | ); 274 | 275 | // Wrap your handler with authorization 276 | const verifyToken = async ( 277 | req: Request, 278 | bearerToken?: string 279 | ): Promise => { 280 | if (!bearerToken) return undefined; 281 | 282 | // Replace this example with actual token verification logic 283 | // Return an AuthInfo object if verification succeeds 284 | // Otherwise, return undefined 285 | const isValid = bearerToken.startsWith("__TEST_VALUE__"); 286 | 287 | if (!isValid) return undefined; 288 | 289 | return { 290 | token: bearerToken, 291 | scopes: ["read:stuff"], // Add relevant scopes 292 | clientId: "user123", // Add user/client identifier 293 | extra: { 294 | // Optional extra information 295 | userId: "123", 296 | }, 297 | }; 298 | }; 299 | 300 | // Make authorization required 301 | const authHandler = withMcpAuth(handler, verifyToken, { 302 | required: true, // Make auth required for all requests 303 | requiredScopes: ["read:stuff"], // Optional: Require specific scopes 304 | resourceMetadataPath: "/.well-known/oauth-protected-resource", // Optional: Custom metadata path 305 | }); 306 | 307 | export { authHandler as GET, authHandler as POST }; 308 | ``` 309 | 310 | ### OAuth Protected Resource Metadata 311 | 312 | When implementing authorization in MCP, you must define the OAuth [Protected Resource Metadata](https://modelcontextprotocol.io/specification/draft/basic/authorization#authorization-server-location) endpoint. This endpoint provides information about your MCP server's authentication requirements to clients. 313 | 314 | Create a new file at `app/.well-known/oauth-protected-resource/route.ts`: 315 | 316 | ```typescript 317 | import { 318 | protectedResourceHandler, 319 | metadataCorsOptionsRequestHandler, 320 | } from "mcp-handler"; 321 | 322 | const handler = protectedResourceHandler({ 323 | // Specify the Issuer URL of the associated Authorization Server 324 | authServerUrls: ["https://auth-server.com"], 325 | }); 326 | 327 | const corsHandler = metadataCorsOptionsRequestHandler() 328 | 329 | export { handler as GET, corsHandler as OPTIONS }; 330 | ``` 331 | 332 | This endpoint provides: 333 | 334 | - `resource`: The URL of your MCP server 335 | - `authorization_servers`: Array of OAuth authorization server Issuer URLs that can issue valid tokens 336 | 337 | The path to this endpoint should match the `resourceMetadataPath` option in your `withMcpAuth` configuration, 338 | which by default is `/.well-known/oauth-protected-resource` (the full URL will be `https://your-domain.com/.well-known/oauth-protected-resource`). 339 | 340 | ### Authorization Flow 341 | 342 | 1. Client makes a request with a Bearer token in the Authorization header 343 | 2. The `verifyToken` function validates the token and returns auth info 344 | 3. If authentication is required and fails, a 401 response is returned 345 | 4. If specific scopes are required and missing, a 403 response is returned 346 | 5. On successful authentication, the auth info is available in tool handlers via `extra.authInfo` 347 | 348 | ## Features 349 | 350 | - **Framework Support**: Currently supports Next.js with more framework adapters coming soon 351 | - **Multiple Transport Options**: Supports both Streamable HTTP and Server-Sent Events (SSE) transports 352 | - **Redis Integration**: For SSE transport resumability 353 | - **TypeScript Support**: Full TypeScript support with type definitions 354 | 355 | ## Requirements 356 | 357 | - Next.js 13 or later (for Next.js adapter) 358 | - Node.js 18 or later 359 | - Redis (optional, for SSE transport) 360 | 361 | ## License 362 | 363 | Apache-2.0 364 | -------------------------------------------------------------------------------- /tests/e2e.test.ts: -------------------------------------------------------------------------------- 1 | import {describe, it, expect, beforeEach, afterEach, vi, Mock} from "vitest"; 2 | import { z } from "zod"; 3 | import { 4 | createServer, 5 | IncomingMessage, 6 | ServerResponse, 7 | type Server, 8 | } from "node:http"; 9 | import type { AddressInfo } from "node:net"; 10 | import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js"; 11 | import { Client } from "@modelcontextprotocol/sdk/client/index.js"; 12 | import { createMcpHandler } from "../src/index"; 13 | import { withMcpAuth } from "../src/auth/auth-wrapper"; 14 | 15 | describe("e2e", () => { 16 | let server: Server; 17 | let endpoint: string; 18 | let client: Client; 19 | let verifyTokenMock: Mock; 20 | 21 | beforeEach(async () => { 22 | const _mcpHandler = createMcpHandler( 23 | (server) => { 24 | server.registerTool( 25 | "echo", 26 | { 27 | description: "Echo a message", 28 | inputSchema: { message: z.string() }, 29 | }, 30 | async ({ message }, extra) => { 31 | return { 32 | content: [ 33 | { 34 | type: "text", 35 | text: `Tool echo: ${message}${ 36 | extra.authInfo?.token ? ` for ${extra.authInfo?.token}` : "" 37 | }`, 38 | }, 39 | ], 40 | }; 41 | } 42 | ); 43 | 44 | server.registerPrompt( 45 | "greeting", 46 | { 47 | description: "Generate a greeting message", 48 | argsSchema: { 49 | name: z.string().describe("The name of the person to greet"), 50 | }, 51 | }, 52 | async ({ name }) => { 53 | return { 54 | messages: [ 55 | { 56 | role: "user" as const, 57 | content: { 58 | type: "text" as const, 59 | text: `Hello, ${name}! Welcome to the MCP server.`, 60 | }, 61 | }, 62 | ], 63 | }; 64 | } 65 | ); 66 | 67 | server.registerResource( 68 | "test-resource", 69 | "test://example/resource", 70 | { 71 | description: "A test resource", 72 | mimeType: "text/plain", 73 | }, 74 | async () => { 75 | return { 76 | contents: [ 77 | { 78 | uri: "test://example/resource", 79 | text: "This is test resource content", 80 | mimeType: "text/plain", 81 | }, 82 | ], 83 | }; 84 | } 85 | ); 86 | }, 87 | { 88 | capabilities: { 89 | tools: { 90 | listChanged: true, 91 | }, 92 | prompts: { 93 | listChanged: true, 94 | }, 95 | resources: { 96 | listChanged: true, 97 | subscribe: true, 98 | }, 99 | }, 100 | }, 101 | { 102 | redisUrl: process.env.KV_URL, 103 | basePath: "", 104 | verboseLogs: true, 105 | maxDuration: 60, 106 | } 107 | ); 108 | 109 | verifyTokenMock = vi.fn((req) => { 110 | const header = req.headers.get("Authorization"); 111 | if (header?.startsWith("Bearer ")) { 112 | const token = header.slice(7).trim(); 113 | return Promise.resolve({ 114 | token, 115 | clientId: "client1", 116 | scopes: ["read:stuff"], 117 | }); 118 | } 119 | return undefined; 120 | }) 121 | 122 | const mcpHandler = withMcpAuth(_mcpHandler, verifyTokenMock); 123 | 124 | server = createServer(nodeToWebHandler(mcpHandler)); 125 | await new Promise((resolve) => { 126 | server.listen(0, () => { 127 | resolve(); 128 | }); 129 | }); 130 | const port = (server.address() as AddressInfo | null)?.port; 131 | endpoint = `http://localhost:${port}`; 132 | 133 | const transport = new StreamableHTTPClientTransport( 134 | new URL(`${endpoint}/mcp`) 135 | ); 136 | client = new Client( 137 | { 138 | name: "example-client", 139 | version: "1.0.0", 140 | }, 141 | { 142 | capabilities: {}, 143 | } 144 | ); 145 | await client.connect(transport); 146 | }); 147 | 148 | afterEach(() => { 149 | server.close(); 150 | }); 151 | 152 | it("should read server capabilities", async () => { 153 | const capabilities = client.getServerCapabilities(); 154 | expect(capabilities).toBeDefined(); 155 | expect(capabilities?.tools).toBeDefined(); 156 | expect(capabilities?.prompts).toBeDefined(); 157 | expect(capabilities?.resources).toBeDefined(); 158 | expect((await client.listTools()).tools).toStrictEqual([ 159 | { 160 | "description": "Echo a message", 161 | "inputSchema": { 162 | "properties": { 163 | "message": { 164 | "type": "string", 165 | }, 166 | }, 167 | "required": [ 168 | "message", 169 | ], 170 | "type": "object", 171 | }, 172 | "name": "echo", 173 | }, 174 | ]); 175 | expect((await client.listPrompts()).prompts).toStrictEqual([ 176 | { 177 | "arguments": [ 178 | { 179 | "description": "The name of the person to greet", 180 | "name": "name", 181 | "required": true, 182 | }, 183 | ], 184 | "description": "Generate a greeting message", 185 | "name": "greeting", 186 | }, 187 | ]); 188 | expect((await client.listResources()).resources).toStrictEqual([ 189 | { 190 | "description": "A test resource", 191 | "mimeType": "text/plain", 192 | "name": "test-resource", 193 | "uri": "test://example/resource", 194 | }, 195 | ]); 196 | }); 197 | 198 | it("should list tools", async () => { 199 | const { tools } = await client.listTools(); 200 | expect(tools.length).toEqual(1); 201 | 202 | const echo = tools.find((tool) => tool.name === "echo"); 203 | expect(echo).toBeDefined(); 204 | expect(echo?.description).toEqual("Echo a message"); 205 | }); 206 | 207 | it("should list prompts", async () => { 208 | const { prompts } = await client.listPrompts(); 209 | expect(prompts.length).toEqual(1); 210 | 211 | const greeting = prompts.find((prompt) => prompt.name === "greeting"); 212 | expect(greeting).toBeDefined(); 213 | expect(greeting?.description).toEqual("Generate a greeting message"); 214 | expect(greeting?.arguments).toBeDefined(); 215 | expect(greeting?.arguments?.length).toBeGreaterThan(0); 216 | }); 217 | 218 | it("should get a prompt", async () => { 219 | const result = await client.getPrompt({ 220 | name: "greeting", 221 | arguments: { 222 | name: "Alice", 223 | }, 224 | }); 225 | expect(result.messages).toBeDefined(); 226 | expect(result.messages.length).toEqual(1); 227 | expect(result.messages[0].role).toEqual("user"); 228 | expect(result.messages[0].content.type).toEqual("text"); 229 | if (result.messages[0].content.type === "text") { 230 | expect(result.messages[0].content.text).toContain("Hello, Alice!"); 231 | } 232 | }); 233 | 234 | it("should list resources", async () => { 235 | const { resources } = await client.listResources(); 236 | expect(resources.length).toEqual(1); 237 | 238 | const testResource = resources.find( 239 | (resource) => resource.name === "test-resource" 240 | ); 241 | expect(testResource).toBeDefined(); 242 | expect(testResource?.uri).toEqual("test://example/resource"); 243 | expect(testResource?.description).toEqual("A test resource"); 244 | }); 245 | 246 | it("should read a resource", async () => { 247 | const result = await client.readResource({ 248 | uri: "test://example/resource", 249 | }); 250 | expect(result.contents).toBeDefined(); 251 | expect(result.contents.length).toEqual(1); 252 | expect(result.contents[0].uri).toEqual("test://example/resource"); 253 | expect("text" in result.contents[0]).toBe(true); 254 | if ("text" in result.contents[0]) { 255 | expect(result.contents[0].text).toEqual( 256 | "This is test resource content" 257 | ); 258 | } 259 | }); 260 | 261 | it("should call a tool", async () => { 262 | const result = await client.callTool( 263 | { 264 | name: "echo", 265 | arguments: { 266 | message: "Are you there?", 267 | }, 268 | }, 269 | undefined, 270 | {} 271 | ); 272 | expect((result.content as any)[0].text).toEqual( 273 | "Tool echo: Are you there?" 274 | ); 275 | }); 276 | 277 | it("should call a tool with auth", async () => { 278 | const authenticatedTransport = new StreamableHTTPClientTransport( 279 | new URL(`${endpoint}/mcp`), 280 | { 281 | requestInit: { 282 | headers: { 283 | Authorization: `Bearer ACCESS_TOKEN`, 284 | }, 285 | }, 286 | } 287 | ); 288 | const authenticatedClient = new Client( 289 | { 290 | name: "example-client", 291 | version: "1.0.0", 292 | }, 293 | { 294 | capabilities: {}, 295 | } 296 | ); 297 | await authenticatedClient.connect(authenticatedTransport); 298 | const result = await authenticatedClient.callTool( 299 | { 300 | name: "echo", 301 | arguments: { 302 | message: "Are you there?", 303 | }, 304 | }, 305 | undefined, 306 | {} 307 | ); 308 | expect((result.content as any)[0].text).toEqual( 309 | "Tool echo: Are you there? for ACCESS_TOKEN" 310 | ); 311 | }); 312 | 313 | it("should return an invalid token error when verifyToken fails", async () => { 314 | const authenticatedTransport = new StreamableHTTPClientTransport( 315 | new URL(`${endpoint}/mcp`), 316 | { 317 | requestInit: { 318 | headers: { 319 | Authorization: `Bearer ACCESS_TOKEN`, 320 | }, 321 | }, 322 | } 323 | ); 324 | const authenticatedClient = new Client( 325 | { 326 | name: "example-client", 327 | version: "1.0.0", 328 | }, 329 | { 330 | capabilities: {}, 331 | } 332 | ); 333 | verifyTokenMock.mockImplementation(() => { 334 | throw new Error('JWT signature failed, or something') 335 | }) 336 | 337 | expect(() => authenticatedClient.connect(authenticatedTransport)).rejects.toThrow('Invalid token') 338 | }); 339 | }); 340 | 341 | function nodeToWebHandler( 342 | handler: (req: Request) => Promise 343 | ): (req: IncomingMessage, res: ServerResponse) => void { 344 | return async (req, res) => { 345 | const method = (req.method || "GET").toUpperCase(); 346 | const requestBody = 347 | method === "GET" || method === "HEAD" 348 | ? undefined 349 | : await new Promise((resolve, reject) => { 350 | const chunks: Buffer[] = []; 351 | req.on("data", (chunk) => { 352 | chunks.push(chunk); 353 | }); 354 | req.on("end", () => { 355 | const buf = Buffer.concat(chunks); 356 | resolve( 357 | buf.buffer.slice( 358 | buf.byteOffset, 359 | buf.byteOffset + buf.byteLength 360 | ) 361 | ); 362 | }); 363 | req.on("error", () => { 364 | reject(new Error("Failed to read request body")); 365 | }); 366 | }); 367 | 368 | const requestHeaders = new Headers(); 369 | for (const [key, value] of Object.entries(req.headers)) { 370 | if (value === undefined) { 371 | continue; 372 | } 373 | if (Array.isArray(value)) { 374 | for (const val of value) { 375 | requestHeaders.append(key, val); 376 | } 377 | } else { 378 | requestHeaders.append(key, value); 379 | } 380 | } 381 | 382 | const reqUrl = new URL(req.url || "/", "http://localhost"); 383 | const webReq = new Request(reqUrl, { 384 | method: req.method, 385 | headers: requestHeaders, 386 | body: requestBody, 387 | }); 388 | 389 | const webResp = await handler(webReq); 390 | 391 | const responseHeaders = Object.fromEntries(webResp.headers); 392 | 393 | res.writeHead(webResp.status, webResp.statusText, responseHeaders); 394 | 395 | if (webResp.body) { 396 | const arrayBuffer = await webResp.arrayBuffer(); 397 | const buffer = Buffer.from(arrayBuffer); 398 | res.write(buffer); 399 | } 400 | res.end(); 401 | }; 402 | } 403 | -------------------------------------------------------------------------------- /src/handler/mcp-api-handler.ts: -------------------------------------------------------------------------------- 1 | import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; 2 | import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js"; 3 | import { 4 | type IncomingHttpHeaders, 5 | IncomingMessage, 6 | type ServerResponse, 7 | } from "node:http"; 8 | import { createClient } from "redis"; 9 | import { Socket } from "node:net"; 10 | import { Readable } from "node:stream"; 11 | import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js"; 12 | import type { BodyType } from "./server-response-adapter"; 13 | import assert from "node:assert"; 14 | import type { 15 | McpEvent, 16 | McpErrorEvent, 17 | McpSessionEvent, 18 | McpRequestEvent, 19 | } from "../lib/log-helper"; 20 | import { createEvent } from "../lib/log-helper"; 21 | import { EventEmittingResponse } from "../lib/event-emitter.js"; 22 | import { AuthInfo } from "@modelcontextprotocol/sdk/server/auth/types"; 23 | import { getAuthContext } from "../auth/auth-context"; 24 | import { ServerOptions } from "."; 25 | 26 | interface SerializedRequest { 27 | requestId: string; 28 | url: string; 29 | method: string; 30 | body: BodyType; 31 | headers: IncomingHttpHeaders; 32 | } 33 | 34 | type LogLevel = "log" | "error" | "warn" | "info" | "debug"; 35 | 36 | type Logger = { 37 | log: (...args: unknown[]) => void; 38 | error: (...args: unknown[]) => void; 39 | warn: (...args: unknown[]) => void; 40 | info: (...args: unknown[]) => void; 41 | debug: (...args: unknown[]) => void; 42 | }; 43 | 44 | function createLogger(verboseLogs = false): Logger { 45 | return { 46 | log: (...args: unknown[]) => { 47 | if (verboseLogs) console.log(...args); 48 | }, 49 | error: (...args: unknown[]) => { 50 | if (verboseLogs) console.error(...args); 51 | }, 52 | warn: (...args: unknown[]) => { 53 | if (verboseLogs) console.warn(...args); 54 | }, 55 | info: (...args: unknown[]) => { 56 | if (verboseLogs) console.info(...args); 57 | }, 58 | debug: (...args: unknown[]) => { 59 | if (verboseLogs) console.debug(...args); 60 | }, 61 | }; 62 | } 63 | /** 64 | * Configuration for the MCP handler. 65 | * @property redisUrl - The URL of the Redis instance to use for the MCP handler. 66 | * @property streamableHttpEndpoint - The endpoint to use for the streamable HTTP transport. 67 | * @property sseEndpoint - The endpoint to use for the SSE transport. 68 | * @property verboseLogs - If true, enables console logging. 69 | */ 70 | export type Config = { 71 | /** 72 | * The URL of the Redis instance to use for the MCP handler. 73 | * @default process.env.REDIS_URL || process.env.KV_URL 74 | */ 75 | redisUrl?: string; 76 | /** 77 | * The endpoint to use for the streamable HTTP transport. 78 | * @deprecated Use `set basePath` instead. 79 | * @default "/mcp" 80 | */ 81 | streamableHttpEndpoint?: string; 82 | /** 83 | * The endpoint to use for the SSE transport. 84 | * @deprecated Use `set basePath` instead. 85 | * @default "/sse" 86 | */ 87 | sseEndpoint?: string; 88 | /** 89 | * The endpoint to use for the SSE messages transport. 90 | * @deprecated Use `set basePath` instead. 91 | * @default "/message" 92 | */ 93 | sseMessageEndpoint?: string; 94 | /** 95 | * The maximum duration of an MCP request in seconds. 96 | * @default 60 97 | */ 98 | maxDuration?: number; 99 | /** 100 | * If true, enables console logging. 101 | * @default false 102 | */ 103 | verboseLogs?: boolean; 104 | /** 105 | * The base path to use for deriving endpoints. 106 | * If provided, endpoints will be derived from this path. 107 | * For example, if basePath is "/", that means your routing is: 108 | * /app/[transport]/route.ts and then: 109 | * - streamableHttpEndpoint will be "/mcp" 110 | * - sseEndpoint will be "/sse" 111 | * - sseMessageEndpoint will be "/message" 112 | * @default "" 113 | */ 114 | basePath?: string; 115 | /** 116 | * Callback function that receives MCP events. 117 | * This can be used to track analytics, debug issues, or implement custom behaviors. 118 | */ 119 | onEvent?: (event: McpEvent) => void; 120 | 121 | /** 122 | * If true, disables the SSE endpoint. 123 | * As of 2025-03-26, SSE is not supported by the MCP spec. 124 | * https://modelcontextprotocol.io/specification/2025-03-26/basic/transports 125 | * @default false 126 | */ 127 | disableSse?: boolean; 128 | }; 129 | 130 | /** 131 | * Derives MCP endpoints from a base path. 132 | * @param basePath - The base path to derive endpoints from 133 | * @returns An object containing the derived endpoints 134 | */ 135 | function deriveEndpointsFromBasePath(basePath: string): { 136 | streamableHttpEndpoint: string; 137 | sseEndpoint: string; 138 | sseMessageEndpoint: string; 139 | } { 140 | // Remove trailing slash if present 141 | const normalizedBasePath = basePath.replace(/\/$/, ""); 142 | 143 | return { 144 | streamableHttpEndpoint: `${normalizedBasePath}/mcp`, 145 | sseEndpoint: `${normalizedBasePath}/sse`, 146 | sseMessageEndpoint: `${normalizedBasePath}/message`, 147 | }; 148 | } 149 | /** 150 | * Calculates the endpoints for the MCP handler. 151 | * @param config - The configuration for the MCP handler. 152 | * @returns An object containing the endpoints for the MCP handler. 153 | */ 154 | export function calculateEndpoints({ 155 | basePath, 156 | streamableHttpEndpoint = "/mcp", 157 | sseEndpoint = "/sse", 158 | sseMessageEndpoint = "/message", 159 | }: Config) { 160 | const { 161 | streamableHttpEndpoint: fullStreamableHttpEndpoint, 162 | sseEndpoint: fullSseEndpoint, 163 | sseMessageEndpoint: fullSseMessageEndpoint, 164 | } = basePath != null 165 | ? deriveEndpointsFromBasePath(basePath) 166 | : { 167 | streamableHttpEndpoint, 168 | sseEndpoint, 169 | sseMessageEndpoint, 170 | }; 171 | 172 | return { 173 | streamableHttpEndpoint: fullStreamableHttpEndpoint, 174 | sseEndpoint: fullSseEndpoint, 175 | sseMessageEndpoint: fullSseMessageEndpoint, 176 | }; 177 | } 178 | 179 | let redisPublisher: ReturnType; 180 | let redis: ReturnType; 181 | 182 | // WeakMap to track server metadata without preventing GC 183 | const serverMetadata = new WeakMap(); 188 | 189 | // Periodic cleanup interval 190 | let cleanupInterval: NodeJS.Timeout | null = null; 191 | 192 | async function initializeRedis({ 193 | redisUrl, 194 | logger, 195 | }: { 196 | redisUrl?: string; 197 | logger: Logger; 198 | }) { 199 | if (redis && redisPublisher) { 200 | return { redis, redisPublisher }; 201 | } 202 | 203 | if (!redisUrl) { 204 | throw new Error("redisUrl is required"); 205 | } 206 | 207 | redis = createClient({ 208 | url: redisUrl, 209 | }); 210 | redisPublisher = createClient({ 211 | url: redisUrl, 212 | }); 213 | redis.on("error", (err) => { 214 | logger.error("Redis error", err); 215 | }); 216 | redisPublisher.on("error", (err) => { 217 | logger.error("Redis error", err); 218 | }); 219 | 220 | await Promise.all([redis.connect(), redisPublisher.connect()]); 221 | 222 | return { redis, redisPublisher }; 223 | } 224 | 225 | export function initializeMcpApiHandler( 226 | initializeServer: 227 | | ((server: McpServer) => Promise) 228 | | ((server: McpServer) => void), 229 | serverOptions: ServerOptions = {}, 230 | config: Config = { 231 | redisUrl: process.env.REDIS_URL || process.env.KV_URL, 232 | streamableHttpEndpoint: "/mcp", 233 | sseEndpoint: "/sse", 234 | sseMessageEndpoint: "/message", 235 | basePath: "", 236 | maxDuration: 60, 237 | verboseLogs: false, 238 | disableSse: false, 239 | } 240 | ) { 241 | const { 242 | redisUrl, 243 | basePath, 244 | streamableHttpEndpoint: explicitStreamableHttpEndpoint, 245 | sseEndpoint: explicitSseEndpoint, 246 | sseMessageEndpoint: explicitSseMessageEndpoint, 247 | maxDuration, 248 | verboseLogs, 249 | disableSse, 250 | } = config; 251 | 252 | const { 253 | serverInfo = { 254 | name: "mcp-typescript server on vercel", 255 | version: "0.1.0", 256 | }, 257 | ...mcpServerOptions 258 | } = serverOptions; 259 | 260 | // If basePath is provided, derive endpoints from it 261 | const { streamableHttpEndpoint, sseEndpoint, sseMessageEndpoint } = 262 | calculateEndpoints({ 263 | basePath, 264 | streamableHttpEndpoint: explicitStreamableHttpEndpoint, 265 | sseEndpoint: explicitSseEndpoint, 266 | sseMessageEndpoint: explicitSseMessageEndpoint, 267 | }); 268 | 269 | const logger = createLogger(verboseLogs); 270 | 271 | let servers: McpServer[] = []; 272 | 273 | let statelessServer: McpServer; 274 | const statelessTransport = new StreamableHTTPServerTransport({ 275 | sessionIdGenerator: undefined, 276 | }); 277 | 278 | // Start periodic cleanup if not already running 279 | if (!cleanupInterval) { 280 | cleanupInterval = setInterval(() => { 281 | const now = Date.now(); 282 | const staleThreshold = 5 * 60 * 1000; // 5 minutes 283 | 284 | servers = servers.filter(server => { 285 | const metadata = serverMetadata.get(server); 286 | if (!metadata) { 287 | // No metadata means the server is orphaned 288 | logger.log("Removing orphaned server without metadata"); 289 | try { 290 | if (server?.server) { 291 | server.server.close(); 292 | } 293 | } catch (error) { 294 | logger.error("Error closing orphaned server:", error); 295 | } 296 | return false; 297 | } 298 | 299 | const age = now - metadata.createdAt.getTime(); 300 | if (age > staleThreshold) { 301 | logger.log(`Removing stale server (session ${metadata.sessionId}, age: ${age}ms)`); 302 | try { 303 | if (server?.server) { 304 | server.server.close(); 305 | } 306 | if (metadata.transport?.close) { 307 | metadata.transport.close(); 308 | } 309 | } catch (error) { 310 | logger.error("Error closing stale server:", error); 311 | } 312 | serverMetadata.delete(server); 313 | return false; 314 | } 315 | 316 | return true; 317 | }); 318 | }, 30 * 1000); // Run every 30 seconds 319 | } 320 | 321 | return async function mcpApiHandler(req: Request, res: ServerResponse) { 322 | const url = new URL(req.url || "", "https://example.com"); 323 | if (url.pathname === streamableHttpEndpoint) { 324 | if (req.method === "GET") { 325 | logger.log("Received GET MCP request"); 326 | res.writeHead(405).end( 327 | JSON.stringify({ 328 | jsonrpc: "2.0", 329 | error: { 330 | code: -32000, 331 | message: "Method not allowed.", 332 | }, 333 | id: null, 334 | }) 335 | ); 336 | return; 337 | } 338 | if (req.method === "DELETE") { 339 | logger.log("Received DELETE MCP request"); 340 | res.writeHead(405).end( 341 | JSON.stringify({ 342 | jsonrpc: "2.0", 343 | error: { 344 | code: -32000, 345 | message: "Method not allowed.", 346 | }, 347 | id: null, 348 | }) 349 | ); 350 | return; 351 | } 352 | 353 | if (req.method === "POST") { 354 | const eventRes = new EventEmittingResponse( 355 | createFakeIncomingMessage(), 356 | config.onEvent 357 | ); 358 | 359 | if (!statelessServer) { 360 | statelessServer = new McpServer(serverInfo, mcpServerOptions); 361 | await initializeServer(statelessServer); 362 | await statelessServer.connect(statelessTransport); 363 | } 364 | 365 | // Parse the request body 366 | let bodyContent: BodyType; 367 | const contentType = req.headers.get("content-type") || ""; 368 | if (contentType.includes("application/json")) { 369 | bodyContent = await req.json(); 370 | } else { 371 | bodyContent = await req.text(); 372 | } 373 | 374 | const incomingRequest = createFakeIncomingMessage({ 375 | method: req.method, 376 | url: req.url, 377 | headers: Object.fromEntries(req.headers), 378 | body: bodyContent, 379 | auth: req.auth, // Use the auth info that should already be set by withMcpAuth 380 | }); 381 | 382 | // Create a response that will emit events 383 | const wrappedRes = new EventEmittingResponse( 384 | incomingRequest, 385 | config.onEvent 386 | ); 387 | Object.assign(wrappedRes, res); 388 | 389 | try { 390 | await statelessTransport.handleRequest(incomingRequest, wrappedRes); 391 | if ( 392 | typeof bodyContent === "object" && 393 | bodyContent && 394 | "method" in bodyContent 395 | ) { 396 | eventRes.requestCompleted( 397 | bodyContent.method as string, 398 | bodyContent 399 | ); 400 | } 401 | } catch (error) { 402 | if ( 403 | typeof bodyContent === "object" && 404 | bodyContent && 405 | "method" in bodyContent 406 | ) { 407 | eventRes.requestCompleted( 408 | bodyContent.method as string, 409 | undefined, 410 | error instanceof Error ? error : String(error) 411 | ); 412 | } 413 | throw error; 414 | } 415 | } 416 | } else if (url.pathname === sseEndpoint) { 417 | if (disableSse) { 418 | res.statusCode = 404; 419 | res.end("Not found"); 420 | return; 421 | } 422 | 423 | // Check HTTP method - only allow GET for SSE connections 424 | if (req.method !== "GET") { 425 | logger.log(`Rejected SSE connection with method ${req.method}`); 426 | res 427 | .writeHead(405, { "Content-Type": "text/plain" }) 428 | .end("Method Not Allowed"); 429 | return; 430 | } 431 | 432 | // Check that Accept header supports event-stream 433 | const acceptHeader = 434 | req.headers.get("accept") || req.headers.get("Accept"); 435 | if ( 436 | acceptHeader && 437 | !acceptHeader.includes("text/event-stream") && 438 | !acceptHeader.includes("*/*") && 439 | !acceptHeader.includes("text/*") 440 | ) { 441 | logger.log( 442 | `Rejected SSE connection with incompatible Accept header: ${acceptHeader}` 443 | ); 444 | res 445 | .writeHead(406, { "Content-Type": "text/plain" }) 446 | .end("Not Acceptable"); 447 | return; 448 | } 449 | 450 | const { redis, redisPublisher } = await initializeRedis({ 451 | redisUrl, 452 | logger, 453 | }); 454 | logger.log("Got new SSE connection"); 455 | assert(sseMessageEndpoint, "sseMessageEndpoint is required"); 456 | const transport = new SSEServerTransport(sseMessageEndpoint, res); 457 | const sessionId = transport.sessionId; 458 | 459 | const eventRes = new EventEmittingResponse( 460 | createFakeIncomingMessage(), 461 | config.onEvent, 462 | sessionId 463 | ); 464 | eventRes.startSession("SSE", { 465 | userAgent: req.headers.get("user-agent") ?? undefined, 466 | ip: 467 | req.headers.get("x-forwarded-for") ?? 468 | req.headers.get("x-real-ip") ?? 469 | undefined, 470 | }); 471 | 472 | const server = new McpServer(serverInfo, serverOptions); 473 | 474 | // Track cleanup state to prevent double cleanup 475 | let isCleanedUp = false; 476 | let interval: NodeJS.Timeout | null = null; 477 | let timeout: NodeJS.Timeout | null = null; 478 | let abortHandler: (() => void) | null = null; 479 | let handleMessage: ((message: string) => Promise) | null = null; 480 | let logs: { type: LogLevel; messages: string[]; }[] = []; 481 | 482 | // Comprehensive cleanup function 483 | const cleanup = async (reason: string) => { 484 | if (isCleanedUp) return; 485 | isCleanedUp = true; 486 | 487 | logger.log(`Cleaning up SSE connection: ${reason}`); 488 | 489 | // Clear timers 490 | if (timeout) { 491 | clearTimeout(timeout); 492 | timeout = null; 493 | } 494 | if (interval) { 495 | clearInterval(interval); 496 | interval = null; 497 | } 498 | 499 | // Remove abort event listener 500 | if (abortHandler) { 501 | req.signal.removeEventListener("abort", abortHandler); 502 | abortHandler = null; 503 | } 504 | 505 | // Unsubscribe from Redis 506 | if (handleMessage) { 507 | try { 508 | await redis.unsubscribe(`requests:${sessionId}`, handleMessage); 509 | logger.log(`Unsubscribed from requests:${sessionId}`); 510 | } catch (error) { 511 | logger.error("Error unsubscribing from Redis:", error); 512 | } 513 | } 514 | 515 | // Close server and transport 516 | try { 517 | if (server?.server) { 518 | await server.server.close(); 519 | } 520 | if (transport?.close) { 521 | await transport.close(); 522 | } 523 | } catch (error) { 524 | logger.error("Error closing server/transport:", error); 525 | } 526 | 527 | // Remove server from array and WeakMap 528 | servers = servers.filter((s) => s !== server); 529 | serverMetadata.delete(server); 530 | 531 | // End session event 532 | eventRes.endSession("SSE"); 533 | 534 | // Clear logs array to free memory 535 | logs = []; 536 | 537 | // End response if not already ended 538 | if (!res.headersSent) { 539 | res.statusCode = 200; 540 | res.end(); 541 | } 542 | }; 543 | 544 | try { 545 | await initializeServer(server); 546 | servers.push(server); 547 | 548 | // Store metadata in WeakMap 549 | serverMetadata.set(server, { 550 | sessionId, 551 | createdAt: new Date(), 552 | transport 553 | }); 554 | 555 | server.server.onclose = () => { 556 | cleanup("server closed"); 557 | }; 558 | 559 | // eslint-disable-next-line no-inner-declarations 560 | function logInContext(severity: LogLevel, ...messages: string[]) { 561 | logs.push({ 562 | type: severity, 563 | messages, 564 | }); 565 | } 566 | 567 | // Handles messages originally received via /message 568 | handleMessage = async (message: string) => { 569 | logger.log("Received message from Redis", message); 570 | logInContext("log", "Received message from Redis", message); 571 | const request = JSON.parse(message) as SerializedRequest; 572 | 573 | // Make in IncomingMessage object because that is what the SDK expects. 574 | const req = createFakeIncomingMessage({ 575 | method: request.method, 576 | url: request.url, 577 | headers: request.headers, 578 | body: request.body, 579 | }); 580 | 581 | const syntheticRes = new EventEmittingResponse( 582 | req, 583 | config.onEvent, 584 | sessionId 585 | ); 586 | let status = 100; 587 | let body = ""; 588 | syntheticRes.writeHead = (statusCode: number) => { 589 | status = statusCode; 590 | return syntheticRes; 591 | }; 592 | syntheticRes.end = (b: unknown) => { 593 | body = b as string; 594 | return syntheticRes; 595 | }; 596 | 597 | try { 598 | await transport.handlePostMessage(req, syntheticRes); 599 | 600 | // If it was a function call, complete it 601 | if ( 602 | typeof request.body === "object" && 603 | request.body && 604 | "method" in request.body 605 | ) { 606 | try { 607 | const result = JSON.parse(body); 608 | eventRes.requestCompleted(request.body.method as string, result); 609 | } catch { 610 | eventRes.requestCompleted(request.body.method as string, body); 611 | } 612 | } 613 | } catch (error) { 614 | eventRes.error( 615 | error instanceof Error ? error : String(error), 616 | "Error handling SSE message", 617 | "session" 618 | ); 619 | throw error; 620 | } 621 | 622 | await redisPublisher.publish( 623 | `responses:${sessionId}:${request.requestId}`, 624 | JSON.stringify({ 625 | status, 626 | body, 627 | }) 628 | ); 629 | 630 | if (status >= 200 && status < 300) { 631 | logInContext( 632 | "log", 633 | `Request ${sessionId}:${request.requestId} succeeded: ${body}` 634 | ); 635 | } else { 636 | logInContext( 637 | "error", 638 | `Message for ${sessionId}:${request.requestId} failed with status ${status}: ${body}` 639 | ); 640 | eventRes.error( 641 | `Request failed with status ${status}`, 642 | body, 643 | "session" 644 | ); 645 | } 646 | }; 647 | 648 | interval = setInterval(() => { 649 | for (const log of logs) { 650 | logger[log.type](...log.messages); 651 | } 652 | logs = []; 653 | }, 100); 654 | 655 | await redis.subscribe(`requests:${sessionId}`, handleMessage); 656 | logger.log(`Subscribed to requests:${sessionId}`); 657 | 658 | let resolveTimeout: (value: unknown) => void; 659 | const waitPromise = new Promise((resolve) => { 660 | resolveTimeout = resolve; 661 | timeout = setTimeout(() => { 662 | resolve("max duration reached"); 663 | }, (maxDuration ?? 60) * 1000); 664 | }); 665 | 666 | abortHandler = () => resolveTimeout("client hang up"); 667 | req.signal.addEventListener("abort", abortHandler); 668 | 669 | // Handle response close event 670 | res.on("close", () => { 671 | cleanup("response closed"); 672 | }); 673 | 674 | // Handle response error event 675 | res.on("error", (error) => { 676 | logger.error("Response error:", error); 677 | cleanup("response error"); 678 | }); 679 | 680 | await server.connect(transport); 681 | const closeReason = await waitPromise; 682 | logger.log(closeReason); 683 | await cleanup(String(closeReason)); 684 | } catch (error) { 685 | logger.error("Error in SSE handler:", error); 686 | await cleanup("error during setup"); 687 | throw error; 688 | } 689 | } else if (url.pathname === sseMessageEndpoint) { 690 | if (disableSse) { 691 | res.statusCode = 404; 692 | res.end("Not found"); 693 | return; 694 | } 695 | 696 | const { redis, redisPublisher } = await initializeRedis({ 697 | redisUrl, 698 | logger, 699 | }); 700 | logger.log("Received message"); 701 | 702 | const body = await req.text(); 703 | let parsedBody: BodyType; 704 | try { 705 | parsedBody = JSON.parse(body); 706 | } catch (e) { 707 | parsedBody = body; 708 | } 709 | 710 | const sessionId = url.searchParams.get("sessionId") || ""; 711 | if (!sessionId) { 712 | res.statusCode = 400; 713 | res.end("No sessionId provided"); 714 | return; 715 | } 716 | const requestId = crypto.randomUUID(); 717 | const serializedRequest: SerializedRequest = { 718 | requestId, 719 | url: req.url || "", 720 | method: req.method || "", 721 | body: parsedBody, 722 | headers: Object.fromEntries(req.headers.entries()), 723 | }; 724 | 725 | // Declare timeout and response handling state before subscription 726 | let timeout: NodeJS.Timeout | null = null; 727 | let hasResponded = false; 728 | let isCleanedUp = false; 729 | 730 | // Cleanup function to ensure all resources are freed 731 | const cleanup = async () => { 732 | if (isCleanedUp) return; 733 | isCleanedUp = true; 734 | 735 | if (timeout) { 736 | clearTimeout(timeout); 737 | timeout = null; 738 | } 739 | 740 | try { 741 | await redis.unsubscribe(`responses:${sessionId}:${requestId}`); 742 | } catch (error) { 743 | logger.error("Error unsubscribing from Redis response channel:", error); 744 | } 745 | }; 746 | 747 | // Safe response handler to prevent double res.end() 748 | const sendResponse = async (status: number, body: string) => { 749 | if (!hasResponded) { 750 | hasResponded = true; 751 | res.statusCode = status; 752 | res.end(body); 753 | await cleanup(); 754 | } 755 | }; 756 | 757 | // Response handler 758 | const handleResponse = async (message: string) => { 759 | try { 760 | const response = JSON.parse(message) as { 761 | status: number; 762 | body: string; 763 | }; 764 | await sendResponse(response.status, response.body); 765 | } catch (error) { 766 | logger.error("Failed to parse response message:", error); 767 | await sendResponse(500, "Internal server error"); 768 | } 769 | }; 770 | 771 | try { 772 | // Handles responses from the /sse endpoint. 773 | await redis.subscribe( 774 | `responses:${sessionId}:${requestId}`, 775 | handleResponse 776 | ); 777 | 778 | // Queue the request in Redis so that a subscriber can pick it up. 779 | // One queue per session. 780 | await redisPublisher.publish( 781 | `requests:${sessionId}`, 782 | JSON.stringify(serializedRequest) 783 | ); 784 | logger.log(`Published requests:${sessionId}`, serializedRequest); 785 | 786 | // Set timeout after subscription is established 787 | timeout = setTimeout(async () => { 788 | await sendResponse(408, "Request timed out"); 789 | }, 10 * 1000); 790 | 791 | // Handle response close event 792 | res.on("close", async () => { 793 | if (!hasResponded) { 794 | hasResponded = true; 795 | await cleanup(); 796 | } 797 | }); 798 | 799 | // Handle response error event 800 | res.on("error", async (error) => { 801 | logger.error("Response error in message handler:", error); 802 | if (!hasResponded) { 803 | hasResponded = true; 804 | await cleanup(); 805 | } 806 | }); 807 | } catch (error) { 808 | logger.error("Error in message handler:", error); 809 | await cleanup(); 810 | if (!hasResponded) { 811 | res.statusCode = 500; 812 | res.end("Internal server error"); 813 | } 814 | } 815 | } else { 816 | res.statusCode = 404; 817 | res.end("Not found"); 818 | } 819 | }; 820 | } 821 | 822 | // Define the options interface 823 | interface FakeIncomingMessageOptions { 824 | method?: string; 825 | url?: string; 826 | headers?: IncomingHttpHeaders; 827 | body?: BodyType; 828 | socket?: Socket; 829 | auth?: AuthInfo; 830 | } 831 | 832 | // Create a fake IncomingMessage 833 | function createFakeIncomingMessage( 834 | options: FakeIncomingMessageOptions = {} 835 | ): IncomingMessage & { auth?: AuthInfo } { 836 | const { 837 | method = "GET", 838 | url = "/", 839 | headers = {}, 840 | body = null, 841 | socket = new Socket(), 842 | } = options; 843 | 844 | // Create a readable stream that will be used as the base for IncomingMessage 845 | const readable = new Readable(); 846 | readable._read = (): void => {}; // Required implementation 847 | 848 | // Add the body content if provided 849 | if (body) { 850 | if (typeof body === "string") { 851 | readable.push(body); 852 | } else if (Buffer.isBuffer(body)) { 853 | readable.push(body); 854 | } else { 855 | // Ensure proper JSON-RPC format 856 | const bodyString = JSON.stringify(body); 857 | readable.push(bodyString); 858 | } 859 | readable.push(null); // Signal the end of the stream 860 | } else { 861 | readable.push(null); // Always end the stream even if no body 862 | } 863 | 864 | // Create the IncomingMessage instance 865 | const req = new IncomingMessage(socket) as IncomingMessage & { 866 | auth?: AuthInfo; 867 | }; 868 | 869 | // Set the properties 870 | req.method = method; 871 | req.url = url; 872 | req.headers = headers; 873 | 874 | const auth = options.auth || getAuthContext(); 875 | if (auth) { 876 | // See https://github.com/modelcontextprotocol/typescript-sdk/blob/590d4841373fc4eb86ecc9079834353a98cb84a3/src/server/auth/middleware/bearerAuth.ts#L71 for more info. 877 | (req as { auth?: AuthInfo }).auth = auth; 878 | } 879 | 880 | // Copy over the stream methods 881 | req.push = readable.push.bind(readable); 882 | req.read = readable.read.bind(readable); 883 | // @ts-expect-error 884 | req.on = readable.on.bind(readable); 885 | req.pipe = readable.pipe.bind(readable); 886 | 887 | return req; 888 | } 889 | -------------------------------------------------------------------------------- /pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '9.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | importers: 8 | 9 | .: 10 | dependencies: 11 | '@modelcontextprotocol/sdk': 12 | specifier: ^1.22.0 13 | version: 1.22.0 14 | chalk: 15 | specifier: ^5.3.0 16 | version: 5.4.1 17 | commander: 18 | specifier: ^11.1.0 19 | version: 11.1.0 20 | next: 21 | specifier: '>=13.0.0' 22 | version: 13.0.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) 23 | redis: 24 | specifier: ^4.6.0 25 | version: 4.6.0 26 | devDependencies: 27 | '@changesets/cli': 28 | specifier: ^2.27.12 29 | version: 2.29.4 30 | '@types/node': 31 | specifier: ^22.15.8 32 | version: 22.15.8 33 | tsup: 34 | specifier: ^8.0.0 35 | version: 8.0.0(postcss@8.5.4)(typescript@5.0.2) 36 | typescript: 37 | specifier: ^5.0.0 38 | version: 5.0.2 39 | vitest: 40 | specifier: ^3.2.1 41 | version: 3.2.1(@types/node@22.15.8)(yaml@2.8.0) 42 | zod: 43 | specifier: ^3.25.50 44 | version: 3.25.50 45 | 46 | packages: 47 | 48 | '@babel/runtime@7.27.1': 49 | resolution: {integrity: sha512-1x3D2xEk2fRo3PAhwQwu5UubzgiVWSXTBfWpVd2Mx2AzRqJuDJCsgaDVZ7HB5iGzDW1Hl1sWN2mFyKjmR9uAog==} 50 | engines: {node: '>=6.9.0'} 51 | 52 | '@changesets/apply-release-plan@7.0.12': 53 | resolution: {integrity: sha512-EaET7As5CeuhTzvXTQCRZeBUcisoYPDDcXvgTE/2jmmypKp0RC7LxKj/yzqeh/1qFTZI7oDGFcL1PHRuQuketQ==} 54 | 55 | '@changesets/assemble-release-plan@6.0.8': 56 | resolution: {integrity: sha512-y8+8LvZCkKJdbUlpXFuqcavpzJR80PN0OIfn8HZdwK7Sh6MgLXm4hKY5vu6/NDoKp8lAlM4ERZCqRMLxP4m+MQ==} 57 | 58 | '@changesets/changelog-git@0.2.1': 59 | resolution: {integrity: sha512-x/xEleCFLH28c3bQeQIyeZf8lFXyDFVn1SgcBiR2Tw/r4IAWlk1fzxCEZ6NxQAjF2Nwtczoen3OA2qR+UawQ8Q==} 60 | 61 | '@changesets/cli@2.29.4': 62 | resolution: {integrity: sha512-VW30x9oiFp/un/80+5jLeWgEU6Btj8IqOgI+X/zAYu4usVOWXjPIK5jSSlt5jsCU7/6Z7AxEkarxBxGUqkAmNg==} 63 | hasBin: true 64 | 65 | '@changesets/config@3.1.1': 66 | resolution: {integrity: sha512-bd+3Ap2TKXxljCggI0mKPfzCQKeV/TU4yO2h2C6vAihIo8tzseAn2e7klSuiyYYXvgu53zMN1OeYMIQkaQoWnA==} 67 | 68 | '@changesets/errors@0.2.0': 69 | resolution: {integrity: sha512-6BLOQUscTpZeGljvyQXlWOItQyU71kCdGz7Pi8H8zdw6BI0g3m43iL4xKUVPWtG+qrrL9DTjpdn8eYuCQSRpow==} 70 | 71 | '@changesets/get-dependents-graph@2.1.3': 72 | resolution: {integrity: sha512-gphr+v0mv2I3Oxt19VdWRRUxq3sseyUpX9DaHpTUmLj92Y10AGy+XOtV+kbM6L/fDcpx7/ISDFK6T8A/P3lOdQ==} 73 | 74 | '@changesets/get-release-plan@4.0.12': 75 | resolution: {integrity: sha512-KukdEgaafnyGryUwpHG2kZ7xJquOmWWWk5mmoeQaSvZTWH1DC5D/Sw6ClgGFYtQnOMSQhgoEbDxAbpIIayKH1g==} 76 | 77 | '@changesets/get-version-range-type@0.4.0': 78 | resolution: {integrity: sha512-hwawtob9DryoGTpixy1D3ZXbGgJu1Rhr+ySH2PvTLHvkZuQ7sRT4oQwMh0hbqZH1weAooedEjRsbrWcGLCeyVQ==} 79 | 80 | '@changesets/git@3.0.4': 81 | resolution: {integrity: sha512-BXANzRFkX+XcC1q/d27NKvlJ1yf7PSAgi8JG6dt8EfbHFHi4neau7mufcSca5zRhwOL8j9s6EqsxmT+s+/E6Sw==} 82 | 83 | '@changesets/logger@0.1.1': 84 | resolution: {integrity: sha512-OQtR36ZlnuTxKqoW4Sv6x5YIhOmClRd5pWsjZsddYxpWs517R0HkyiefQPIytCVh4ZcC5x9XaG8KTdd5iRQUfg==} 85 | 86 | '@changesets/parse@0.4.1': 87 | resolution: {integrity: sha512-iwksMs5Bf/wUItfcg+OXrEpravm5rEd9Bf4oyIPL4kVTmJQ7PNDSd6MDYkpSJR1pn7tz/k8Zf2DhTCqX08Ou+Q==} 88 | 89 | '@changesets/pre@2.0.2': 90 | resolution: {integrity: sha512-HaL/gEyFVvkf9KFg6484wR9s0qjAXlZ8qWPDkTyKF6+zqjBe/I2mygg3MbpZ++hdi0ToqNUF8cjj7fBy0dg8Ug==} 91 | 92 | '@changesets/read@0.6.5': 93 | resolution: {integrity: sha512-UPzNGhsSjHD3Veb0xO/MwvasGe8eMyNrR/sT9gR8Q3DhOQZirgKhhXv/8hVsI0QpPjR004Z9iFxoJU6in3uGMg==} 94 | 95 | '@changesets/should-skip-package@0.1.2': 96 | resolution: {integrity: sha512-qAK/WrqWLNCP22UDdBTMPH5f41elVDlsNyat180A33dWxuUDyNpg6fPi/FyTZwRriVjg0L8gnjJn2F9XAoF0qw==} 97 | 98 | '@changesets/types@4.1.0': 99 | resolution: {integrity: sha512-LDQvVDv5Kb50ny2s25Fhm3d9QSZimsoUGBsUioj6MC3qbMUCuC8GPIvk/M6IvXx3lYhAs0lwWUQLb+VIEUCECw==} 100 | 101 | '@changesets/types@6.1.0': 102 | resolution: {integrity: sha512-rKQcJ+o1nKNgeoYRHKOS07tAMNd3YSN0uHaJOZYjBAgxfV7TUE7JE+z4BzZdQwb5hKaYbayKN5KrYV7ODb2rAA==} 103 | 104 | '@changesets/write@0.4.0': 105 | resolution: {integrity: sha512-CdTLvIOPiCNuH71pyDu3rA+Q0n65cmAbXnwWH84rKGiFumFzkmHNT8KHTMEchcxN+Kl8I54xGUhJ7l3E7X396Q==} 106 | 107 | '@esbuild/aix-ppc64@0.19.12': 108 | resolution: {integrity: sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==} 109 | engines: {node: '>=12'} 110 | cpu: [ppc64] 111 | os: [aix] 112 | 113 | '@esbuild/aix-ppc64@0.25.5': 114 | resolution: {integrity: sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==} 115 | engines: {node: '>=18'} 116 | cpu: [ppc64] 117 | os: [aix] 118 | 119 | '@esbuild/android-arm64@0.19.12': 120 | resolution: {integrity: sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==} 121 | engines: {node: '>=12'} 122 | cpu: [arm64] 123 | os: [android] 124 | 125 | '@esbuild/android-arm64@0.25.5': 126 | resolution: {integrity: sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg==} 127 | engines: {node: '>=18'} 128 | cpu: [arm64] 129 | os: [android] 130 | 131 | '@esbuild/android-arm@0.19.12': 132 | resolution: {integrity: sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==} 133 | engines: {node: '>=12'} 134 | cpu: [arm] 135 | os: [android] 136 | 137 | '@esbuild/android-arm@0.25.5': 138 | resolution: {integrity: sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA==} 139 | engines: {node: '>=18'} 140 | cpu: [arm] 141 | os: [android] 142 | 143 | '@esbuild/android-x64@0.19.12': 144 | resolution: {integrity: sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==} 145 | engines: {node: '>=12'} 146 | cpu: [x64] 147 | os: [android] 148 | 149 | '@esbuild/android-x64@0.25.5': 150 | resolution: {integrity: sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw==} 151 | engines: {node: '>=18'} 152 | cpu: [x64] 153 | os: [android] 154 | 155 | '@esbuild/darwin-arm64@0.19.12': 156 | resolution: {integrity: sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==} 157 | engines: {node: '>=12'} 158 | cpu: [arm64] 159 | os: [darwin] 160 | 161 | '@esbuild/darwin-arm64@0.25.5': 162 | resolution: {integrity: sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ==} 163 | engines: {node: '>=18'} 164 | cpu: [arm64] 165 | os: [darwin] 166 | 167 | '@esbuild/darwin-x64@0.19.12': 168 | resolution: {integrity: sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==} 169 | engines: {node: '>=12'} 170 | cpu: [x64] 171 | os: [darwin] 172 | 173 | '@esbuild/darwin-x64@0.25.5': 174 | resolution: {integrity: sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ==} 175 | engines: {node: '>=18'} 176 | cpu: [x64] 177 | os: [darwin] 178 | 179 | '@esbuild/freebsd-arm64@0.19.12': 180 | resolution: {integrity: sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==} 181 | engines: {node: '>=12'} 182 | cpu: [arm64] 183 | os: [freebsd] 184 | 185 | '@esbuild/freebsd-arm64@0.25.5': 186 | resolution: {integrity: sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw==} 187 | engines: {node: '>=18'} 188 | cpu: [arm64] 189 | os: [freebsd] 190 | 191 | '@esbuild/freebsd-x64@0.19.12': 192 | resolution: {integrity: sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==} 193 | engines: {node: '>=12'} 194 | cpu: [x64] 195 | os: [freebsd] 196 | 197 | '@esbuild/freebsd-x64@0.25.5': 198 | resolution: {integrity: sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw==} 199 | engines: {node: '>=18'} 200 | cpu: [x64] 201 | os: [freebsd] 202 | 203 | '@esbuild/linux-arm64@0.19.12': 204 | resolution: {integrity: sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==} 205 | engines: {node: '>=12'} 206 | cpu: [arm64] 207 | os: [linux] 208 | 209 | '@esbuild/linux-arm64@0.25.5': 210 | resolution: {integrity: sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg==} 211 | engines: {node: '>=18'} 212 | cpu: [arm64] 213 | os: [linux] 214 | 215 | '@esbuild/linux-arm@0.19.12': 216 | resolution: {integrity: sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==} 217 | engines: {node: '>=12'} 218 | cpu: [arm] 219 | os: [linux] 220 | 221 | '@esbuild/linux-arm@0.25.5': 222 | resolution: {integrity: sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw==} 223 | engines: {node: '>=18'} 224 | cpu: [arm] 225 | os: [linux] 226 | 227 | '@esbuild/linux-ia32@0.19.12': 228 | resolution: {integrity: sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==} 229 | engines: {node: '>=12'} 230 | cpu: [ia32] 231 | os: [linux] 232 | 233 | '@esbuild/linux-ia32@0.25.5': 234 | resolution: {integrity: sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA==} 235 | engines: {node: '>=18'} 236 | cpu: [ia32] 237 | os: [linux] 238 | 239 | '@esbuild/linux-loong64@0.19.12': 240 | resolution: {integrity: sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==} 241 | engines: {node: '>=12'} 242 | cpu: [loong64] 243 | os: [linux] 244 | 245 | '@esbuild/linux-loong64@0.25.5': 246 | resolution: {integrity: sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg==} 247 | engines: {node: '>=18'} 248 | cpu: [loong64] 249 | os: [linux] 250 | 251 | '@esbuild/linux-mips64el@0.19.12': 252 | resolution: {integrity: sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==} 253 | engines: {node: '>=12'} 254 | cpu: [mips64el] 255 | os: [linux] 256 | 257 | '@esbuild/linux-mips64el@0.25.5': 258 | resolution: {integrity: sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg==} 259 | engines: {node: '>=18'} 260 | cpu: [mips64el] 261 | os: [linux] 262 | 263 | '@esbuild/linux-ppc64@0.19.12': 264 | resolution: {integrity: sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==} 265 | engines: {node: '>=12'} 266 | cpu: [ppc64] 267 | os: [linux] 268 | 269 | '@esbuild/linux-ppc64@0.25.5': 270 | resolution: {integrity: sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ==} 271 | engines: {node: '>=18'} 272 | cpu: [ppc64] 273 | os: [linux] 274 | 275 | '@esbuild/linux-riscv64@0.19.12': 276 | resolution: {integrity: sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==} 277 | engines: {node: '>=12'} 278 | cpu: [riscv64] 279 | os: [linux] 280 | 281 | '@esbuild/linux-riscv64@0.25.5': 282 | resolution: {integrity: sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA==} 283 | engines: {node: '>=18'} 284 | cpu: [riscv64] 285 | os: [linux] 286 | 287 | '@esbuild/linux-s390x@0.19.12': 288 | resolution: {integrity: sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==} 289 | engines: {node: '>=12'} 290 | cpu: [s390x] 291 | os: [linux] 292 | 293 | '@esbuild/linux-s390x@0.25.5': 294 | resolution: {integrity: sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ==} 295 | engines: {node: '>=18'} 296 | cpu: [s390x] 297 | os: [linux] 298 | 299 | '@esbuild/linux-x64@0.19.12': 300 | resolution: {integrity: sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==} 301 | engines: {node: '>=12'} 302 | cpu: [x64] 303 | os: [linux] 304 | 305 | '@esbuild/linux-x64@0.25.5': 306 | resolution: {integrity: sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw==} 307 | engines: {node: '>=18'} 308 | cpu: [x64] 309 | os: [linux] 310 | 311 | '@esbuild/netbsd-arm64@0.25.5': 312 | resolution: {integrity: sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw==} 313 | engines: {node: '>=18'} 314 | cpu: [arm64] 315 | os: [netbsd] 316 | 317 | '@esbuild/netbsd-x64@0.19.12': 318 | resolution: {integrity: sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==} 319 | engines: {node: '>=12'} 320 | cpu: [x64] 321 | os: [netbsd] 322 | 323 | '@esbuild/netbsd-x64@0.25.5': 324 | resolution: {integrity: sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ==} 325 | engines: {node: '>=18'} 326 | cpu: [x64] 327 | os: [netbsd] 328 | 329 | '@esbuild/openbsd-arm64@0.25.5': 330 | resolution: {integrity: sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw==} 331 | engines: {node: '>=18'} 332 | cpu: [arm64] 333 | os: [openbsd] 334 | 335 | '@esbuild/openbsd-x64@0.19.12': 336 | resolution: {integrity: sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==} 337 | engines: {node: '>=12'} 338 | cpu: [x64] 339 | os: [openbsd] 340 | 341 | '@esbuild/openbsd-x64@0.25.5': 342 | resolution: {integrity: sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg==} 343 | engines: {node: '>=18'} 344 | cpu: [x64] 345 | os: [openbsd] 346 | 347 | '@esbuild/sunos-x64@0.19.12': 348 | resolution: {integrity: sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==} 349 | engines: {node: '>=12'} 350 | cpu: [x64] 351 | os: [sunos] 352 | 353 | '@esbuild/sunos-x64@0.25.5': 354 | resolution: {integrity: sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA==} 355 | engines: {node: '>=18'} 356 | cpu: [x64] 357 | os: [sunos] 358 | 359 | '@esbuild/win32-arm64@0.19.12': 360 | resolution: {integrity: sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==} 361 | engines: {node: '>=12'} 362 | cpu: [arm64] 363 | os: [win32] 364 | 365 | '@esbuild/win32-arm64@0.25.5': 366 | resolution: {integrity: sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw==} 367 | engines: {node: '>=18'} 368 | cpu: [arm64] 369 | os: [win32] 370 | 371 | '@esbuild/win32-ia32@0.19.12': 372 | resolution: {integrity: sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==} 373 | engines: {node: '>=12'} 374 | cpu: [ia32] 375 | os: [win32] 376 | 377 | '@esbuild/win32-ia32@0.25.5': 378 | resolution: {integrity: sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ==} 379 | engines: {node: '>=18'} 380 | cpu: [ia32] 381 | os: [win32] 382 | 383 | '@esbuild/win32-x64@0.19.12': 384 | resolution: {integrity: sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==} 385 | engines: {node: '>=12'} 386 | cpu: [x64] 387 | os: [win32] 388 | 389 | '@esbuild/win32-x64@0.25.5': 390 | resolution: {integrity: sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g==} 391 | engines: {node: '>=18'} 392 | cpu: [x64] 393 | os: [win32] 394 | 395 | '@isaacs/cliui@8.0.2': 396 | resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} 397 | engines: {node: '>=12'} 398 | 399 | '@jridgewell/gen-mapping@0.3.8': 400 | resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==} 401 | engines: {node: '>=6.0.0'} 402 | 403 | '@jridgewell/resolve-uri@3.1.2': 404 | resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} 405 | engines: {node: '>=6.0.0'} 406 | 407 | '@jridgewell/set-array@1.2.1': 408 | resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} 409 | engines: {node: '>=6.0.0'} 410 | 411 | '@jridgewell/sourcemap-codec@1.5.0': 412 | resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} 413 | 414 | '@jridgewell/trace-mapping@0.3.25': 415 | resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} 416 | 417 | '@manypkg/find-root@1.1.0': 418 | resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==} 419 | 420 | '@manypkg/get-packages@1.1.3': 421 | resolution: {integrity: sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A==} 422 | 423 | '@modelcontextprotocol/sdk@1.22.0': 424 | resolution: {integrity: sha512-VUpl106XVTCpDmTBil2ehgJZjhyLY2QZikzF8NvTXtLRF1CvO5iEE2UNZdVIUer35vFOwMKYeUGbjJtvPWan3g==} 425 | engines: {node: '>=18'} 426 | peerDependencies: 427 | '@cfworker/json-schema': ^4.1.1 428 | peerDependenciesMeta: 429 | '@cfworker/json-schema': 430 | optional: true 431 | 432 | '@next/env@13.0.0': 433 | resolution: {integrity: sha512-65v9BVuah2Mplohm4+efsKEnoEuhmlGm8B2w6vD1geeEP2wXtlSJCvR/cCRJ3fD8wzCQBV41VcMBQeYET6MRkg==} 434 | 435 | '@next/swc-android-arm-eabi@13.0.0': 436 | resolution: {integrity: sha512-+DUQkYF93gxFjWY+CYWE1QDX6gTgnUiWf+W4UqZjM1Jcef8U97fS6xYh+i+8rH4MM0AXHm7OSakvfOMzmjU6VA==} 437 | engines: {node: '>= 10'} 438 | cpu: [arm] 439 | os: [android] 440 | 441 | '@next/swc-android-arm64@13.0.0': 442 | resolution: {integrity: sha512-RW9Uy3bMSc0zVGCa11klFuwfP/jdcdkhdruqnrJ7v+7XHm6OFKkSRzX6ee7yGR1rdDZvTnP4GZSRSpzjLv/N0g==} 443 | engines: {node: '>= 10'} 444 | cpu: [arm64] 445 | os: [android] 446 | 447 | '@next/swc-darwin-arm64@13.0.0': 448 | resolution: {integrity: sha512-APA26nps1j4qyhOIzkclW/OmgotVHj1jBxebSpMCPw2rXfiNvKNY9FA0TcuwPmUCNqaTnm703h6oW4dvp73A4Q==} 449 | engines: {node: '>= 10'} 450 | cpu: [arm64] 451 | os: [darwin] 452 | 453 | '@next/swc-darwin-x64@13.0.0': 454 | resolution: {integrity: sha512-qsUhUdoFuRJiaJ7LnvTQ6GZv1QnMDcRXCIjxaN0FNVXwrjkq++U7KjBUaxXkRzLV4C7u0NHLNOp0iZwNNE7ypw==} 455 | engines: {node: '>= 10'} 456 | cpu: [x64] 457 | os: [darwin] 458 | 459 | '@next/swc-freebsd-x64@13.0.0': 460 | resolution: {integrity: sha512-sCdyCbboS7CwdnevKH9J6hkJI76LUw1jVWt4eV7kISuLiPba3JmehZSWm80oa4ADChRVAwzhLAo2zJaYRrInbg==} 461 | engines: {node: '>= 10'} 462 | cpu: [x64] 463 | os: [freebsd] 464 | 465 | '@next/swc-linux-arm-gnueabihf@13.0.0': 466 | resolution: {integrity: sha512-/X/VxfFA41C9jrEv+sUsPLQ5vbDPVIgG0CJrzKvrcc+b+4zIgPgtfsaWq9ockjHFQi3ycvlZK4TALOXO8ovQ6Q==} 467 | engines: {node: '>= 10'} 468 | cpu: [arm] 469 | os: [linux] 470 | 471 | '@next/swc-linux-arm64-gnu@13.0.0': 472 | resolution: {integrity: sha512-x6Oxr1GIi0ZtNiT6jbw+JVcbEi3UQgF7mMmkrgfL4mfchOwXtWSHKTSSPnwoJWJfXYa0Vy1n8NElWNTGAqoWFw==} 473 | engines: {node: '>= 10'} 474 | cpu: [arm64] 475 | os: [linux] 476 | 477 | '@next/swc-linux-arm64-musl@13.0.0': 478 | resolution: {integrity: sha512-SnMH9ngI+ipGh3kqQ8+mDtWunirwmhQnQeZkEq9e/9Xsgjf04OetqrqRHKM1HmJtG2qMUJbyXFJ0F81TPuT+3g==} 479 | engines: {node: '>= 10'} 480 | cpu: [arm64] 481 | os: [linux] 482 | 483 | '@next/swc-linux-x64-gnu@13.0.0': 484 | resolution: {integrity: sha512-VSQwTX9EmdbotArtA1J67X8964oQfe0xHb32x4tu+JqTR+wOHyG6wGzPMdXH2oKAp6rdd7BzqxUXXf0J+ypHlw==} 485 | engines: {node: '>= 10'} 486 | cpu: [x64] 487 | os: [linux] 488 | 489 | '@next/swc-linux-x64-musl@13.0.0': 490 | resolution: {integrity: sha512-xBCP0nnpO0q4tsytXkvIwWFINtbFRyVY5gxa1zB0vlFtqYR9lNhrOwH3CBrks3kkeaePOXd611+8sjdUtrLnXA==} 491 | engines: {node: '>= 10'} 492 | cpu: [x64] 493 | os: [linux] 494 | 495 | '@next/swc-win32-arm64-msvc@13.0.0': 496 | resolution: {integrity: sha512-NutwDafqhGxqPj/eiUixJq9ImS/0sgx6gqlD7jRndCvQ2Q8AvDdu1+xKcGWGNnhcDsNM/n1avf1e62OG1GaqJg==} 497 | engines: {node: '>= 10'} 498 | cpu: [arm64] 499 | os: [win32] 500 | 501 | '@next/swc-win32-ia32-msvc@13.0.0': 502 | resolution: {integrity: sha512-zNaxaO+Kl/xNz02E9QlcVz0pT4MjkXGDLb25qxtAzyJL15aU0+VjjbIZAYWctG59dvggNIUNDWgoBeVTKB9xLg==} 503 | engines: {node: '>= 10'} 504 | cpu: [ia32] 505 | os: [win32] 506 | 507 | '@next/swc-win32-x64-msvc@13.0.0': 508 | resolution: {integrity: sha512-FFOGGWwTCRMu9W7MF496Urefxtuo2lttxF1vwS+1rIRsKvuLrWhVaVTj3T8sf2EBL6gtJbmh4TYlizS+obnGKA==} 509 | engines: {node: '>= 10'} 510 | cpu: [x64] 511 | os: [win32] 512 | 513 | '@nodelib/fs.scandir@2.1.5': 514 | resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} 515 | engines: {node: '>= 8'} 516 | 517 | '@nodelib/fs.stat@2.0.5': 518 | resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} 519 | engines: {node: '>= 8'} 520 | 521 | '@nodelib/fs.walk@1.2.8': 522 | resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} 523 | engines: {node: '>= 8'} 524 | 525 | '@pkgjs/parseargs@0.11.0': 526 | resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} 527 | engines: {node: '>=14'} 528 | 529 | '@redis/bloom@1.2.0': 530 | resolution: {integrity: sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==} 531 | peerDependencies: 532 | '@redis/client': ^1.0.0 533 | 534 | '@redis/client@1.5.0': 535 | resolution: {integrity: sha512-MafrVNQ5LSnii1yYIlzjbz3i6Bw8c9RZkV3g7jNd3As/A1vo6UIn0+29ii631oKxIA+nAEMeACh6+9k9+iup1A==} 536 | engines: {node: '>=14'} 537 | 538 | '@redis/graph@1.1.0': 539 | resolution: {integrity: sha512-16yZWngxyXPd+MJxeSr0dqh2AIOi8j9yXKcKCwVaKDbH3HTuETpDVPcLujhFYVPtYrngSco31BUcSa9TH31Gqg==} 540 | peerDependencies: 541 | '@redis/client': ^1.0.0 542 | 543 | '@redis/json@1.0.4': 544 | resolution: {integrity: sha512-LUZE2Gdrhg0Rx7AN+cZkb1e6HjoSKaeeW8rYnt89Tly13GBI5eP4CwDVr+MY8BAYfCg4/N15OUrtLoona9uSgw==} 545 | peerDependencies: 546 | '@redis/client': ^1.0.0 547 | 548 | '@redis/search@1.1.1': 549 | resolution: {integrity: sha512-pqCXTc5e7wJJgUuJiC3hBgfoFRoPxYzwn0BEfKgejTM7M/9zP3IpUcqcjgfp8hF+LoV8rHZzcNTz7V+pEIY7LQ==} 550 | peerDependencies: 551 | '@redis/client': ^1.0.0 552 | 553 | '@redis/time-series@1.0.4': 554 | resolution: {integrity: sha512-ThUIgo2U/g7cCuZavucQTQzA9g9JbDDY2f64u3AbAoz/8vE2lt2U37LamDUVChhaDA3IRT9R6VvJwqnUfTJzng==} 555 | peerDependencies: 556 | '@redis/client': ^1.0.0 557 | 558 | '@rollup/rollup-android-arm-eabi@4.40.2': 559 | resolution: {integrity: sha512-JkdNEq+DFxZfUwxvB58tHMHBHVgX23ew41g1OQinthJ+ryhdRk67O31S7sYw8u2lTjHUPFxwar07BBt1KHp/hg==} 560 | cpu: [arm] 561 | os: [android] 562 | 563 | '@rollup/rollup-android-arm64@4.40.2': 564 | resolution: {integrity: sha512-13unNoZ8NzUmnndhPTkWPWbX3vtHodYmy+I9kuLxN+F+l+x3LdVF7UCu8TWVMt1POHLh6oDHhnOA04n8oJZhBw==} 565 | cpu: [arm64] 566 | os: [android] 567 | 568 | '@rollup/rollup-darwin-arm64@4.40.2': 569 | resolution: {integrity: sha512-Gzf1Hn2Aoe8VZzevHostPX23U7N5+4D36WJNHK88NZHCJr7aVMG4fadqkIf72eqVPGjGc0HJHNuUaUcxiR+N/w==} 570 | cpu: [arm64] 571 | os: [darwin] 572 | 573 | '@rollup/rollup-darwin-x64@4.40.2': 574 | resolution: {integrity: sha512-47N4hxa01a4x6XnJoskMKTS8XZ0CZMd8YTbINbi+w03A2w4j1RTlnGHOz/P0+Bg1LaVL6ufZyNprSg+fW5nYQQ==} 575 | cpu: [x64] 576 | os: [darwin] 577 | 578 | '@rollup/rollup-freebsd-arm64@4.40.2': 579 | resolution: {integrity: sha512-8t6aL4MD+rXSHHZUR1z19+9OFJ2rl1wGKvckN47XFRVO+QL/dUSpKA2SLRo4vMg7ELA8pzGpC+W9OEd1Z/ZqoQ==} 580 | cpu: [arm64] 581 | os: [freebsd] 582 | 583 | '@rollup/rollup-freebsd-x64@4.40.2': 584 | resolution: {integrity: sha512-C+AyHBzfpsOEYRFjztcYUFsH4S7UsE9cDtHCtma5BK8+ydOZYgMmWg1d/4KBytQspJCld8ZIujFMAdKG1xyr4Q==} 585 | cpu: [x64] 586 | os: [freebsd] 587 | 588 | '@rollup/rollup-linux-arm-gnueabihf@4.40.2': 589 | resolution: {integrity: sha512-de6TFZYIvJwRNjmW3+gaXiZ2DaWL5D5yGmSYzkdzjBDS3W+B9JQ48oZEsmMvemqjtAFzE16DIBLqd6IQQRuG9Q==} 590 | cpu: [arm] 591 | os: [linux] 592 | 593 | '@rollup/rollup-linux-arm-musleabihf@4.40.2': 594 | resolution: {integrity: sha512-urjaEZubdIkacKc930hUDOfQPysezKla/O9qV+O89enqsqUmQm8Xj8O/vh0gHg4LYfv7Y7UsE3QjzLQzDYN1qg==} 595 | cpu: [arm] 596 | os: [linux] 597 | 598 | '@rollup/rollup-linux-arm64-gnu@4.40.2': 599 | resolution: {integrity: sha512-KlE8IC0HFOC33taNt1zR8qNlBYHj31qGT1UqWqtvR/+NuCVhfufAq9fxO8BMFC22Wu0rxOwGVWxtCMvZVLmhQg==} 600 | cpu: [arm64] 601 | os: [linux] 602 | 603 | '@rollup/rollup-linux-arm64-musl@4.40.2': 604 | resolution: {integrity: sha512-j8CgxvfM0kbnhu4XgjnCWJQyyBOeBI1Zq91Z850aUddUmPeQvuAy6OiMdPS46gNFgy8gN1xkYyLgwLYZG3rBOg==} 605 | cpu: [arm64] 606 | os: [linux] 607 | 608 | '@rollup/rollup-linux-loongarch64-gnu@4.40.2': 609 | resolution: {integrity: sha512-Ybc/1qUampKuRF4tQXc7G7QY9YRyeVSykfK36Y5Qc5dmrIxwFhrOzqaVTNoZygqZ1ZieSWTibfFhQ5qK8jpWxw==} 610 | cpu: [loong64] 611 | os: [linux] 612 | 613 | '@rollup/rollup-linux-powerpc64le-gnu@4.40.2': 614 | resolution: {integrity: sha512-3FCIrnrt03CCsZqSYAOW/k9n625pjpuMzVfeI+ZBUSDT3MVIFDSPfSUgIl9FqUftxcUXInvFah79hE1c9abD+Q==} 615 | cpu: [ppc64] 616 | os: [linux] 617 | 618 | '@rollup/rollup-linux-riscv64-gnu@4.40.2': 619 | resolution: {integrity: sha512-QNU7BFHEvHMp2ESSY3SozIkBPaPBDTsfVNGx3Xhv+TdvWXFGOSH2NJvhD1zKAT6AyuuErJgbdvaJhYVhVqrWTg==} 620 | cpu: [riscv64] 621 | os: [linux] 622 | 623 | '@rollup/rollup-linux-riscv64-musl@4.40.2': 624 | resolution: {integrity: sha512-5W6vNYkhgfh7URiXTO1E9a0cy4fSgfE4+Hl5agb/U1sa0kjOLMLC1wObxwKxecE17j0URxuTrYZZME4/VH57Hg==} 625 | cpu: [riscv64] 626 | os: [linux] 627 | 628 | '@rollup/rollup-linux-s390x-gnu@4.40.2': 629 | resolution: {integrity: sha512-B7LKIz+0+p348JoAL4X/YxGx9zOx3sR+o6Hj15Y3aaApNfAshK8+mWZEf759DXfRLeL2vg5LYJBB7DdcleYCoQ==} 630 | cpu: [s390x] 631 | os: [linux] 632 | 633 | '@rollup/rollup-linux-x64-gnu@4.40.2': 634 | resolution: {integrity: sha512-lG7Xa+BmBNwpjmVUbmyKxdQJ3Q6whHjMjzQplOs5Z+Gj7mxPtWakGHqzMqNER68G67kmCX9qX57aRsW5V0VOng==} 635 | cpu: [x64] 636 | os: [linux] 637 | 638 | '@rollup/rollup-linux-x64-musl@4.40.2': 639 | resolution: {integrity: sha512-tD46wKHd+KJvsmije4bUskNuvWKFcTOIM9tZ/RrmIvcXnbi0YK/cKS9FzFtAm7Oxi2EhV5N2OpfFB348vSQRXA==} 640 | cpu: [x64] 641 | os: [linux] 642 | 643 | '@rollup/rollup-win32-arm64-msvc@4.40.2': 644 | resolution: {integrity: sha512-Bjv/HG8RRWLNkXwQQemdsWw4Mg+IJ29LK+bJPW2SCzPKOUaMmPEppQlu/Fqk1d7+DX3V7JbFdbkh/NMmurT6Pg==} 645 | cpu: [arm64] 646 | os: [win32] 647 | 648 | '@rollup/rollup-win32-ia32-msvc@4.40.2': 649 | resolution: {integrity: sha512-dt1llVSGEsGKvzeIO76HToiYPNPYPkmjhMHhP00T9S4rDern8P2ZWvWAQUEJ+R1UdMWJ/42i/QqJ2WV765GZcA==} 650 | cpu: [ia32] 651 | os: [win32] 652 | 653 | '@rollup/rollup-win32-x64-msvc@4.40.2': 654 | resolution: {integrity: sha512-bwspbWB04XJpeElvsp+DCylKfF4trJDa2Y9Go8O6A7YLX2LIKGcNK/CYImJN6ZP4DcuOHB4Utl3iCbnR62DudA==} 655 | cpu: [x64] 656 | os: [win32] 657 | 658 | '@swc/helpers@0.4.11': 659 | resolution: {integrity: sha512-rEUrBSGIoSFuYxwBYtlUFMlE2CwGhmW+w9355/5oduSw8e5h2+Tj4UrAGNNgP9915++wj5vkQo0UuOBqOAq4nw==} 660 | 661 | '@types/chai@5.2.2': 662 | resolution: {integrity: sha512-8kB30R7Hwqf40JPiKhVzodJs2Qc1ZJ5zuT3uzw5Hq/dhNCl3G3l83jfpdI1e20BP348+fV7VIL/+FxaXkqBmWg==} 663 | 664 | '@types/deep-eql@4.0.2': 665 | resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} 666 | 667 | '@types/estree@1.0.7': 668 | resolution: {integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==} 669 | 670 | '@types/node@12.20.55': 671 | resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} 672 | 673 | '@types/node@22.15.8': 674 | resolution: {integrity: sha512-VINDWfc4C3DGAa1J+riYRHjzt+IFj5eRaEl768ze7ZqXcjyN/4WHxPLAWMLTwmODpPvFyzuMTAT6A4RMOHlg5g==} 675 | 676 | '@vitest/expect@3.2.1': 677 | resolution: {integrity: sha512-FqS/BnDOzV6+IpxrTg5GQRyLOCtcJqkwMwcS8qGCI2IyRVDwPAtutztaf1CjtPHlZlWtl1yUPCd7HM0cNiDOYw==} 678 | 679 | '@vitest/mocker@3.2.1': 680 | resolution: {integrity: sha512-OXxMJnx1lkB+Vl65Re5BrsZEHc90s5NMjD23ZQ9NlU7f7nZiETGoX4NeKZSmsKjseuMq2uOYXdLOeoM0pJU+qw==} 681 | peerDependencies: 682 | msw: ^2.4.9 683 | vite: ^5.0.0 || ^6.0.0 || ^7.0.0-0 684 | peerDependenciesMeta: 685 | msw: 686 | optional: true 687 | vite: 688 | optional: true 689 | 690 | '@vitest/pretty-format@3.2.1': 691 | resolution: {integrity: sha512-xBh1X2GPlOGBupp6E1RcUQWIxw0w/hRLd3XyBS6H+dMdKTAqHDNsIR2AnJwPA3yYe9DFy3VUKTe3VRTrAiQ01g==} 692 | 693 | '@vitest/runner@3.2.1': 694 | resolution: {integrity: sha512-kygXhNTu/wkMYbwYpS3z/9tBe0O8qpdBuC3dD/AW9sWa0LE/DAZEjnHtWA9sIad7lpD4nFW1yQ+zN7mEKNH3yA==} 695 | 696 | '@vitest/snapshot@3.2.1': 697 | resolution: {integrity: sha512-5xko/ZpW2Yc65NVK9Gpfg2y4BFvcF+At7yRT5AHUpTg9JvZ4xZoyuRY4ASlmNcBZjMslV08VRLDrBOmUe2YX3g==} 698 | 699 | '@vitest/spy@3.2.1': 700 | resolution: {integrity: sha512-Nbfib34Z2rfcJGSetMxjDCznn4pCYPZOtQYox2kzebIJcgH75yheIKd5QYSFmR8DIZf2M8fwOm66qSDIfRFFfQ==} 701 | 702 | '@vitest/utils@3.2.1': 703 | resolution: {integrity: sha512-KkHlGhePEKZSub5ViknBcN5KEF+u7dSUr9NW8QsVICusUojrgrOnnY3DEWWO877ax2Pyopuk2qHmt+gkNKnBVw==} 704 | 705 | accepts@2.0.0: 706 | resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} 707 | engines: {node: '>= 0.6'} 708 | 709 | ajv-formats@3.0.1: 710 | resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} 711 | peerDependencies: 712 | ajv: ^8.0.0 713 | peerDependenciesMeta: 714 | ajv: 715 | optional: true 716 | 717 | ajv@8.17.1: 718 | resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} 719 | 720 | ansi-colors@4.1.3: 721 | resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} 722 | engines: {node: '>=6'} 723 | 724 | ansi-regex@5.0.1: 725 | resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} 726 | engines: {node: '>=8'} 727 | 728 | ansi-regex@6.1.0: 729 | resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} 730 | engines: {node: '>=12'} 731 | 732 | ansi-styles@4.3.0: 733 | resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} 734 | engines: {node: '>=8'} 735 | 736 | ansi-styles@6.2.1: 737 | resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} 738 | engines: {node: '>=12'} 739 | 740 | any-promise@1.3.0: 741 | resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} 742 | 743 | anymatch@3.1.3: 744 | resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} 745 | engines: {node: '>= 8'} 746 | 747 | argparse@1.0.10: 748 | resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} 749 | 750 | array-union@2.1.0: 751 | resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} 752 | engines: {node: '>=8'} 753 | 754 | assertion-error@2.0.1: 755 | resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} 756 | engines: {node: '>=12'} 757 | 758 | balanced-match@1.0.2: 759 | resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} 760 | 761 | better-path-resolve@1.0.0: 762 | resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==} 763 | engines: {node: '>=4'} 764 | 765 | binary-extensions@2.3.0: 766 | resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} 767 | engines: {node: '>=8'} 768 | 769 | body-parser@2.2.0: 770 | resolution: {integrity: sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==} 771 | engines: {node: '>=18'} 772 | 773 | brace-expansion@2.0.1: 774 | resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} 775 | 776 | braces@3.0.3: 777 | resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} 778 | engines: {node: '>=8'} 779 | 780 | bundle-require@4.2.1: 781 | resolution: {integrity: sha512-7Q/6vkyYAwOmQNRw75x+4yRtZCZJXUDmHHlFdkiV0wgv/reNjtJwpu1jPJ0w2kbEpIM0uoKI3S4/f39dU7AjSA==} 782 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 783 | peerDependencies: 784 | esbuild: '>=0.17' 785 | 786 | bytes@3.1.2: 787 | resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} 788 | engines: {node: '>= 0.8'} 789 | 790 | cac@6.7.14: 791 | resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} 792 | engines: {node: '>=8'} 793 | 794 | call-bind-apply-helpers@1.0.2: 795 | resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} 796 | engines: {node: '>= 0.4'} 797 | 798 | call-bound@1.0.4: 799 | resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} 800 | engines: {node: '>= 0.4'} 801 | 802 | caniuse-lite@1.0.30001718: 803 | resolution: {integrity: sha512-AflseV1ahcSunK53NfEs9gFWgOEmzr0f+kaMFA4xiLZlr9Hzt7HxcSpIFcnNCUkz6R6dWKa54rUz3HUmI3nVcw==} 804 | 805 | chai@5.2.0: 806 | resolution: {integrity: sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==} 807 | engines: {node: '>=12'} 808 | 809 | chalk@5.4.1: 810 | resolution: {integrity: sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==} 811 | engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} 812 | 813 | chardet@0.7.0: 814 | resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==} 815 | 816 | check-error@2.1.1: 817 | resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} 818 | engines: {node: '>= 16'} 819 | 820 | chokidar@3.6.0: 821 | resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} 822 | engines: {node: '>= 8.10.0'} 823 | 824 | ci-info@3.9.0: 825 | resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} 826 | engines: {node: '>=8'} 827 | 828 | client-only@0.0.1: 829 | resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} 830 | 831 | cluster-key-slot@1.1.2: 832 | resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==} 833 | engines: {node: '>=0.10.0'} 834 | 835 | color-convert@2.0.1: 836 | resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} 837 | engines: {node: '>=7.0.0'} 838 | 839 | color-name@1.1.4: 840 | resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} 841 | 842 | commander@11.1.0: 843 | resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} 844 | engines: {node: '>=16'} 845 | 846 | commander@4.1.1: 847 | resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} 848 | engines: {node: '>= 6'} 849 | 850 | content-disposition@1.0.0: 851 | resolution: {integrity: sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==} 852 | engines: {node: '>= 0.6'} 853 | 854 | content-type@1.0.5: 855 | resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} 856 | engines: {node: '>= 0.6'} 857 | 858 | cookie-signature@1.2.2: 859 | resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} 860 | engines: {node: '>=6.6.0'} 861 | 862 | cookie@0.7.2: 863 | resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} 864 | engines: {node: '>= 0.6'} 865 | 866 | cors@2.8.5: 867 | resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==} 868 | engines: {node: '>= 0.10'} 869 | 870 | cross-spawn@7.0.6: 871 | resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} 872 | engines: {node: '>= 8'} 873 | 874 | debug@4.4.1: 875 | resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==} 876 | engines: {node: '>=6.0'} 877 | peerDependencies: 878 | supports-color: '*' 879 | peerDependenciesMeta: 880 | supports-color: 881 | optional: true 882 | 883 | deep-eql@5.0.2: 884 | resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} 885 | engines: {node: '>=6'} 886 | 887 | depd@2.0.0: 888 | resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} 889 | engines: {node: '>= 0.8'} 890 | 891 | detect-indent@6.1.0: 892 | resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} 893 | engines: {node: '>=8'} 894 | 895 | dir-glob@3.0.1: 896 | resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} 897 | engines: {node: '>=8'} 898 | 899 | dunder-proto@1.0.1: 900 | resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} 901 | engines: {node: '>= 0.4'} 902 | 903 | eastasianwidth@0.2.0: 904 | resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} 905 | 906 | ee-first@1.1.1: 907 | resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} 908 | 909 | emoji-regex@8.0.0: 910 | resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} 911 | 912 | emoji-regex@9.2.2: 913 | resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} 914 | 915 | encodeurl@2.0.0: 916 | resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} 917 | engines: {node: '>= 0.8'} 918 | 919 | enquirer@2.4.1: 920 | resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} 921 | engines: {node: '>=8.6'} 922 | 923 | es-define-property@1.0.1: 924 | resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} 925 | engines: {node: '>= 0.4'} 926 | 927 | es-errors@1.3.0: 928 | resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} 929 | engines: {node: '>= 0.4'} 930 | 931 | es-module-lexer@1.7.0: 932 | resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} 933 | 934 | es-object-atoms@1.1.1: 935 | resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} 936 | engines: {node: '>= 0.4'} 937 | 938 | esbuild@0.19.12: 939 | resolution: {integrity: sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==} 940 | engines: {node: '>=12'} 941 | hasBin: true 942 | 943 | esbuild@0.25.5: 944 | resolution: {integrity: sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ==} 945 | engines: {node: '>=18'} 946 | hasBin: true 947 | 948 | escape-html@1.0.3: 949 | resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} 950 | 951 | esprima@4.0.1: 952 | resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} 953 | engines: {node: '>=4'} 954 | hasBin: true 955 | 956 | estree-walker@3.0.3: 957 | resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} 958 | 959 | etag@1.8.1: 960 | resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} 961 | engines: {node: '>= 0.6'} 962 | 963 | eventsource-parser@3.0.2: 964 | resolution: {integrity: sha512-6RxOBZ/cYgd8usLwsEl+EC09Au/9BcmCKYF2/xbml6DNczf7nv0MQb+7BA2F+li6//I+28VNlQR37XfQtcAJuA==} 965 | engines: {node: '>=18.0.0'} 966 | 967 | eventsource@3.0.7: 968 | resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==} 969 | engines: {node: '>=18.0.0'} 970 | 971 | execa@5.1.1: 972 | resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} 973 | engines: {node: '>=10'} 974 | 975 | expect-type@1.2.1: 976 | resolution: {integrity: sha512-/kP8CAwxzLVEeFrMm4kMmy4CCDlpipyA7MYLVrdJIkV0fYF0UaigQHRsxHiuY/GEea+bh4KSv3TIlgr+2UL6bw==} 977 | engines: {node: '>=12.0.0'} 978 | 979 | express-rate-limit@7.5.0: 980 | resolution: {integrity: sha512-eB5zbQh5h+VenMPM3fh+nw1YExi5nMr6HUCR62ELSP11huvxm/Uir1H1QEyTkk5QX6A58pX6NmaTMceKZ0Eodg==} 981 | engines: {node: '>= 16'} 982 | peerDependencies: 983 | express: ^4.11 || 5 || ^5.0.0-beta.1 984 | 985 | express@5.1.0: 986 | resolution: {integrity: sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==} 987 | engines: {node: '>= 18'} 988 | 989 | extendable-error@0.1.7: 990 | resolution: {integrity: sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg==} 991 | 992 | external-editor@3.1.0: 993 | resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==} 994 | engines: {node: '>=4'} 995 | 996 | fast-deep-equal@3.1.3: 997 | resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} 998 | 999 | fast-glob@3.3.3: 1000 | resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} 1001 | engines: {node: '>=8.6.0'} 1002 | 1003 | fast-uri@3.1.0: 1004 | resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} 1005 | 1006 | fastq@1.19.1: 1007 | resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} 1008 | 1009 | fdir@6.4.5: 1010 | resolution: {integrity: sha512-4BG7puHpVsIYxZUbiUE3RqGloLaSSwzYie5jvasC4LWuBWzZawynvYouhjbQKw2JuIGYdm0DzIxl8iVidKlUEw==} 1011 | peerDependencies: 1012 | picomatch: ^3 || ^4 1013 | peerDependenciesMeta: 1014 | picomatch: 1015 | optional: true 1016 | 1017 | fill-range@7.1.1: 1018 | resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} 1019 | engines: {node: '>=8'} 1020 | 1021 | finalhandler@2.1.0: 1022 | resolution: {integrity: sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==} 1023 | engines: {node: '>= 0.8'} 1024 | 1025 | find-up@4.1.0: 1026 | resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} 1027 | engines: {node: '>=8'} 1028 | 1029 | foreground-child@3.3.1: 1030 | resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} 1031 | engines: {node: '>=14'} 1032 | 1033 | forwarded@0.2.0: 1034 | resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} 1035 | engines: {node: '>= 0.6'} 1036 | 1037 | fresh@2.0.0: 1038 | resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} 1039 | engines: {node: '>= 0.8'} 1040 | 1041 | fs-extra@7.0.1: 1042 | resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} 1043 | engines: {node: '>=6 <7 || >=8'} 1044 | 1045 | fs-extra@8.1.0: 1046 | resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} 1047 | engines: {node: '>=6 <7 || >=8'} 1048 | 1049 | fsevents@2.3.3: 1050 | resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} 1051 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} 1052 | os: [darwin] 1053 | 1054 | function-bind@1.1.2: 1055 | resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} 1056 | 1057 | generic-pool@3.9.0: 1058 | resolution: {integrity: sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==} 1059 | engines: {node: '>= 4'} 1060 | 1061 | get-intrinsic@1.3.0: 1062 | resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} 1063 | engines: {node: '>= 0.4'} 1064 | 1065 | get-proto@1.0.1: 1066 | resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} 1067 | engines: {node: '>= 0.4'} 1068 | 1069 | get-stream@6.0.1: 1070 | resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} 1071 | engines: {node: '>=10'} 1072 | 1073 | glob-parent@5.1.2: 1074 | resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} 1075 | engines: {node: '>= 6'} 1076 | 1077 | glob@10.4.5: 1078 | resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} 1079 | hasBin: true 1080 | 1081 | globby@11.1.0: 1082 | resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} 1083 | engines: {node: '>=10'} 1084 | 1085 | gopd@1.2.0: 1086 | resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} 1087 | engines: {node: '>= 0.4'} 1088 | 1089 | graceful-fs@4.2.11: 1090 | resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} 1091 | 1092 | has-symbols@1.1.0: 1093 | resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} 1094 | engines: {node: '>= 0.4'} 1095 | 1096 | hasown@2.0.2: 1097 | resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} 1098 | engines: {node: '>= 0.4'} 1099 | 1100 | http-errors@2.0.0: 1101 | resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} 1102 | engines: {node: '>= 0.8'} 1103 | 1104 | human-id@4.1.1: 1105 | resolution: {integrity: sha512-3gKm/gCSUipeLsRYZbbdA1BD83lBoWUkZ7G9VFrhWPAU76KwYo5KR8V28bpoPm/ygy0x5/GCbpRQdY7VLYCoIg==} 1106 | hasBin: true 1107 | 1108 | human-signals@2.1.0: 1109 | resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} 1110 | engines: {node: '>=10.17.0'} 1111 | 1112 | iconv-lite@0.4.24: 1113 | resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} 1114 | engines: {node: '>=0.10.0'} 1115 | 1116 | iconv-lite@0.6.3: 1117 | resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} 1118 | engines: {node: '>=0.10.0'} 1119 | 1120 | ignore@5.3.2: 1121 | resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} 1122 | engines: {node: '>= 4'} 1123 | 1124 | inherits@2.0.4: 1125 | resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} 1126 | 1127 | ipaddr.js@1.9.1: 1128 | resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} 1129 | engines: {node: '>= 0.10'} 1130 | 1131 | is-binary-path@2.1.0: 1132 | resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} 1133 | engines: {node: '>=8'} 1134 | 1135 | is-extglob@2.1.1: 1136 | resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} 1137 | engines: {node: '>=0.10.0'} 1138 | 1139 | is-fullwidth-code-point@3.0.0: 1140 | resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} 1141 | engines: {node: '>=8'} 1142 | 1143 | is-glob@4.0.3: 1144 | resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} 1145 | engines: {node: '>=0.10.0'} 1146 | 1147 | is-number@7.0.0: 1148 | resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} 1149 | engines: {node: '>=0.12.0'} 1150 | 1151 | is-promise@4.0.0: 1152 | resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} 1153 | 1154 | is-stream@2.0.1: 1155 | resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} 1156 | engines: {node: '>=8'} 1157 | 1158 | is-subdir@1.2.0: 1159 | resolution: {integrity: sha512-2AT6j+gXe/1ueqbW6fLZJiIw3F8iXGJtt0yDrZaBhAZEG1raiTxKWU+IPqMCzQAXOUCKdA4UDMgacKH25XG2Cw==} 1160 | engines: {node: '>=4'} 1161 | 1162 | is-windows@1.0.2: 1163 | resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} 1164 | engines: {node: '>=0.10.0'} 1165 | 1166 | isexe@2.0.0: 1167 | resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} 1168 | 1169 | jackspeak@3.4.3: 1170 | resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} 1171 | 1172 | joycon@3.1.1: 1173 | resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} 1174 | engines: {node: '>=10'} 1175 | 1176 | js-tokens@4.0.0: 1177 | resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} 1178 | 1179 | js-yaml@3.14.1: 1180 | resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} 1181 | hasBin: true 1182 | 1183 | json-schema-traverse@1.0.0: 1184 | resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} 1185 | 1186 | jsonfile@4.0.0: 1187 | resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} 1188 | 1189 | lilconfig@3.1.3: 1190 | resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} 1191 | engines: {node: '>=14'} 1192 | 1193 | lines-and-columns@1.2.4: 1194 | resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} 1195 | 1196 | load-tsconfig@0.2.5: 1197 | resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==} 1198 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 1199 | 1200 | locate-path@5.0.0: 1201 | resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} 1202 | engines: {node: '>=8'} 1203 | 1204 | lodash.sortby@4.7.0: 1205 | resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==} 1206 | 1207 | lodash.startcase@4.4.0: 1208 | resolution: {integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==} 1209 | 1210 | loose-envify@1.4.0: 1211 | resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} 1212 | hasBin: true 1213 | 1214 | loupe@3.1.3: 1215 | resolution: {integrity: sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug==} 1216 | 1217 | lru-cache@10.4.3: 1218 | resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} 1219 | 1220 | magic-string@0.30.17: 1221 | resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} 1222 | 1223 | math-intrinsics@1.1.0: 1224 | resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} 1225 | engines: {node: '>= 0.4'} 1226 | 1227 | media-typer@1.1.0: 1228 | resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} 1229 | engines: {node: '>= 0.8'} 1230 | 1231 | merge-descriptors@2.0.0: 1232 | resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} 1233 | engines: {node: '>=18'} 1234 | 1235 | merge-stream@2.0.0: 1236 | resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} 1237 | 1238 | merge2@1.4.1: 1239 | resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} 1240 | engines: {node: '>= 8'} 1241 | 1242 | micromatch@4.0.8: 1243 | resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} 1244 | engines: {node: '>=8.6'} 1245 | 1246 | mime-db@1.54.0: 1247 | resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} 1248 | engines: {node: '>= 0.6'} 1249 | 1250 | mime-types@3.0.1: 1251 | resolution: {integrity: sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==} 1252 | engines: {node: '>= 0.6'} 1253 | 1254 | mimic-fn@2.1.0: 1255 | resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} 1256 | engines: {node: '>=6'} 1257 | 1258 | minimatch@9.0.5: 1259 | resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} 1260 | engines: {node: '>=16 || 14 >=14.17'} 1261 | 1262 | minipass@7.1.2: 1263 | resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} 1264 | engines: {node: '>=16 || 14 >=14.17'} 1265 | 1266 | mri@1.2.0: 1267 | resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} 1268 | engines: {node: '>=4'} 1269 | 1270 | ms@2.1.3: 1271 | resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} 1272 | 1273 | mz@2.7.0: 1274 | resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} 1275 | 1276 | nanoid@3.3.11: 1277 | resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} 1278 | engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} 1279 | hasBin: true 1280 | 1281 | negotiator@1.0.0: 1282 | resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} 1283 | engines: {node: '>= 0.6'} 1284 | 1285 | next@13.0.0: 1286 | resolution: {integrity: sha512-puH1WGM6rGeFOoFdXXYfUxN9Sgi4LMytCV5HkQJvVUOhHfC1DoVqOfvzaEteyp6P04IW+gbtK2Q9pInVSrltPA==} 1287 | engines: {node: '>=14.6.0'} 1288 | hasBin: true 1289 | peerDependencies: 1290 | fibers: '>= 3.1.0' 1291 | node-sass: ^6.0.0 || ^7.0.0 1292 | react: ^18.0.0-0 1293 | react-dom: ^18.0.0-0 1294 | sass: ^1.3.0 1295 | peerDependenciesMeta: 1296 | fibers: 1297 | optional: true 1298 | node-sass: 1299 | optional: true 1300 | sass: 1301 | optional: true 1302 | 1303 | normalize-path@3.0.0: 1304 | resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} 1305 | engines: {node: '>=0.10.0'} 1306 | 1307 | npm-run-path@4.0.1: 1308 | resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} 1309 | engines: {node: '>=8'} 1310 | 1311 | object-assign@4.1.1: 1312 | resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} 1313 | engines: {node: '>=0.10.0'} 1314 | 1315 | object-inspect@1.13.4: 1316 | resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} 1317 | engines: {node: '>= 0.4'} 1318 | 1319 | on-finished@2.4.1: 1320 | resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} 1321 | engines: {node: '>= 0.8'} 1322 | 1323 | once@1.4.0: 1324 | resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} 1325 | 1326 | onetime@5.1.2: 1327 | resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} 1328 | engines: {node: '>=6'} 1329 | 1330 | os-tmpdir@1.0.2: 1331 | resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} 1332 | engines: {node: '>=0.10.0'} 1333 | 1334 | outdent@0.5.0: 1335 | resolution: {integrity: sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==} 1336 | 1337 | p-filter@2.1.0: 1338 | resolution: {integrity: sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==} 1339 | engines: {node: '>=8'} 1340 | 1341 | p-limit@2.3.0: 1342 | resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} 1343 | engines: {node: '>=6'} 1344 | 1345 | p-locate@4.1.0: 1346 | resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} 1347 | engines: {node: '>=8'} 1348 | 1349 | p-map@2.1.0: 1350 | resolution: {integrity: sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==} 1351 | engines: {node: '>=6'} 1352 | 1353 | p-try@2.2.0: 1354 | resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} 1355 | engines: {node: '>=6'} 1356 | 1357 | package-json-from-dist@1.0.1: 1358 | resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} 1359 | 1360 | package-manager-detector@0.2.11: 1361 | resolution: {integrity: sha512-BEnLolu+yuz22S56CU1SUKq3XC3PkwD5wv4ikR4MfGvnRVcmzXR9DwSlW2fEamyTPyXHomBJRzgapeuBvRNzJQ==} 1362 | 1363 | parseurl@1.3.3: 1364 | resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} 1365 | engines: {node: '>= 0.8'} 1366 | 1367 | path-exists@4.0.0: 1368 | resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} 1369 | engines: {node: '>=8'} 1370 | 1371 | path-key@3.1.1: 1372 | resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} 1373 | engines: {node: '>=8'} 1374 | 1375 | path-scurry@1.11.1: 1376 | resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} 1377 | engines: {node: '>=16 || 14 >=14.18'} 1378 | 1379 | path-to-regexp@8.2.0: 1380 | resolution: {integrity: sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==} 1381 | engines: {node: '>=16'} 1382 | 1383 | path-type@4.0.0: 1384 | resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} 1385 | engines: {node: '>=8'} 1386 | 1387 | pathe@2.0.3: 1388 | resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} 1389 | 1390 | pathval@2.0.0: 1391 | resolution: {integrity: sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==} 1392 | engines: {node: '>= 14.16'} 1393 | 1394 | picocolors@1.1.1: 1395 | resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} 1396 | 1397 | picomatch@2.3.1: 1398 | resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} 1399 | engines: {node: '>=8.6'} 1400 | 1401 | picomatch@4.0.2: 1402 | resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} 1403 | engines: {node: '>=12'} 1404 | 1405 | pify@4.0.1: 1406 | resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} 1407 | engines: {node: '>=6'} 1408 | 1409 | pirates@4.0.7: 1410 | resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} 1411 | engines: {node: '>= 6'} 1412 | 1413 | pkce-challenge@5.0.0: 1414 | resolution: {integrity: sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ==} 1415 | engines: {node: '>=16.20.0'} 1416 | 1417 | postcss-load-config@4.0.2: 1418 | resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==} 1419 | engines: {node: '>= 14'} 1420 | peerDependencies: 1421 | postcss: '>=8.0.9' 1422 | ts-node: '>=9.0.0' 1423 | peerDependenciesMeta: 1424 | postcss: 1425 | optional: true 1426 | ts-node: 1427 | optional: true 1428 | 1429 | postcss@8.4.14: 1430 | resolution: {integrity: sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==} 1431 | engines: {node: ^10 || ^12 || >=14} 1432 | 1433 | postcss@8.5.4: 1434 | resolution: {integrity: sha512-QSa9EBe+uwlGTFmHsPKokv3B/oEMQZxfqW0QqNCyhpa6mB1afzulwn8hihglqAb2pOw+BJgNlmXQ8la2VeHB7w==} 1435 | engines: {node: ^10 || ^12 || >=14} 1436 | 1437 | prettier@2.8.8: 1438 | resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} 1439 | engines: {node: '>=10.13.0'} 1440 | hasBin: true 1441 | 1442 | proxy-addr@2.0.7: 1443 | resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} 1444 | engines: {node: '>= 0.10'} 1445 | 1446 | punycode@2.3.1: 1447 | resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} 1448 | engines: {node: '>=6'} 1449 | 1450 | qs@6.14.0: 1451 | resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} 1452 | engines: {node: '>=0.6'} 1453 | 1454 | quansync@0.2.10: 1455 | resolution: {integrity: sha512-t41VRkMYbkHyCYmOvx/6URnN80H7k4X0lLdBMGsz+maAwrJQYB1djpV6vHrQIBE0WBSGqhtEHrK9U3DWWH8v7A==} 1456 | 1457 | queue-microtask@1.2.3: 1458 | resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} 1459 | 1460 | range-parser@1.2.1: 1461 | resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} 1462 | engines: {node: '>= 0.6'} 1463 | 1464 | raw-body@3.0.0: 1465 | resolution: {integrity: sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==} 1466 | engines: {node: '>= 0.8'} 1467 | 1468 | react-dom@18.3.1: 1469 | resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==} 1470 | peerDependencies: 1471 | react: ^18.3.1 1472 | 1473 | react@18.3.1: 1474 | resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} 1475 | engines: {node: '>=0.10.0'} 1476 | 1477 | read-yaml-file@1.1.0: 1478 | resolution: {integrity: sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA==} 1479 | engines: {node: '>=6'} 1480 | 1481 | readdirp@3.6.0: 1482 | resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} 1483 | engines: {node: '>=8.10.0'} 1484 | 1485 | redis@4.6.0: 1486 | resolution: {integrity: sha512-QTlRvQtfRM9ZxFRfBmd8UsGGrKZil/cAwlbDTnaSKirCUMfWgXjKQ4VlkhmNBc3mnAbbSgeYw9zs/HcfYGd1Cw==} 1487 | 1488 | require-from-string@2.0.2: 1489 | resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} 1490 | engines: {node: '>=0.10.0'} 1491 | 1492 | resolve-from@5.0.0: 1493 | resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} 1494 | engines: {node: '>=8'} 1495 | 1496 | reusify@1.1.0: 1497 | resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} 1498 | engines: {iojs: '>=1.0.0', node: '>=0.10.0'} 1499 | 1500 | rollup@4.40.2: 1501 | resolution: {integrity: sha512-tfUOg6DTP4rhQ3VjOO6B4wyrJnGOX85requAXvqYTHsOgb2TFJdZ3aWpT8W2kPoypSGP7dZUyzxJ9ee4buM5Fg==} 1502 | engines: {node: '>=18.0.0', npm: '>=8.0.0'} 1503 | hasBin: true 1504 | 1505 | router@2.2.0: 1506 | resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} 1507 | engines: {node: '>= 18'} 1508 | 1509 | run-parallel@1.2.0: 1510 | resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} 1511 | 1512 | safe-buffer@5.2.1: 1513 | resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} 1514 | 1515 | safer-buffer@2.1.2: 1516 | resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} 1517 | 1518 | scheduler@0.23.2: 1519 | resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} 1520 | 1521 | semver@7.7.2: 1522 | resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==} 1523 | engines: {node: '>=10'} 1524 | hasBin: true 1525 | 1526 | send@1.2.0: 1527 | resolution: {integrity: sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==} 1528 | engines: {node: '>= 18'} 1529 | 1530 | serve-static@2.2.0: 1531 | resolution: {integrity: sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==} 1532 | engines: {node: '>= 18'} 1533 | 1534 | setprototypeof@1.2.0: 1535 | resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} 1536 | 1537 | shebang-command@2.0.0: 1538 | resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} 1539 | engines: {node: '>=8'} 1540 | 1541 | shebang-regex@3.0.0: 1542 | resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} 1543 | engines: {node: '>=8'} 1544 | 1545 | side-channel-list@1.0.0: 1546 | resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} 1547 | engines: {node: '>= 0.4'} 1548 | 1549 | side-channel-map@1.0.1: 1550 | resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} 1551 | engines: {node: '>= 0.4'} 1552 | 1553 | side-channel-weakmap@1.0.2: 1554 | resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} 1555 | engines: {node: '>= 0.4'} 1556 | 1557 | side-channel@1.1.0: 1558 | resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} 1559 | engines: {node: '>= 0.4'} 1560 | 1561 | siginfo@2.0.0: 1562 | resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} 1563 | 1564 | signal-exit@3.0.7: 1565 | resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} 1566 | 1567 | signal-exit@4.1.0: 1568 | resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} 1569 | engines: {node: '>=14'} 1570 | 1571 | slash@3.0.0: 1572 | resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} 1573 | engines: {node: '>=8'} 1574 | 1575 | source-map-js@1.2.1: 1576 | resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} 1577 | engines: {node: '>=0.10.0'} 1578 | 1579 | source-map@0.8.0-beta.0: 1580 | resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} 1581 | engines: {node: '>= 8'} 1582 | 1583 | spawndamnit@3.0.1: 1584 | resolution: {integrity: sha512-MmnduQUuHCoFckZoWnXsTg7JaiLBJrKFj9UI2MbRPGaJeVpsLcVBu6P/IGZovziM/YBsellCmsprgNA+w0CzVg==} 1585 | 1586 | sprintf-js@1.0.3: 1587 | resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} 1588 | 1589 | stackback@0.0.2: 1590 | resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} 1591 | 1592 | statuses@2.0.1: 1593 | resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} 1594 | engines: {node: '>= 0.8'} 1595 | 1596 | std-env@3.9.0: 1597 | resolution: {integrity: sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==} 1598 | 1599 | string-width@4.2.3: 1600 | resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} 1601 | engines: {node: '>=8'} 1602 | 1603 | string-width@5.1.2: 1604 | resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} 1605 | engines: {node: '>=12'} 1606 | 1607 | strip-ansi@6.0.1: 1608 | resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} 1609 | engines: {node: '>=8'} 1610 | 1611 | strip-ansi@7.1.0: 1612 | resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} 1613 | engines: {node: '>=12'} 1614 | 1615 | strip-bom@3.0.0: 1616 | resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} 1617 | engines: {node: '>=4'} 1618 | 1619 | strip-final-newline@2.0.0: 1620 | resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} 1621 | engines: {node: '>=6'} 1622 | 1623 | styled-jsx@5.1.0: 1624 | resolution: {integrity: sha512-/iHaRJt9U7T+5tp6TRelLnqBqiaIT0HsO0+vgyj8hK2KUk7aejFqRrumqPUlAqDwAj8IbS/1hk3IhBAAK/FCUQ==} 1625 | engines: {node: '>= 12.0.0'} 1626 | peerDependencies: 1627 | '@babel/core': '*' 1628 | babel-plugin-macros: '*' 1629 | react: '>= 16.8.0 || 17.x.x || ^18.0.0-0' 1630 | peerDependenciesMeta: 1631 | '@babel/core': 1632 | optional: true 1633 | babel-plugin-macros: 1634 | optional: true 1635 | 1636 | sucrase@3.35.0: 1637 | resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} 1638 | engines: {node: '>=16 || 14 >=14.17'} 1639 | hasBin: true 1640 | 1641 | term-size@2.2.1: 1642 | resolution: {integrity: sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==} 1643 | engines: {node: '>=8'} 1644 | 1645 | thenify-all@1.6.0: 1646 | resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} 1647 | engines: {node: '>=0.8'} 1648 | 1649 | thenify@3.3.1: 1650 | resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} 1651 | 1652 | tinybench@2.9.0: 1653 | resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} 1654 | 1655 | tinyexec@0.3.2: 1656 | resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} 1657 | 1658 | tinyglobby@0.2.14: 1659 | resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==} 1660 | engines: {node: '>=12.0.0'} 1661 | 1662 | tinypool@1.1.0: 1663 | resolution: {integrity: sha512-7CotroY9a8DKsKprEy/a14aCCm8jYVmR7aFy4fpkZM8sdpNJbKkixuNjgM50yCmip2ezc8z4N7k3oe2+rfRJCQ==} 1664 | engines: {node: ^18.0.0 || >=20.0.0} 1665 | 1666 | tinyrainbow@2.0.0: 1667 | resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==} 1668 | engines: {node: '>=14.0.0'} 1669 | 1670 | tinyspy@4.0.3: 1671 | resolution: {integrity: sha512-t2T/WLB2WRgZ9EpE4jgPJ9w+i66UZfDc8wHh0xrwiRNN+UwH98GIJkTeZqX9rg0i0ptwzqW+uYeIF0T4F8LR7A==} 1672 | engines: {node: '>=14.0.0'} 1673 | 1674 | tmp@0.0.33: 1675 | resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} 1676 | engines: {node: '>=0.6.0'} 1677 | 1678 | to-regex-range@5.0.1: 1679 | resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} 1680 | engines: {node: '>=8.0'} 1681 | 1682 | toidentifier@1.0.1: 1683 | resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} 1684 | engines: {node: '>=0.6'} 1685 | 1686 | tr46@1.0.1: 1687 | resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==} 1688 | 1689 | tree-kill@1.2.2: 1690 | resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} 1691 | hasBin: true 1692 | 1693 | ts-interface-checker@0.1.13: 1694 | resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} 1695 | 1696 | tslib@2.8.1: 1697 | resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} 1698 | 1699 | tsup@8.0.0: 1700 | resolution: {integrity: sha512-9rOGn8LsFn2iAg2pCB1jnH7ygVuGjlzIomjw0jKXUxAii3iL5cXgm0jZMPKfFH1bSAjQovJ1DUVPSw+oDuIu8A==} 1701 | engines: {node: '>=18'} 1702 | hasBin: true 1703 | peerDependencies: 1704 | '@microsoft/api-extractor': ^7.36.0 1705 | '@swc/core': ^1 1706 | postcss: ^8.4.12 1707 | typescript: '>=4.5.0' 1708 | peerDependenciesMeta: 1709 | '@microsoft/api-extractor': 1710 | optional: true 1711 | '@swc/core': 1712 | optional: true 1713 | postcss: 1714 | optional: true 1715 | typescript: 1716 | optional: true 1717 | 1718 | type-is@2.0.1: 1719 | resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} 1720 | engines: {node: '>= 0.6'} 1721 | 1722 | typescript@5.0.2: 1723 | resolution: {integrity: sha512-wVORMBGO/FAs/++blGNeAVdbNKtIh1rbBL2EyQ1+J9lClJ93KiiKe8PmFIVdXhHcyv44SL9oglmfeSsndo0jRw==} 1724 | engines: {node: '>=12.20'} 1725 | hasBin: true 1726 | 1727 | undici-types@6.21.0: 1728 | resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} 1729 | 1730 | universalify@0.1.2: 1731 | resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} 1732 | engines: {node: '>= 4.0.0'} 1733 | 1734 | unpipe@1.0.0: 1735 | resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} 1736 | engines: {node: '>= 0.8'} 1737 | 1738 | use-sync-external-store@1.2.0: 1739 | resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==} 1740 | peerDependencies: 1741 | react: ^16.8.0 || ^17.0.0 || ^18.0.0 1742 | 1743 | vary@1.1.2: 1744 | resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} 1745 | engines: {node: '>= 0.8'} 1746 | 1747 | vite-node@3.2.1: 1748 | resolution: {integrity: sha512-V4EyKQPxquurNJPtQJRZo8hKOoKNBRIhxcDbQFPFig0JdoWcUhwRgK8yoCXXrfYVPKS6XwirGHPszLnR8FbjCA==} 1749 | engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} 1750 | hasBin: true 1751 | 1752 | vite@6.3.5: 1753 | resolution: {integrity: sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==} 1754 | engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} 1755 | hasBin: true 1756 | peerDependencies: 1757 | '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 1758 | jiti: '>=1.21.0' 1759 | less: '*' 1760 | lightningcss: ^1.21.0 1761 | sass: '*' 1762 | sass-embedded: '*' 1763 | stylus: '*' 1764 | sugarss: '*' 1765 | terser: ^5.16.0 1766 | tsx: ^4.8.1 1767 | yaml: ^2.4.2 1768 | peerDependenciesMeta: 1769 | '@types/node': 1770 | optional: true 1771 | jiti: 1772 | optional: true 1773 | less: 1774 | optional: true 1775 | lightningcss: 1776 | optional: true 1777 | sass: 1778 | optional: true 1779 | sass-embedded: 1780 | optional: true 1781 | stylus: 1782 | optional: true 1783 | sugarss: 1784 | optional: true 1785 | terser: 1786 | optional: true 1787 | tsx: 1788 | optional: true 1789 | yaml: 1790 | optional: true 1791 | 1792 | vitest@3.2.1: 1793 | resolution: {integrity: sha512-VZ40MBnlE1/V5uTgdqY3DmjUgZtIzsYq758JGlyQrv5syIsaYcabkfPkEuWML49Ph0D/SoqpVFd0dyVTr551oA==} 1794 | engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} 1795 | hasBin: true 1796 | peerDependencies: 1797 | '@edge-runtime/vm': '*' 1798 | '@types/debug': ^4.1.12 1799 | '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 1800 | '@vitest/browser': 3.2.1 1801 | '@vitest/ui': 3.2.1 1802 | happy-dom: '*' 1803 | jsdom: '*' 1804 | peerDependenciesMeta: 1805 | '@edge-runtime/vm': 1806 | optional: true 1807 | '@types/debug': 1808 | optional: true 1809 | '@types/node': 1810 | optional: true 1811 | '@vitest/browser': 1812 | optional: true 1813 | '@vitest/ui': 1814 | optional: true 1815 | happy-dom: 1816 | optional: true 1817 | jsdom: 1818 | optional: true 1819 | 1820 | webidl-conversions@4.0.2: 1821 | resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==} 1822 | 1823 | whatwg-url@7.1.0: 1824 | resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==} 1825 | 1826 | which@2.0.2: 1827 | resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} 1828 | engines: {node: '>= 8'} 1829 | hasBin: true 1830 | 1831 | why-is-node-running@2.3.0: 1832 | resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} 1833 | engines: {node: '>=8'} 1834 | hasBin: true 1835 | 1836 | wrap-ansi@7.0.0: 1837 | resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} 1838 | engines: {node: '>=10'} 1839 | 1840 | wrap-ansi@8.1.0: 1841 | resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} 1842 | engines: {node: '>=12'} 1843 | 1844 | wrappy@1.0.2: 1845 | resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} 1846 | 1847 | yallist@4.0.0: 1848 | resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} 1849 | 1850 | yaml@2.8.0: 1851 | resolution: {integrity: sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==} 1852 | engines: {node: '>= 14.6'} 1853 | hasBin: true 1854 | 1855 | zod-to-json-schema@3.24.5: 1856 | resolution: {integrity: sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g==} 1857 | peerDependencies: 1858 | zod: ^3.24.1 1859 | 1860 | zod@3.25.50: 1861 | resolution: {integrity: sha512-VstOnRxf4tlSq0raIwbn0n+LA34SxVoZ8r3pkwSUM0jqNiA/HCMQEVjTuS5FZmHsge+9MDGTiAuHyml5T0um6A==} 1862 | 1863 | snapshots: 1864 | 1865 | '@babel/runtime@7.27.1': {} 1866 | 1867 | '@changesets/apply-release-plan@7.0.12': 1868 | dependencies: 1869 | '@changesets/config': 3.1.1 1870 | '@changesets/get-version-range-type': 0.4.0 1871 | '@changesets/git': 3.0.4 1872 | '@changesets/should-skip-package': 0.1.2 1873 | '@changesets/types': 6.1.0 1874 | '@manypkg/get-packages': 1.1.3 1875 | detect-indent: 6.1.0 1876 | fs-extra: 7.0.1 1877 | lodash.startcase: 4.4.0 1878 | outdent: 0.5.0 1879 | prettier: 2.8.8 1880 | resolve-from: 5.0.0 1881 | semver: 7.7.2 1882 | 1883 | '@changesets/assemble-release-plan@6.0.8': 1884 | dependencies: 1885 | '@changesets/errors': 0.2.0 1886 | '@changesets/get-dependents-graph': 2.1.3 1887 | '@changesets/should-skip-package': 0.1.2 1888 | '@changesets/types': 6.1.0 1889 | '@manypkg/get-packages': 1.1.3 1890 | semver: 7.7.2 1891 | 1892 | '@changesets/changelog-git@0.2.1': 1893 | dependencies: 1894 | '@changesets/types': 6.1.0 1895 | 1896 | '@changesets/cli@2.29.4': 1897 | dependencies: 1898 | '@changesets/apply-release-plan': 7.0.12 1899 | '@changesets/assemble-release-plan': 6.0.8 1900 | '@changesets/changelog-git': 0.2.1 1901 | '@changesets/config': 3.1.1 1902 | '@changesets/errors': 0.2.0 1903 | '@changesets/get-dependents-graph': 2.1.3 1904 | '@changesets/get-release-plan': 4.0.12 1905 | '@changesets/git': 3.0.4 1906 | '@changesets/logger': 0.1.1 1907 | '@changesets/pre': 2.0.2 1908 | '@changesets/read': 0.6.5 1909 | '@changesets/should-skip-package': 0.1.2 1910 | '@changesets/types': 6.1.0 1911 | '@changesets/write': 0.4.0 1912 | '@manypkg/get-packages': 1.1.3 1913 | ansi-colors: 4.1.3 1914 | ci-info: 3.9.0 1915 | enquirer: 2.4.1 1916 | external-editor: 3.1.0 1917 | fs-extra: 7.0.1 1918 | mri: 1.2.0 1919 | p-limit: 2.3.0 1920 | package-manager-detector: 0.2.11 1921 | picocolors: 1.1.1 1922 | resolve-from: 5.0.0 1923 | semver: 7.7.2 1924 | spawndamnit: 3.0.1 1925 | term-size: 2.2.1 1926 | 1927 | '@changesets/config@3.1.1': 1928 | dependencies: 1929 | '@changesets/errors': 0.2.0 1930 | '@changesets/get-dependents-graph': 2.1.3 1931 | '@changesets/logger': 0.1.1 1932 | '@changesets/types': 6.1.0 1933 | '@manypkg/get-packages': 1.1.3 1934 | fs-extra: 7.0.1 1935 | micromatch: 4.0.8 1936 | 1937 | '@changesets/errors@0.2.0': 1938 | dependencies: 1939 | extendable-error: 0.1.7 1940 | 1941 | '@changesets/get-dependents-graph@2.1.3': 1942 | dependencies: 1943 | '@changesets/types': 6.1.0 1944 | '@manypkg/get-packages': 1.1.3 1945 | picocolors: 1.1.1 1946 | semver: 7.7.2 1947 | 1948 | '@changesets/get-release-plan@4.0.12': 1949 | dependencies: 1950 | '@changesets/assemble-release-plan': 6.0.8 1951 | '@changesets/config': 3.1.1 1952 | '@changesets/pre': 2.0.2 1953 | '@changesets/read': 0.6.5 1954 | '@changesets/types': 6.1.0 1955 | '@manypkg/get-packages': 1.1.3 1956 | 1957 | '@changesets/get-version-range-type@0.4.0': {} 1958 | 1959 | '@changesets/git@3.0.4': 1960 | dependencies: 1961 | '@changesets/errors': 0.2.0 1962 | '@manypkg/get-packages': 1.1.3 1963 | is-subdir: 1.2.0 1964 | micromatch: 4.0.8 1965 | spawndamnit: 3.0.1 1966 | 1967 | '@changesets/logger@0.1.1': 1968 | dependencies: 1969 | picocolors: 1.1.1 1970 | 1971 | '@changesets/parse@0.4.1': 1972 | dependencies: 1973 | '@changesets/types': 6.1.0 1974 | js-yaml: 3.14.1 1975 | 1976 | '@changesets/pre@2.0.2': 1977 | dependencies: 1978 | '@changesets/errors': 0.2.0 1979 | '@changesets/types': 6.1.0 1980 | '@manypkg/get-packages': 1.1.3 1981 | fs-extra: 7.0.1 1982 | 1983 | '@changesets/read@0.6.5': 1984 | dependencies: 1985 | '@changesets/git': 3.0.4 1986 | '@changesets/logger': 0.1.1 1987 | '@changesets/parse': 0.4.1 1988 | '@changesets/types': 6.1.0 1989 | fs-extra: 7.0.1 1990 | p-filter: 2.1.0 1991 | picocolors: 1.1.1 1992 | 1993 | '@changesets/should-skip-package@0.1.2': 1994 | dependencies: 1995 | '@changesets/types': 6.1.0 1996 | '@manypkg/get-packages': 1.1.3 1997 | 1998 | '@changesets/types@4.1.0': {} 1999 | 2000 | '@changesets/types@6.1.0': {} 2001 | 2002 | '@changesets/write@0.4.0': 2003 | dependencies: 2004 | '@changesets/types': 6.1.0 2005 | fs-extra: 7.0.1 2006 | human-id: 4.1.1 2007 | prettier: 2.8.8 2008 | 2009 | '@esbuild/aix-ppc64@0.19.12': 2010 | optional: true 2011 | 2012 | '@esbuild/aix-ppc64@0.25.5': 2013 | optional: true 2014 | 2015 | '@esbuild/android-arm64@0.19.12': 2016 | optional: true 2017 | 2018 | '@esbuild/android-arm64@0.25.5': 2019 | optional: true 2020 | 2021 | '@esbuild/android-arm@0.19.12': 2022 | optional: true 2023 | 2024 | '@esbuild/android-arm@0.25.5': 2025 | optional: true 2026 | 2027 | '@esbuild/android-x64@0.19.12': 2028 | optional: true 2029 | 2030 | '@esbuild/android-x64@0.25.5': 2031 | optional: true 2032 | 2033 | '@esbuild/darwin-arm64@0.19.12': 2034 | optional: true 2035 | 2036 | '@esbuild/darwin-arm64@0.25.5': 2037 | optional: true 2038 | 2039 | '@esbuild/darwin-x64@0.19.12': 2040 | optional: true 2041 | 2042 | '@esbuild/darwin-x64@0.25.5': 2043 | optional: true 2044 | 2045 | '@esbuild/freebsd-arm64@0.19.12': 2046 | optional: true 2047 | 2048 | '@esbuild/freebsd-arm64@0.25.5': 2049 | optional: true 2050 | 2051 | '@esbuild/freebsd-x64@0.19.12': 2052 | optional: true 2053 | 2054 | '@esbuild/freebsd-x64@0.25.5': 2055 | optional: true 2056 | 2057 | '@esbuild/linux-arm64@0.19.12': 2058 | optional: true 2059 | 2060 | '@esbuild/linux-arm64@0.25.5': 2061 | optional: true 2062 | 2063 | '@esbuild/linux-arm@0.19.12': 2064 | optional: true 2065 | 2066 | '@esbuild/linux-arm@0.25.5': 2067 | optional: true 2068 | 2069 | '@esbuild/linux-ia32@0.19.12': 2070 | optional: true 2071 | 2072 | '@esbuild/linux-ia32@0.25.5': 2073 | optional: true 2074 | 2075 | '@esbuild/linux-loong64@0.19.12': 2076 | optional: true 2077 | 2078 | '@esbuild/linux-loong64@0.25.5': 2079 | optional: true 2080 | 2081 | '@esbuild/linux-mips64el@0.19.12': 2082 | optional: true 2083 | 2084 | '@esbuild/linux-mips64el@0.25.5': 2085 | optional: true 2086 | 2087 | '@esbuild/linux-ppc64@0.19.12': 2088 | optional: true 2089 | 2090 | '@esbuild/linux-ppc64@0.25.5': 2091 | optional: true 2092 | 2093 | '@esbuild/linux-riscv64@0.19.12': 2094 | optional: true 2095 | 2096 | '@esbuild/linux-riscv64@0.25.5': 2097 | optional: true 2098 | 2099 | '@esbuild/linux-s390x@0.19.12': 2100 | optional: true 2101 | 2102 | '@esbuild/linux-s390x@0.25.5': 2103 | optional: true 2104 | 2105 | '@esbuild/linux-x64@0.19.12': 2106 | optional: true 2107 | 2108 | '@esbuild/linux-x64@0.25.5': 2109 | optional: true 2110 | 2111 | '@esbuild/netbsd-arm64@0.25.5': 2112 | optional: true 2113 | 2114 | '@esbuild/netbsd-x64@0.19.12': 2115 | optional: true 2116 | 2117 | '@esbuild/netbsd-x64@0.25.5': 2118 | optional: true 2119 | 2120 | '@esbuild/openbsd-arm64@0.25.5': 2121 | optional: true 2122 | 2123 | '@esbuild/openbsd-x64@0.19.12': 2124 | optional: true 2125 | 2126 | '@esbuild/openbsd-x64@0.25.5': 2127 | optional: true 2128 | 2129 | '@esbuild/sunos-x64@0.19.12': 2130 | optional: true 2131 | 2132 | '@esbuild/sunos-x64@0.25.5': 2133 | optional: true 2134 | 2135 | '@esbuild/win32-arm64@0.19.12': 2136 | optional: true 2137 | 2138 | '@esbuild/win32-arm64@0.25.5': 2139 | optional: true 2140 | 2141 | '@esbuild/win32-ia32@0.19.12': 2142 | optional: true 2143 | 2144 | '@esbuild/win32-ia32@0.25.5': 2145 | optional: true 2146 | 2147 | '@esbuild/win32-x64@0.19.12': 2148 | optional: true 2149 | 2150 | '@esbuild/win32-x64@0.25.5': 2151 | optional: true 2152 | 2153 | '@isaacs/cliui@8.0.2': 2154 | dependencies: 2155 | string-width: 5.1.2 2156 | string-width-cjs: string-width@4.2.3 2157 | strip-ansi: 7.1.0 2158 | strip-ansi-cjs: strip-ansi@6.0.1 2159 | wrap-ansi: 8.1.0 2160 | wrap-ansi-cjs: wrap-ansi@7.0.0 2161 | 2162 | '@jridgewell/gen-mapping@0.3.8': 2163 | dependencies: 2164 | '@jridgewell/set-array': 1.2.1 2165 | '@jridgewell/sourcemap-codec': 1.5.0 2166 | '@jridgewell/trace-mapping': 0.3.25 2167 | 2168 | '@jridgewell/resolve-uri@3.1.2': {} 2169 | 2170 | '@jridgewell/set-array@1.2.1': {} 2171 | 2172 | '@jridgewell/sourcemap-codec@1.5.0': {} 2173 | 2174 | '@jridgewell/trace-mapping@0.3.25': 2175 | dependencies: 2176 | '@jridgewell/resolve-uri': 3.1.2 2177 | '@jridgewell/sourcemap-codec': 1.5.0 2178 | 2179 | '@manypkg/find-root@1.1.0': 2180 | dependencies: 2181 | '@babel/runtime': 7.27.1 2182 | '@types/node': 12.20.55 2183 | find-up: 4.1.0 2184 | fs-extra: 8.1.0 2185 | 2186 | '@manypkg/get-packages@1.1.3': 2187 | dependencies: 2188 | '@babel/runtime': 7.27.1 2189 | '@changesets/types': 4.1.0 2190 | '@manypkg/find-root': 1.1.0 2191 | fs-extra: 8.1.0 2192 | globby: 11.1.0 2193 | read-yaml-file: 1.1.0 2194 | 2195 | '@modelcontextprotocol/sdk@1.22.0': 2196 | dependencies: 2197 | ajv: 8.17.1 2198 | ajv-formats: 3.0.1(ajv@8.17.1) 2199 | content-type: 1.0.5 2200 | cors: 2.8.5 2201 | cross-spawn: 7.0.6 2202 | eventsource: 3.0.7 2203 | eventsource-parser: 3.0.2 2204 | express: 5.1.0 2205 | express-rate-limit: 7.5.0(express@5.1.0) 2206 | pkce-challenge: 5.0.0 2207 | raw-body: 3.0.0 2208 | zod: 3.25.50 2209 | zod-to-json-schema: 3.24.5(zod@3.25.50) 2210 | transitivePeerDependencies: 2211 | - supports-color 2212 | 2213 | '@next/env@13.0.0': {} 2214 | 2215 | '@next/swc-android-arm-eabi@13.0.0': 2216 | optional: true 2217 | 2218 | '@next/swc-android-arm64@13.0.0': 2219 | optional: true 2220 | 2221 | '@next/swc-darwin-arm64@13.0.0': 2222 | optional: true 2223 | 2224 | '@next/swc-darwin-x64@13.0.0': 2225 | optional: true 2226 | 2227 | '@next/swc-freebsd-x64@13.0.0': 2228 | optional: true 2229 | 2230 | '@next/swc-linux-arm-gnueabihf@13.0.0': 2231 | optional: true 2232 | 2233 | '@next/swc-linux-arm64-gnu@13.0.0': 2234 | optional: true 2235 | 2236 | '@next/swc-linux-arm64-musl@13.0.0': 2237 | optional: true 2238 | 2239 | '@next/swc-linux-x64-gnu@13.0.0': 2240 | optional: true 2241 | 2242 | '@next/swc-linux-x64-musl@13.0.0': 2243 | optional: true 2244 | 2245 | '@next/swc-win32-arm64-msvc@13.0.0': 2246 | optional: true 2247 | 2248 | '@next/swc-win32-ia32-msvc@13.0.0': 2249 | optional: true 2250 | 2251 | '@next/swc-win32-x64-msvc@13.0.0': 2252 | optional: true 2253 | 2254 | '@nodelib/fs.scandir@2.1.5': 2255 | dependencies: 2256 | '@nodelib/fs.stat': 2.0.5 2257 | run-parallel: 1.2.0 2258 | 2259 | '@nodelib/fs.stat@2.0.5': {} 2260 | 2261 | '@nodelib/fs.walk@1.2.8': 2262 | dependencies: 2263 | '@nodelib/fs.scandir': 2.1.5 2264 | fastq: 1.19.1 2265 | 2266 | '@pkgjs/parseargs@0.11.0': 2267 | optional: true 2268 | 2269 | '@redis/bloom@1.2.0(@redis/client@1.5.0)': 2270 | dependencies: 2271 | '@redis/client': 1.5.0 2272 | 2273 | '@redis/client@1.5.0': 2274 | dependencies: 2275 | cluster-key-slot: 1.1.2 2276 | generic-pool: 3.9.0 2277 | yallist: 4.0.0 2278 | 2279 | '@redis/graph@1.1.0(@redis/client@1.5.0)': 2280 | dependencies: 2281 | '@redis/client': 1.5.0 2282 | 2283 | '@redis/json@1.0.4(@redis/client@1.5.0)': 2284 | dependencies: 2285 | '@redis/client': 1.5.0 2286 | 2287 | '@redis/search@1.1.1(@redis/client@1.5.0)': 2288 | dependencies: 2289 | '@redis/client': 1.5.0 2290 | 2291 | '@redis/time-series@1.0.4(@redis/client@1.5.0)': 2292 | dependencies: 2293 | '@redis/client': 1.5.0 2294 | 2295 | '@rollup/rollup-android-arm-eabi@4.40.2': 2296 | optional: true 2297 | 2298 | '@rollup/rollup-android-arm64@4.40.2': 2299 | optional: true 2300 | 2301 | '@rollup/rollup-darwin-arm64@4.40.2': 2302 | optional: true 2303 | 2304 | '@rollup/rollup-darwin-x64@4.40.2': 2305 | optional: true 2306 | 2307 | '@rollup/rollup-freebsd-arm64@4.40.2': 2308 | optional: true 2309 | 2310 | '@rollup/rollup-freebsd-x64@4.40.2': 2311 | optional: true 2312 | 2313 | '@rollup/rollup-linux-arm-gnueabihf@4.40.2': 2314 | optional: true 2315 | 2316 | '@rollup/rollup-linux-arm-musleabihf@4.40.2': 2317 | optional: true 2318 | 2319 | '@rollup/rollup-linux-arm64-gnu@4.40.2': 2320 | optional: true 2321 | 2322 | '@rollup/rollup-linux-arm64-musl@4.40.2': 2323 | optional: true 2324 | 2325 | '@rollup/rollup-linux-loongarch64-gnu@4.40.2': 2326 | optional: true 2327 | 2328 | '@rollup/rollup-linux-powerpc64le-gnu@4.40.2': 2329 | optional: true 2330 | 2331 | '@rollup/rollup-linux-riscv64-gnu@4.40.2': 2332 | optional: true 2333 | 2334 | '@rollup/rollup-linux-riscv64-musl@4.40.2': 2335 | optional: true 2336 | 2337 | '@rollup/rollup-linux-s390x-gnu@4.40.2': 2338 | optional: true 2339 | 2340 | '@rollup/rollup-linux-x64-gnu@4.40.2': 2341 | optional: true 2342 | 2343 | '@rollup/rollup-linux-x64-musl@4.40.2': 2344 | optional: true 2345 | 2346 | '@rollup/rollup-win32-arm64-msvc@4.40.2': 2347 | optional: true 2348 | 2349 | '@rollup/rollup-win32-ia32-msvc@4.40.2': 2350 | optional: true 2351 | 2352 | '@rollup/rollup-win32-x64-msvc@4.40.2': 2353 | optional: true 2354 | 2355 | '@swc/helpers@0.4.11': 2356 | dependencies: 2357 | tslib: 2.8.1 2358 | 2359 | '@types/chai@5.2.2': 2360 | dependencies: 2361 | '@types/deep-eql': 4.0.2 2362 | 2363 | '@types/deep-eql@4.0.2': {} 2364 | 2365 | '@types/estree@1.0.7': {} 2366 | 2367 | '@types/node@12.20.55': {} 2368 | 2369 | '@types/node@22.15.8': 2370 | dependencies: 2371 | undici-types: 6.21.0 2372 | 2373 | '@vitest/expect@3.2.1': 2374 | dependencies: 2375 | '@types/chai': 5.2.2 2376 | '@vitest/spy': 3.2.1 2377 | '@vitest/utils': 3.2.1 2378 | chai: 5.2.0 2379 | tinyrainbow: 2.0.0 2380 | 2381 | '@vitest/mocker@3.2.1(vite@6.3.5(@types/node@22.15.8)(yaml@2.8.0))': 2382 | dependencies: 2383 | '@vitest/spy': 3.2.1 2384 | estree-walker: 3.0.3 2385 | magic-string: 0.30.17 2386 | optionalDependencies: 2387 | vite: 6.3.5(@types/node@22.15.8)(yaml@2.8.0) 2388 | 2389 | '@vitest/pretty-format@3.2.1': 2390 | dependencies: 2391 | tinyrainbow: 2.0.0 2392 | 2393 | '@vitest/runner@3.2.1': 2394 | dependencies: 2395 | '@vitest/utils': 3.2.1 2396 | pathe: 2.0.3 2397 | 2398 | '@vitest/snapshot@3.2.1': 2399 | dependencies: 2400 | '@vitest/pretty-format': 3.2.1 2401 | magic-string: 0.30.17 2402 | pathe: 2.0.3 2403 | 2404 | '@vitest/spy@3.2.1': 2405 | dependencies: 2406 | tinyspy: 4.0.3 2407 | 2408 | '@vitest/utils@3.2.1': 2409 | dependencies: 2410 | '@vitest/pretty-format': 3.2.1 2411 | loupe: 3.1.3 2412 | tinyrainbow: 2.0.0 2413 | 2414 | accepts@2.0.0: 2415 | dependencies: 2416 | mime-types: 3.0.1 2417 | negotiator: 1.0.0 2418 | 2419 | ajv-formats@3.0.1(ajv@8.17.1): 2420 | optionalDependencies: 2421 | ajv: 8.17.1 2422 | 2423 | ajv@8.17.1: 2424 | dependencies: 2425 | fast-deep-equal: 3.1.3 2426 | fast-uri: 3.1.0 2427 | json-schema-traverse: 1.0.0 2428 | require-from-string: 2.0.2 2429 | 2430 | ansi-colors@4.1.3: {} 2431 | 2432 | ansi-regex@5.0.1: {} 2433 | 2434 | ansi-regex@6.1.0: {} 2435 | 2436 | ansi-styles@4.3.0: 2437 | dependencies: 2438 | color-convert: 2.0.1 2439 | 2440 | ansi-styles@6.2.1: {} 2441 | 2442 | any-promise@1.3.0: {} 2443 | 2444 | anymatch@3.1.3: 2445 | dependencies: 2446 | normalize-path: 3.0.0 2447 | picomatch: 2.3.1 2448 | 2449 | argparse@1.0.10: 2450 | dependencies: 2451 | sprintf-js: 1.0.3 2452 | 2453 | array-union@2.1.0: {} 2454 | 2455 | assertion-error@2.0.1: {} 2456 | 2457 | balanced-match@1.0.2: {} 2458 | 2459 | better-path-resolve@1.0.0: 2460 | dependencies: 2461 | is-windows: 1.0.2 2462 | 2463 | binary-extensions@2.3.0: {} 2464 | 2465 | body-parser@2.2.0: 2466 | dependencies: 2467 | bytes: 3.1.2 2468 | content-type: 1.0.5 2469 | debug: 4.4.1 2470 | http-errors: 2.0.0 2471 | iconv-lite: 0.6.3 2472 | on-finished: 2.4.1 2473 | qs: 6.14.0 2474 | raw-body: 3.0.0 2475 | type-is: 2.0.1 2476 | transitivePeerDependencies: 2477 | - supports-color 2478 | 2479 | brace-expansion@2.0.1: 2480 | dependencies: 2481 | balanced-match: 1.0.2 2482 | 2483 | braces@3.0.3: 2484 | dependencies: 2485 | fill-range: 7.1.1 2486 | 2487 | bundle-require@4.2.1(esbuild@0.19.12): 2488 | dependencies: 2489 | esbuild: 0.19.12 2490 | load-tsconfig: 0.2.5 2491 | 2492 | bytes@3.1.2: {} 2493 | 2494 | cac@6.7.14: {} 2495 | 2496 | call-bind-apply-helpers@1.0.2: 2497 | dependencies: 2498 | es-errors: 1.3.0 2499 | function-bind: 1.1.2 2500 | 2501 | call-bound@1.0.4: 2502 | dependencies: 2503 | call-bind-apply-helpers: 1.0.2 2504 | get-intrinsic: 1.3.0 2505 | 2506 | caniuse-lite@1.0.30001718: {} 2507 | 2508 | chai@5.2.0: 2509 | dependencies: 2510 | assertion-error: 2.0.1 2511 | check-error: 2.1.1 2512 | deep-eql: 5.0.2 2513 | loupe: 3.1.3 2514 | pathval: 2.0.0 2515 | 2516 | chalk@5.4.1: {} 2517 | 2518 | chardet@0.7.0: {} 2519 | 2520 | check-error@2.1.1: {} 2521 | 2522 | chokidar@3.6.0: 2523 | dependencies: 2524 | anymatch: 3.1.3 2525 | braces: 3.0.3 2526 | glob-parent: 5.1.2 2527 | is-binary-path: 2.1.0 2528 | is-glob: 4.0.3 2529 | normalize-path: 3.0.0 2530 | readdirp: 3.6.0 2531 | optionalDependencies: 2532 | fsevents: 2.3.3 2533 | 2534 | ci-info@3.9.0: {} 2535 | 2536 | client-only@0.0.1: {} 2537 | 2538 | cluster-key-slot@1.1.2: {} 2539 | 2540 | color-convert@2.0.1: 2541 | dependencies: 2542 | color-name: 1.1.4 2543 | 2544 | color-name@1.1.4: {} 2545 | 2546 | commander@11.1.0: {} 2547 | 2548 | commander@4.1.1: {} 2549 | 2550 | content-disposition@1.0.0: 2551 | dependencies: 2552 | safe-buffer: 5.2.1 2553 | 2554 | content-type@1.0.5: {} 2555 | 2556 | cookie-signature@1.2.2: {} 2557 | 2558 | cookie@0.7.2: {} 2559 | 2560 | cors@2.8.5: 2561 | dependencies: 2562 | object-assign: 4.1.1 2563 | vary: 1.1.2 2564 | 2565 | cross-spawn@7.0.6: 2566 | dependencies: 2567 | path-key: 3.1.1 2568 | shebang-command: 2.0.0 2569 | which: 2.0.2 2570 | 2571 | debug@4.4.1: 2572 | dependencies: 2573 | ms: 2.1.3 2574 | 2575 | deep-eql@5.0.2: {} 2576 | 2577 | depd@2.0.0: {} 2578 | 2579 | detect-indent@6.1.0: {} 2580 | 2581 | dir-glob@3.0.1: 2582 | dependencies: 2583 | path-type: 4.0.0 2584 | 2585 | dunder-proto@1.0.1: 2586 | dependencies: 2587 | call-bind-apply-helpers: 1.0.2 2588 | es-errors: 1.3.0 2589 | gopd: 1.2.0 2590 | 2591 | eastasianwidth@0.2.0: {} 2592 | 2593 | ee-first@1.1.1: {} 2594 | 2595 | emoji-regex@8.0.0: {} 2596 | 2597 | emoji-regex@9.2.2: {} 2598 | 2599 | encodeurl@2.0.0: {} 2600 | 2601 | enquirer@2.4.1: 2602 | dependencies: 2603 | ansi-colors: 4.1.3 2604 | strip-ansi: 6.0.1 2605 | 2606 | es-define-property@1.0.1: {} 2607 | 2608 | es-errors@1.3.0: {} 2609 | 2610 | es-module-lexer@1.7.0: {} 2611 | 2612 | es-object-atoms@1.1.1: 2613 | dependencies: 2614 | es-errors: 1.3.0 2615 | 2616 | esbuild@0.19.12: 2617 | optionalDependencies: 2618 | '@esbuild/aix-ppc64': 0.19.12 2619 | '@esbuild/android-arm': 0.19.12 2620 | '@esbuild/android-arm64': 0.19.12 2621 | '@esbuild/android-x64': 0.19.12 2622 | '@esbuild/darwin-arm64': 0.19.12 2623 | '@esbuild/darwin-x64': 0.19.12 2624 | '@esbuild/freebsd-arm64': 0.19.12 2625 | '@esbuild/freebsd-x64': 0.19.12 2626 | '@esbuild/linux-arm': 0.19.12 2627 | '@esbuild/linux-arm64': 0.19.12 2628 | '@esbuild/linux-ia32': 0.19.12 2629 | '@esbuild/linux-loong64': 0.19.12 2630 | '@esbuild/linux-mips64el': 0.19.12 2631 | '@esbuild/linux-ppc64': 0.19.12 2632 | '@esbuild/linux-riscv64': 0.19.12 2633 | '@esbuild/linux-s390x': 0.19.12 2634 | '@esbuild/linux-x64': 0.19.12 2635 | '@esbuild/netbsd-x64': 0.19.12 2636 | '@esbuild/openbsd-x64': 0.19.12 2637 | '@esbuild/sunos-x64': 0.19.12 2638 | '@esbuild/win32-arm64': 0.19.12 2639 | '@esbuild/win32-ia32': 0.19.12 2640 | '@esbuild/win32-x64': 0.19.12 2641 | 2642 | esbuild@0.25.5: 2643 | optionalDependencies: 2644 | '@esbuild/aix-ppc64': 0.25.5 2645 | '@esbuild/android-arm': 0.25.5 2646 | '@esbuild/android-arm64': 0.25.5 2647 | '@esbuild/android-x64': 0.25.5 2648 | '@esbuild/darwin-arm64': 0.25.5 2649 | '@esbuild/darwin-x64': 0.25.5 2650 | '@esbuild/freebsd-arm64': 0.25.5 2651 | '@esbuild/freebsd-x64': 0.25.5 2652 | '@esbuild/linux-arm': 0.25.5 2653 | '@esbuild/linux-arm64': 0.25.5 2654 | '@esbuild/linux-ia32': 0.25.5 2655 | '@esbuild/linux-loong64': 0.25.5 2656 | '@esbuild/linux-mips64el': 0.25.5 2657 | '@esbuild/linux-ppc64': 0.25.5 2658 | '@esbuild/linux-riscv64': 0.25.5 2659 | '@esbuild/linux-s390x': 0.25.5 2660 | '@esbuild/linux-x64': 0.25.5 2661 | '@esbuild/netbsd-arm64': 0.25.5 2662 | '@esbuild/netbsd-x64': 0.25.5 2663 | '@esbuild/openbsd-arm64': 0.25.5 2664 | '@esbuild/openbsd-x64': 0.25.5 2665 | '@esbuild/sunos-x64': 0.25.5 2666 | '@esbuild/win32-arm64': 0.25.5 2667 | '@esbuild/win32-ia32': 0.25.5 2668 | '@esbuild/win32-x64': 0.25.5 2669 | 2670 | escape-html@1.0.3: {} 2671 | 2672 | esprima@4.0.1: {} 2673 | 2674 | estree-walker@3.0.3: 2675 | dependencies: 2676 | '@types/estree': 1.0.7 2677 | 2678 | etag@1.8.1: {} 2679 | 2680 | eventsource-parser@3.0.2: {} 2681 | 2682 | eventsource@3.0.7: 2683 | dependencies: 2684 | eventsource-parser: 3.0.2 2685 | 2686 | execa@5.1.1: 2687 | dependencies: 2688 | cross-spawn: 7.0.6 2689 | get-stream: 6.0.1 2690 | human-signals: 2.1.0 2691 | is-stream: 2.0.1 2692 | merge-stream: 2.0.0 2693 | npm-run-path: 4.0.1 2694 | onetime: 5.1.2 2695 | signal-exit: 3.0.7 2696 | strip-final-newline: 2.0.0 2697 | 2698 | expect-type@1.2.1: {} 2699 | 2700 | express-rate-limit@7.5.0(express@5.1.0): 2701 | dependencies: 2702 | express: 5.1.0 2703 | 2704 | express@5.1.0: 2705 | dependencies: 2706 | accepts: 2.0.0 2707 | body-parser: 2.2.0 2708 | content-disposition: 1.0.0 2709 | content-type: 1.0.5 2710 | cookie: 0.7.2 2711 | cookie-signature: 1.2.2 2712 | debug: 4.4.1 2713 | encodeurl: 2.0.0 2714 | escape-html: 1.0.3 2715 | etag: 1.8.1 2716 | finalhandler: 2.1.0 2717 | fresh: 2.0.0 2718 | http-errors: 2.0.0 2719 | merge-descriptors: 2.0.0 2720 | mime-types: 3.0.1 2721 | on-finished: 2.4.1 2722 | once: 1.4.0 2723 | parseurl: 1.3.3 2724 | proxy-addr: 2.0.7 2725 | qs: 6.14.0 2726 | range-parser: 1.2.1 2727 | router: 2.2.0 2728 | send: 1.2.0 2729 | serve-static: 2.2.0 2730 | statuses: 2.0.1 2731 | type-is: 2.0.1 2732 | vary: 1.1.2 2733 | transitivePeerDependencies: 2734 | - supports-color 2735 | 2736 | extendable-error@0.1.7: {} 2737 | 2738 | external-editor@3.1.0: 2739 | dependencies: 2740 | chardet: 0.7.0 2741 | iconv-lite: 0.4.24 2742 | tmp: 0.0.33 2743 | 2744 | fast-deep-equal@3.1.3: {} 2745 | 2746 | fast-glob@3.3.3: 2747 | dependencies: 2748 | '@nodelib/fs.stat': 2.0.5 2749 | '@nodelib/fs.walk': 1.2.8 2750 | glob-parent: 5.1.2 2751 | merge2: 1.4.1 2752 | micromatch: 4.0.8 2753 | 2754 | fast-uri@3.1.0: {} 2755 | 2756 | fastq@1.19.1: 2757 | dependencies: 2758 | reusify: 1.1.0 2759 | 2760 | fdir@6.4.5(picomatch@4.0.2): 2761 | optionalDependencies: 2762 | picomatch: 4.0.2 2763 | 2764 | fill-range@7.1.1: 2765 | dependencies: 2766 | to-regex-range: 5.0.1 2767 | 2768 | finalhandler@2.1.0: 2769 | dependencies: 2770 | debug: 4.4.1 2771 | encodeurl: 2.0.0 2772 | escape-html: 1.0.3 2773 | on-finished: 2.4.1 2774 | parseurl: 1.3.3 2775 | statuses: 2.0.1 2776 | transitivePeerDependencies: 2777 | - supports-color 2778 | 2779 | find-up@4.1.0: 2780 | dependencies: 2781 | locate-path: 5.0.0 2782 | path-exists: 4.0.0 2783 | 2784 | foreground-child@3.3.1: 2785 | dependencies: 2786 | cross-spawn: 7.0.6 2787 | signal-exit: 4.1.0 2788 | 2789 | forwarded@0.2.0: {} 2790 | 2791 | fresh@2.0.0: {} 2792 | 2793 | fs-extra@7.0.1: 2794 | dependencies: 2795 | graceful-fs: 4.2.11 2796 | jsonfile: 4.0.0 2797 | universalify: 0.1.2 2798 | 2799 | fs-extra@8.1.0: 2800 | dependencies: 2801 | graceful-fs: 4.2.11 2802 | jsonfile: 4.0.0 2803 | universalify: 0.1.2 2804 | 2805 | fsevents@2.3.3: 2806 | optional: true 2807 | 2808 | function-bind@1.1.2: {} 2809 | 2810 | generic-pool@3.9.0: {} 2811 | 2812 | get-intrinsic@1.3.0: 2813 | dependencies: 2814 | call-bind-apply-helpers: 1.0.2 2815 | es-define-property: 1.0.1 2816 | es-errors: 1.3.0 2817 | es-object-atoms: 1.1.1 2818 | function-bind: 1.1.2 2819 | get-proto: 1.0.1 2820 | gopd: 1.2.0 2821 | has-symbols: 1.1.0 2822 | hasown: 2.0.2 2823 | math-intrinsics: 1.1.0 2824 | 2825 | get-proto@1.0.1: 2826 | dependencies: 2827 | dunder-proto: 1.0.1 2828 | es-object-atoms: 1.1.1 2829 | 2830 | get-stream@6.0.1: {} 2831 | 2832 | glob-parent@5.1.2: 2833 | dependencies: 2834 | is-glob: 4.0.3 2835 | 2836 | glob@10.4.5: 2837 | dependencies: 2838 | foreground-child: 3.3.1 2839 | jackspeak: 3.4.3 2840 | minimatch: 9.0.5 2841 | minipass: 7.1.2 2842 | package-json-from-dist: 1.0.1 2843 | path-scurry: 1.11.1 2844 | 2845 | globby@11.1.0: 2846 | dependencies: 2847 | array-union: 2.1.0 2848 | dir-glob: 3.0.1 2849 | fast-glob: 3.3.3 2850 | ignore: 5.3.2 2851 | merge2: 1.4.1 2852 | slash: 3.0.0 2853 | 2854 | gopd@1.2.0: {} 2855 | 2856 | graceful-fs@4.2.11: {} 2857 | 2858 | has-symbols@1.1.0: {} 2859 | 2860 | hasown@2.0.2: 2861 | dependencies: 2862 | function-bind: 1.1.2 2863 | 2864 | http-errors@2.0.0: 2865 | dependencies: 2866 | depd: 2.0.0 2867 | inherits: 2.0.4 2868 | setprototypeof: 1.2.0 2869 | statuses: 2.0.1 2870 | toidentifier: 1.0.1 2871 | 2872 | human-id@4.1.1: {} 2873 | 2874 | human-signals@2.1.0: {} 2875 | 2876 | iconv-lite@0.4.24: 2877 | dependencies: 2878 | safer-buffer: 2.1.2 2879 | 2880 | iconv-lite@0.6.3: 2881 | dependencies: 2882 | safer-buffer: 2.1.2 2883 | 2884 | ignore@5.3.2: {} 2885 | 2886 | inherits@2.0.4: {} 2887 | 2888 | ipaddr.js@1.9.1: {} 2889 | 2890 | is-binary-path@2.1.0: 2891 | dependencies: 2892 | binary-extensions: 2.3.0 2893 | 2894 | is-extglob@2.1.1: {} 2895 | 2896 | is-fullwidth-code-point@3.0.0: {} 2897 | 2898 | is-glob@4.0.3: 2899 | dependencies: 2900 | is-extglob: 2.1.1 2901 | 2902 | is-number@7.0.0: {} 2903 | 2904 | is-promise@4.0.0: {} 2905 | 2906 | is-stream@2.0.1: {} 2907 | 2908 | is-subdir@1.2.0: 2909 | dependencies: 2910 | better-path-resolve: 1.0.0 2911 | 2912 | is-windows@1.0.2: {} 2913 | 2914 | isexe@2.0.0: {} 2915 | 2916 | jackspeak@3.4.3: 2917 | dependencies: 2918 | '@isaacs/cliui': 8.0.2 2919 | optionalDependencies: 2920 | '@pkgjs/parseargs': 0.11.0 2921 | 2922 | joycon@3.1.1: {} 2923 | 2924 | js-tokens@4.0.0: {} 2925 | 2926 | js-yaml@3.14.1: 2927 | dependencies: 2928 | argparse: 1.0.10 2929 | esprima: 4.0.1 2930 | 2931 | json-schema-traverse@1.0.0: {} 2932 | 2933 | jsonfile@4.0.0: 2934 | optionalDependencies: 2935 | graceful-fs: 4.2.11 2936 | 2937 | lilconfig@3.1.3: {} 2938 | 2939 | lines-and-columns@1.2.4: {} 2940 | 2941 | load-tsconfig@0.2.5: {} 2942 | 2943 | locate-path@5.0.0: 2944 | dependencies: 2945 | p-locate: 4.1.0 2946 | 2947 | lodash.sortby@4.7.0: {} 2948 | 2949 | lodash.startcase@4.4.0: {} 2950 | 2951 | loose-envify@1.4.0: 2952 | dependencies: 2953 | js-tokens: 4.0.0 2954 | 2955 | loupe@3.1.3: {} 2956 | 2957 | lru-cache@10.4.3: {} 2958 | 2959 | magic-string@0.30.17: 2960 | dependencies: 2961 | '@jridgewell/sourcemap-codec': 1.5.0 2962 | 2963 | math-intrinsics@1.1.0: {} 2964 | 2965 | media-typer@1.1.0: {} 2966 | 2967 | merge-descriptors@2.0.0: {} 2968 | 2969 | merge-stream@2.0.0: {} 2970 | 2971 | merge2@1.4.1: {} 2972 | 2973 | micromatch@4.0.8: 2974 | dependencies: 2975 | braces: 3.0.3 2976 | picomatch: 2.3.1 2977 | 2978 | mime-db@1.54.0: {} 2979 | 2980 | mime-types@3.0.1: 2981 | dependencies: 2982 | mime-db: 1.54.0 2983 | 2984 | mimic-fn@2.1.0: {} 2985 | 2986 | minimatch@9.0.5: 2987 | dependencies: 2988 | brace-expansion: 2.0.1 2989 | 2990 | minipass@7.1.2: {} 2991 | 2992 | mri@1.2.0: {} 2993 | 2994 | ms@2.1.3: {} 2995 | 2996 | mz@2.7.0: 2997 | dependencies: 2998 | any-promise: 1.3.0 2999 | object-assign: 4.1.1 3000 | thenify-all: 1.6.0 3001 | 3002 | nanoid@3.3.11: {} 3003 | 3004 | negotiator@1.0.0: {} 3005 | 3006 | next@13.0.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): 3007 | dependencies: 3008 | '@next/env': 13.0.0 3009 | '@swc/helpers': 0.4.11 3010 | caniuse-lite: 1.0.30001718 3011 | postcss: 8.4.14 3012 | react: 18.3.1 3013 | react-dom: 18.3.1(react@18.3.1) 3014 | styled-jsx: 5.1.0(react@18.3.1) 3015 | use-sync-external-store: 1.2.0(react@18.3.1) 3016 | optionalDependencies: 3017 | '@next/swc-android-arm-eabi': 13.0.0 3018 | '@next/swc-android-arm64': 13.0.0 3019 | '@next/swc-darwin-arm64': 13.0.0 3020 | '@next/swc-darwin-x64': 13.0.0 3021 | '@next/swc-freebsd-x64': 13.0.0 3022 | '@next/swc-linux-arm-gnueabihf': 13.0.0 3023 | '@next/swc-linux-arm64-gnu': 13.0.0 3024 | '@next/swc-linux-arm64-musl': 13.0.0 3025 | '@next/swc-linux-x64-gnu': 13.0.0 3026 | '@next/swc-linux-x64-musl': 13.0.0 3027 | '@next/swc-win32-arm64-msvc': 13.0.0 3028 | '@next/swc-win32-ia32-msvc': 13.0.0 3029 | '@next/swc-win32-x64-msvc': 13.0.0 3030 | transitivePeerDependencies: 3031 | - '@babel/core' 3032 | - babel-plugin-macros 3033 | 3034 | normalize-path@3.0.0: {} 3035 | 3036 | npm-run-path@4.0.1: 3037 | dependencies: 3038 | path-key: 3.1.1 3039 | 3040 | object-assign@4.1.1: {} 3041 | 3042 | object-inspect@1.13.4: {} 3043 | 3044 | on-finished@2.4.1: 3045 | dependencies: 3046 | ee-first: 1.1.1 3047 | 3048 | once@1.4.0: 3049 | dependencies: 3050 | wrappy: 1.0.2 3051 | 3052 | onetime@5.1.2: 3053 | dependencies: 3054 | mimic-fn: 2.1.0 3055 | 3056 | os-tmpdir@1.0.2: {} 3057 | 3058 | outdent@0.5.0: {} 3059 | 3060 | p-filter@2.1.0: 3061 | dependencies: 3062 | p-map: 2.1.0 3063 | 3064 | p-limit@2.3.0: 3065 | dependencies: 3066 | p-try: 2.2.0 3067 | 3068 | p-locate@4.1.0: 3069 | dependencies: 3070 | p-limit: 2.3.0 3071 | 3072 | p-map@2.1.0: {} 3073 | 3074 | p-try@2.2.0: {} 3075 | 3076 | package-json-from-dist@1.0.1: {} 3077 | 3078 | package-manager-detector@0.2.11: 3079 | dependencies: 3080 | quansync: 0.2.10 3081 | 3082 | parseurl@1.3.3: {} 3083 | 3084 | path-exists@4.0.0: {} 3085 | 3086 | path-key@3.1.1: {} 3087 | 3088 | path-scurry@1.11.1: 3089 | dependencies: 3090 | lru-cache: 10.4.3 3091 | minipass: 7.1.2 3092 | 3093 | path-to-regexp@8.2.0: {} 3094 | 3095 | path-type@4.0.0: {} 3096 | 3097 | pathe@2.0.3: {} 3098 | 3099 | pathval@2.0.0: {} 3100 | 3101 | picocolors@1.1.1: {} 3102 | 3103 | picomatch@2.3.1: {} 3104 | 3105 | picomatch@4.0.2: {} 3106 | 3107 | pify@4.0.1: {} 3108 | 3109 | pirates@4.0.7: {} 3110 | 3111 | pkce-challenge@5.0.0: {} 3112 | 3113 | postcss-load-config@4.0.2(postcss@8.5.4): 3114 | dependencies: 3115 | lilconfig: 3.1.3 3116 | yaml: 2.8.0 3117 | optionalDependencies: 3118 | postcss: 8.5.4 3119 | 3120 | postcss@8.4.14: 3121 | dependencies: 3122 | nanoid: 3.3.11 3123 | picocolors: 1.1.1 3124 | source-map-js: 1.2.1 3125 | 3126 | postcss@8.5.4: 3127 | dependencies: 3128 | nanoid: 3.3.11 3129 | picocolors: 1.1.1 3130 | source-map-js: 1.2.1 3131 | 3132 | prettier@2.8.8: {} 3133 | 3134 | proxy-addr@2.0.7: 3135 | dependencies: 3136 | forwarded: 0.2.0 3137 | ipaddr.js: 1.9.1 3138 | 3139 | punycode@2.3.1: {} 3140 | 3141 | qs@6.14.0: 3142 | dependencies: 3143 | side-channel: 1.1.0 3144 | 3145 | quansync@0.2.10: {} 3146 | 3147 | queue-microtask@1.2.3: {} 3148 | 3149 | range-parser@1.2.1: {} 3150 | 3151 | raw-body@3.0.0: 3152 | dependencies: 3153 | bytes: 3.1.2 3154 | http-errors: 2.0.0 3155 | iconv-lite: 0.6.3 3156 | unpipe: 1.0.0 3157 | 3158 | react-dom@18.3.1(react@18.3.1): 3159 | dependencies: 3160 | loose-envify: 1.4.0 3161 | react: 18.3.1 3162 | scheduler: 0.23.2 3163 | 3164 | react@18.3.1: 3165 | dependencies: 3166 | loose-envify: 1.4.0 3167 | 3168 | read-yaml-file@1.1.0: 3169 | dependencies: 3170 | graceful-fs: 4.2.11 3171 | js-yaml: 3.14.1 3172 | pify: 4.0.1 3173 | strip-bom: 3.0.0 3174 | 3175 | readdirp@3.6.0: 3176 | dependencies: 3177 | picomatch: 2.3.1 3178 | 3179 | redis@4.6.0: 3180 | dependencies: 3181 | '@redis/bloom': 1.2.0(@redis/client@1.5.0) 3182 | '@redis/client': 1.5.0 3183 | '@redis/graph': 1.1.0(@redis/client@1.5.0) 3184 | '@redis/json': 1.0.4(@redis/client@1.5.0) 3185 | '@redis/search': 1.1.1(@redis/client@1.5.0) 3186 | '@redis/time-series': 1.0.4(@redis/client@1.5.0) 3187 | 3188 | require-from-string@2.0.2: {} 3189 | 3190 | resolve-from@5.0.0: {} 3191 | 3192 | reusify@1.1.0: {} 3193 | 3194 | rollup@4.40.2: 3195 | dependencies: 3196 | '@types/estree': 1.0.7 3197 | optionalDependencies: 3198 | '@rollup/rollup-android-arm-eabi': 4.40.2 3199 | '@rollup/rollup-android-arm64': 4.40.2 3200 | '@rollup/rollup-darwin-arm64': 4.40.2 3201 | '@rollup/rollup-darwin-x64': 4.40.2 3202 | '@rollup/rollup-freebsd-arm64': 4.40.2 3203 | '@rollup/rollup-freebsd-x64': 4.40.2 3204 | '@rollup/rollup-linux-arm-gnueabihf': 4.40.2 3205 | '@rollup/rollup-linux-arm-musleabihf': 4.40.2 3206 | '@rollup/rollup-linux-arm64-gnu': 4.40.2 3207 | '@rollup/rollup-linux-arm64-musl': 4.40.2 3208 | '@rollup/rollup-linux-loongarch64-gnu': 4.40.2 3209 | '@rollup/rollup-linux-powerpc64le-gnu': 4.40.2 3210 | '@rollup/rollup-linux-riscv64-gnu': 4.40.2 3211 | '@rollup/rollup-linux-riscv64-musl': 4.40.2 3212 | '@rollup/rollup-linux-s390x-gnu': 4.40.2 3213 | '@rollup/rollup-linux-x64-gnu': 4.40.2 3214 | '@rollup/rollup-linux-x64-musl': 4.40.2 3215 | '@rollup/rollup-win32-arm64-msvc': 4.40.2 3216 | '@rollup/rollup-win32-ia32-msvc': 4.40.2 3217 | '@rollup/rollup-win32-x64-msvc': 4.40.2 3218 | fsevents: 2.3.3 3219 | 3220 | router@2.2.0: 3221 | dependencies: 3222 | debug: 4.4.1 3223 | depd: 2.0.0 3224 | is-promise: 4.0.0 3225 | parseurl: 1.3.3 3226 | path-to-regexp: 8.2.0 3227 | transitivePeerDependencies: 3228 | - supports-color 3229 | 3230 | run-parallel@1.2.0: 3231 | dependencies: 3232 | queue-microtask: 1.2.3 3233 | 3234 | safe-buffer@5.2.1: {} 3235 | 3236 | safer-buffer@2.1.2: {} 3237 | 3238 | scheduler@0.23.2: 3239 | dependencies: 3240 | loose-envify: 1.4.0 3241 | 3242 | semver@7.7.2: {} 3243 | 3244 | send@1.2.0: 3245 | dependencies: 3246 | debug: 4.4.1 3247 | encodeurl: 2.0.0 3248 | escape-html: 1.0.3 3249 | etag: 1.8.1 3250 | fresh: 2.0.0 3251 | http-errors: 2.0.0 3252 | mime-types: 3.0.1 3253 | ms: 2.1.3 3254 | on-finished: 2.4.1 3255 | range-parser: 1.2.1 3256 | statuses: 2.0.1 3257 | transitivePeerDependencies: 3258 | - supports-color 3259 | 3260 | serve-static@2.2.0: 3261 | dependencies: 3262 | encodeurl: 2.0.0 3263 | escape-html: 1.0.3 3264 | parseurl: 1.3.3 3265 | send: 1.2.0 3266 | transitivePeerDependencies: 3267 | - supports-color 3268 | 3269 | setprototypeof@1.2.0: {} 3270 | 3271 | shebang-command@2.0.0: 3272 | dependencies: 3273 | shebang-regex: 3.0.0 3274 | 3275 | shebang-regex@3.0.0: {} 3276 | 3277 | side-channel-list@1.0.0: 3278 | dependencies: 3279 | es-errors: 1.3.0 3280 | object-inspect: 1.13.4 3281 | 3282 | side-channel-map@1.0.1: 3283 | dependencies: 3284 | call-bound: 1.0.4 3285 | es-errors: 1.3.0 3286 | get-intrinsic: 1.3.0 3287 | object-inspect: 1.13.4 3288 | 3289 | side-channel-weakmap@1.0.2: 3290 | dependencies: 3291 | call-bound: 1.0.4 3292 | es-errors: 1.3.0 3293 | get-intrinsic: 1.3.0 3294 | object-inspect: 1.13.4 3295 | side-channel-map: 1.0.1 3296 | 3297 | side-channel@1.1.0: 3298 | dependencies: 3299 | es-errors: 1.3.0 3300 | object-inspect: 1.13.4 3301 | side-channel-list: 1.0.0 3302 | side-channel-map: 1.0.1 3303 | side-channel-weakmap: 1.0.2 3304 | 3305 | siginfo@2.0.0: {} 3306 | 3307 | signal-exit@3.0.7: {} 3308 | 3309 | signal-exit@4.1.0: {} 3310 | 3311 | slash@3.0.0: {} 3312 | 3313 | source-map-js@1.2.1: {} 3314 | 3315 | source-map@0.8.0-beta.0: 3316 | dependencies: 3317 | whatwg-url: 7.1.0 3318 | 3319 | spawndamnit@3.0.1: 3320 | dependencies: 3321 | cross-spawn: 7.0.6 3322 | signal-exit: 4.1.0 3323 | 3324 | sprintf-js@1.0.3: {} 3325 | 3326 | stackback@0.0.2: {} 3327 | 3328 | statuses@2.0.1: {} 3329 | 3330 | std-env@3.9.0: {} 3331 | 3332 | string-width@4.2.3: 3333 | dependencies: 3334 | emoji-regex: 8.0.0 3335 | is-fullwidth-code-point: 3.0.0 3336 | strip-ansi: 6.0.1 3337 | 3338 | string-width@5.1.2: 3339 | dependencies: 3340 | eastasianwidth: 0.2.0 3341 | emoji-regex: 9.2.2 3342 | strip-ansi: 7.1.0 3343 | 3344 | strip-ansi@6.0.1: 3345 | dependencies: 3346 | ansi-regex: 5.0.1 3347 | 3348 | strip-ansi@7.1.0: 3349 | dependencies: 3350 | ansi-regex: 6.1.0 3351 | 3352 | strip-bom@3.0.0: {} 3353 | 3354 | strip-final-newline@2.0.0: {} 3355 | 3356 | styled-jsx@5.1.0(react@18.3.1): 3357 | dependencies: 3358 | client-only: 0.0.1 3359 | react: 18.3.1 3360 | 3361 | sucrase@3.35.0: 3362 | dependencies: 3363 | '@jridgewell/gen-mapping': 0.3.8 3364 | commander: 4.1.1 3365 | glob: 10.4.5 3366 | lines-and-columns: 1.2.4 3367 | mz: 2.7.0 3368 | pirates: 4.0.7 3369 | ts-interface-checker: 0.1.13 3370 | 3371 | term-size@2.2.1: {} 3372 | 3373 | thenify-all@1.6.0: 3374 | dependencies: 3375 | thenify: 3.3.1 3376 | 3377 | thenify@3.3.1: 3378 | dependencies: 3379 | any-promise: 1.3.0 3380 | 3381 | tinybench@2.9.0: {} 3382 | 3383 | tinyexec@0.3.2: {} 3384 | 3385 | tinyglobby@0.2.14: 3386 | dependencies: 3387 | fdir: 6.4.5(picomatch@4.0.2) 3388 | picomatch: 4.0.2 3389 | 3390 | tinypool@1.1.0: {} 3391 | 3392 | tinyrainbow@2.0.0: {} 3393 | 3394 | tinyspy@4.0.3: {} 3395 | 3396 | tmp@0.0.33: 3397 | dependencies: 3398 | os-tmpdir: 1.0.2 3399 | 3400 | to-regex-range@5.0.1: 3401 | dependencies: 3402 | is-number: 7.0.0 3403 | 3404 | toidentifier@1.0.1: {} 3405 | 3406 | tr46@1.0.1: 3407 | dependencies: 3408 | punycode: 2.3.1 3409 | 3410 | tree-kill@1.2.2: {} 3411 | 3412 | ts-interface-checker@0.1.13: {} 3413 | 3414 | tslib@2.8.1: {} 3415 | 3416 | tsup@8.0.0(postcss@8.5.4)(typescript@5.0.2): 3417 | dependencies: 3418 | bundle-require: 4.2.1(esbuild@0.19.12) 3419 | cac: 6.7.14 3420 | chokidar: 3.6.0 3421 | debug: 4.4.1 3422 | esbuild: 0.19.12 3423 | execa: 5.1.1 3424 | globby: 11.1.0 3425 | joycon: 3.1.1 3426 | postcss-load-config: 4.0.2(postcss@8.5.4) 3427 | resolve-from: 5.0.0 3428 | rollup: 4.40.2 3429 | source-map: 0.8.0-beta.0 3430 | sucrase: 3.35.0 3431 | tree-kill: 1.2.2 3432 | optionalDependencies: 3433 | postcss: 8.5.4 3434 | typescript: 5.0.2 3435 | transitivePeerDependencies: 3436 | - supports-color 3437 | - ts-node 3438 | 3439 | type-is@2.0.1: 3440 | dependencies: 3441 | content-type: 1.0.5 3442 | media-typer: 1.1.0 3443 | mime-types: 3.0.1 3444 | 3445 | typescript@5.0.2: {} 3446 | 3447 | undici-types@6.21.0: {} 3448 | 3449 | universalify@0.1.2: {} 3450 | 3451 | unpipe@1.0.0: {} 3452 | 3453 | use-sync-external-store@1.2.0(react@18.3.1): 3454 | dependencies: 3455 | react: 18.3.1 3456 | 3457 | vary@1.1.2: {} 3458 | 3459 | vite-node@3.2.1(@types/node@22.15.8)(yaml@2.8.0): 3460 | dependencies: 3461 | cac: 6.7.14 3462 | debug: 4.4.1 3463 | es-module-lexer: 1.7.0 3464 | pathe: 2.0.3 3465 | vite: 6.3.5(@types/node@22.15.8)(yaml@2.8.0) 3466 | transitivePeerDependencies: 3467 | - '@types/node' 3468 | - jiti 3469 | - less 3470 | - lightningcss 3471 | - sass 3472 | - sass-embedded 3473 | - stylus 3474 | - sugarss 3475 | - supports-color 3476 | - terser 3477 | - tsx 3478 | - yaml 3479 | 3480 | vite@6.3.5(@types/node@22.15.8)(yaml@2.8.0): 3481 | dependencies: 3482 | esbuild: 0.25.5 3483 | fdir: 6.4.5(picomatch@4.0.2) 3484 | picomatch: 4.0.2 3485 | postcss: 8.5.4 3486 | rollup: 4.40.2 3487 | tinyglobby: 0.2.14 3488 | optionalDependencies: 3489 | '@types/node': 22.15.8 3490 | fsevents: 2.3.3 3491 | yaml: 2.8.0 3492 | 3493 | vitest@3.2.1(@types/node@22.15.8)(yaml@2.8.0): 3494 | dependencies: 3495 | '@types/chai': 5.2.2 3496 | '@vitest/expect': 3.2.1 3497 | '@vitest/mocker': 3.2.1(vite@6.3.5(@types/node@22.15.8)(yaml@2.8.0)) 3498 | '@vitest/pretty-format': 3.2.1 3499 | '@vitest/runner': 3.2.1 3500 | '@vitest/snapshot': 3.2.1 3501 | '@vitest/spy': 3.2.1 3502 | '@vitest/utils': 3.2.1 3503 | chai: 5.2.0 3504 | debug: 4.4.1 3505 | expect-type: 1.2.1 3506 | magic-string: 0.30.17 3507 | pathe: 2.0.3 3508 | picomatch: 4.0.2 3509 | std-env: 3.9.0 3510 | tinybench: 2.9.0 3511 | tinyexec: 0.3.2 3512 | tinyglobby: 0.2.14 3513 | tinypool: 1.1.0 3514 | tinyrainbow: 2.0.0 3515 | vite: 6.3.5(@types/node@22.15.8)(yaml@2.8.0) 3516 | vite-node: 3.2.1(@types/node@22.15.8)(yaml@2.8.0) 3517 | why-is-node-running: 2.3.0 3518 | optionalDependencies: 3519 | '@types/node': 22.15.8 3520 | transitivePeerDependencies: 3521 | - jiti 3522 | - less 3523 | - lightningcss 3524 | - msw 3525 | - sass 3526 | - sass-embedded 3527 | - stylus 3528 | - sugarss 3529 | - supports-color 3530 | - terser 3531 | - tsx 3532 | - yaml 3533 | 3534 | webidl-conversions@4.0.2: {} 3535 | 3536 | whatwg-url@7.1.0: 3537 | dependencies: 3538 | lodash.sortby: 4.7.0 3539 | tr46: 1.0.1 3540 | webidl-conversions: 4.0.2 3541 | 3542 | which@2.0.2: 3543 | dependencies: 3544 | isexe: 2.0.0 3545 | 3546 | why-is-node-running@2.3.0: 3547 | dependencies: 3548 | siginfo: 2.0.0 3549 | stackback: 0.0.2 3550 | 3551 | wrap-ansi@7.0.0: 3552 | dependencies: 3553 | ansi-styles: 4.3.0 3554 | string-width: 4.2.3 3555 | strip-ansi: 6.0.1 3556 | 3557 | wrap-ansi@8.1.0: 3558 | dependencies: 3559 | ansi-styles: 6.2.1 3560 | string-width: 5.1.2 3561 | strip-ansi: 7.1.0 3562 | 3563 | wrappy@1.0.2: {} 3564 | 3565 | yallist@4.0.0: {} 3566 | 3567 | yaml@2.8.0: {} 3568 | 3569 | zod-to-json-schema@3.24.5(zod@3.25.50): 3570 | dependencies: 3571 | zod: 3.25.50 3572 | 3573 | zod@3.25.50: {} 3574 | --------------------------------------------------------------------------------