github-to-mcp-monorepo 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +8 -0
- package/.github/CODEOWNERS +6 -0
- package/.husky/pre-commit +1 -0
- package/.nvmrc +1 -0
- package/.prettierignore +5 -0
- package/.prettierrc +7 -0
- package/.vscode/settings.json +4 -0
- package/ARCHITECTURE.md +1429 -0
- package/CHANGELOG.md +167 -0
- package/CONTRIBUTING.md +327 -0
- package/LICENSE +201 -0
- package/README.md +1028 -0
- package/SECURITY.md +248 -0
- package/VISUAL_GUIDE.md +437 -0
- package/apps/vscode/IMPLEMENTATION.md +480 -0
- package/apps/vscode/README.md +248 -0
- package/apps/vscode/package.json +381 -0
- package/apps/vscode/resources/icon.png +0 -0
- package/apps/vscode/resources/icon.svg +5 -0
- package/apps/vscode/src/commands/browseRegistry.ts +211 -0
- package/apps/vscode/src/commands/configureClaudeDesktop.ts +332 -0
- package/apps/vscode/src/commands/convert.ts +82 -0
- package/apps/vscode/src/commands/convertCurrentRepo.ts +109 -0
- package/apps/vscode/src/commands/convertFromUrl.ts +138 -0
- package/apps/vscode/src/commands/index.ts +121 -0
- package/apps/vscode/src/commands/validate.ts +197 -0
- package/apps/vscode/src/extension.ts +464 -0
- package/apps/vscode/src/global.d.ts +36 -0
- package/apps/vscode/src/test/extension.test.ts +73 -0
- package/apps/vscode/src/utils/file-generator.ts +529 -0
- package/apps/vscode/src/utils/github-api.ts +335 -0
- package/apps/vscode/src/utils/index.ts +29 -0
- package/apps/vscode/src/utils/mcp-config.ts +334 -0
- package/apps/vscode/src/utils/storage.ts +87 -0
- package/apps/vscode/src/views/McpServersTreeView.ts +160 -0
- package/apps/vscode/src/views/OutputChannelView.ts +195 -0
- package/apps/vscode/src/views/StatusBarItem.ts +251 -0
- package/apps/vscode/src/views/ToolsExplorerView.ts +314 -0
- package/apps/vscode/src/views/historyProvider.ts +75 -0
- package/apps/vscode/src/views/index.ts +12 -0
- package/apps/vscode/src/views/resultsPanel.ts +330 -0
- package/apps/vscode/src/webviews/ConversionPanel.ts +350 -0
- package/apps/vscode/src/webviews/ToolDetailsPanel.ts +448 -0
- package/apps/vscode/src/webviews/index.ts +9 -0
- package/apps/vscode/src/webviews/webview-ui/styles.ts +492 -0
- package/apps/vscode/tsconfig.json +20 -0
- package/apps/web/PLAYGROUND_GUIDE.md +499 -0
- package/apps/web/README.md +505 -0
- package/apps/web/app/api/convert/route.ts +100 -0
- package/apps/web/app/api/convert/stream/route.ts +198 -0
- package/apps/web/app/api/deploy/route.ts +157 -0
- package/apps/web/app/api/edge/route.ts +308 -0
- package/apps/web/app/api/export-docker/route.ts +284 -0
- package/apps/web/app/api/generate-openapi/route.ts +119 -0
- package/apps/web/app/api/mcp/[serverId]/route.ts +263 -0
- package/apps/web/app/api/playground/connect/route.ts +143 -0
- package/apps/web/app/api/playground/disconnect/route.ts +78 -0
- package/apps/web/app/api/playground/execute/route.ts +135 -0
- package/apps/web/app/api/playground/sessions/route.ts +103 -0
- package/apps/web/app/api/playground/tools/route.ts +117 -0
- package/apps/web/app/api/playground/v2/connect/route.ts +96 -0
- package/apps/web/app/api/playground/v2/disconnect/route.ts +88 -0
- package/apps/web/app/api/playground/v2/health/route.ts +80 -0
- package/apps/web/app/api/playground/v2/prompts/route.ts +160 -0
- package/apps/web/app/api/playground/v2/resources/route.ts +159 -0
- package/apps/web/app/api/playground/v2/sessions/route.ts +184 -0
- package/apps/web/app/api/playground/v2/tools/route.ts +167 -0
- package/apps/web/app/api/stream/route.ts +232 -0
- package/apps/web/app/batch/BatchConvertClient.tsx +190 -0
- package/apps/web/app/batch/page.tsx +37 -0
- package/apps/web/app/convert/page.tsx +269 -0
- package/apps/web/app/dashboard/page.tsx +380 -0
- package/apps/web/app/globals.css +622 -0
- package/apps/web/app/layout.tsx +120 -0
- package/apps/web/app/manifest.ts +31 -0
- package/apps/web/app/opengraph-image.tsx +112 -0
- package/apps/web/app/page.old.tsx +924 -0
- package/apps/web/app/page.tsx +77 -0
- package/apps/web/app/playground/page.tsx +306 -0
- package/apps/web/app/playground/v2/error.tsx +163 -0
- package/apps/web/app/playground/v2/layout.tsx +58 -0
- package/apps/web/app/playground/v2/loading.tsx +152 -0
- package/apps/web/app/playground/v2/page.tsx +644 -0
- package/apps/web/app/playground/v2/providers.tsx +214 -0
- package/apps/web/app/playground/v2/use-shortcuts.ts +209 -0
- package/apps/web/app/playground/v2/use-url-state.ts +296 -0
- package/apps/web/app/providers.tsx +22 -0
- package/apps/web/app/sitemap.ts +32 -0
- package/apps/web/app/twitter-image.tsx +112 -0
- package/apps/web/components/BranchSelector.tsx +401 -0
- package/apps/web/components/ClaudeConfigExport.tsx +226 -0
- package/apps/web/components/Features.tsx +84 -0
- package/apps/web/components/Footer.tsx +119 -0
- package/apps/web/components/GenerationProgress.tsx +248 -0
- package/apps/web/components/GithubUrlInput.tsx +483 -0
- package/apps/web/components/Header.tsx +175 -0
- package/apps/web/components/Hero.tsx +117 -0
- package/apps/web/components/HowItWorks.tsx +119 -0
- package/apps/web/components/InstallBanner.tsx +158 -0
- package/apps/web/components/Logo.tsx +116 -0
- package/apps/web/components/ParticleBackground.tsx +105 -0
- package/apps/web/components/Playground.tsx +472 -0
- package/apps/web/components/PlaygroundToolTester.tsx +410 -0
- package/apps/web/components/ProductCards.tsx +179 -0
- package/apps/web/components/SplitView.tsx +194 -0
- package/apps/web/components/ToolFilter.tsx +260 -0
- package/apps/web/components/ToolList.tsx +325 -0
- package/apps/web/components/batch/BatchConvert.tsx +785 -0
- package/apps/web/components/batch/index.ts +7 -0
- package/apps/web/components/convert/ConfigTabs.tsx +230 -0
- package/apps/web/components/convert/ConversionResult.tsx +482 -0
- package/apps/web/components/convert/InlinePlayground.tsx +259 -0
- package/apps/web/components/convert/LoadingSteps.tsx +311 -0
- package/apps/web/components/convert/OneClickInstall.tsx +224 -0
- package/apps/web/components/convert/ToolCard.tsx +189 -0
- package/apps/web/components/convert/TryInPlayground.tsx +242 -0
- package/apps/web/components/convert/index.ts +12 -0
- package/apps/web/components/deploy/DeployButton.tsx +369 -0
- package/apps/web/components/deploy/index.ts +7 -0
- package/apps/web/components/docker/DockerExport.tsx +690 -0
- package/apps/web/components/docker/index.ts +7 -0
- package/apps/web/components/install/OneClickInstall.tsx +676 -0
- package/apps/web/components/install/index.ts +7 -0
- package/apps/web/components/playground/CapabilityTabs.tsx +150 -0
- package/apps/web/components/playground/ConnectionStatusV2.tsx +322 -0
- package/apps/web/components/playground/EmptyStates.tsx +305 -0
- package/apps/web/components/playground/ExecutionLog.tsx +260 -0
- package/apps/web/components/playground/ExecutionLogV2.tsx +378 -0
- package/apps/web/components/playground/JsonViewer.tsx +388 -0
- package/apps/web/components/playground/PlaygroundLayout.tsx +244 -0
- package/apps/web/components/playground/PromptsPanel.tsx +385 -0
- package/apps/web/components/playground/ResourcesPanel.tsx +378 -0
- package/apps/web/components/playground/SchemaForm.tsx +477 -0
- package/apps/web/components/playground/ServerStatus.tsx +151 -0
- package/apps/web/components/playground/ShareButton.tsx +239 -0
- package/apps/web/components/playground/ToolsPanel.tsx +309 -0
- package/apps/web/components/playground/TransportConfigurator.tsx +563 -0
- package/apps/web/components/playground/index.ts +74 -0
- package/apps/web/components/playground/types.ts +202 -0
- package/apps/web/components/streaming/StreamingProgress.tsx +441 -0
- package/apps/web/components/streaming/index.ts +7 -0
- package/apps/web/components/ui/badge.tsx +42 -0
- package/apps/web/components/ui/button.tsx +88 -0
- package/apps/web/components/ui/card.tsx +75 -0
- package/apps/web/components/ui/code-block.tsx +122 -0
- package/apps/web/components/ui/index.ts +12 -0
- package/apps/web/components/ui/input.tsx +55 -0
- package/apps/web/components/ui/tabs.tsx +61 -0
- package/apps/web/hooks/index.ts +85 -0
- package/apps/web/hooks/types.ts +1173 -0
- package/apps/web/hooks/use-conversion.ts +133 -0
- package/apps/web/hooks/use-execution-history.ts +376 -0
- package/apps/web/hooks/use-generation-progress.ts +147 -0
- package/apps/web/hooks/use-local-storage.ts +88 -0
- package/apps/web/hooks/use-mcp-client.ts +623 -0
- package/apps/web/hooks/use-mcp-connection.ts +500 -0
- package/apps/web/hooks/use-mcp-execution.ts +282 -0
- package/apps/web/hooks/use-mcp-prompts.ts +441 -0
- package/apps/web/hooks/use-mcp-resources.ts +430 -0
- package/apps/web/hooks/use-mcp-tools.ts +540 -0
- package/apps/web/hooks/use-playground-store.ts +299 -0
- package/apps/web/hooks/use-playground.ts +184 -0
- package/apps/web/hooks/use-streaming-conversion.ts +227 -0
- package/apps/web/hooks/useBatchConversion.ts +271 -0
- package/apps/web/hooks/useDockerConfig.ts +161 -0
- package/apps/web/hooks/usePlatformDetection.ts +80 -0
- package/apps/web/hooks/useStreaming.ts +199 -0
- package/apps/web/lib/api/errors.ts +386 -0
- package/apps/web/lib/api/index.ts +137 -0
- package/apps/web/lib/api/logger.ts +187 -0
- package/apps/web/lib/api/middleware.ts +364 -0
- package/apps/web/lib/api/openapi.ts +977 -0
- package/apps/web/lib/api/session-manager.ts +594 -0
- package/apps/web/lib/api/types.ts +433 -0
- package/apps/web/lib/api/validation.ts +523 -0
- package/apps/web/lib/constants.ts +114 -0
- package/apps/web/lib/mcp/client.ts +1137 -0
- package/apps/web/lib/mcp/events.ts +651 -0
- package/apps/web/lib/mcp/index.ts +347 -0
- package/apps/web/lib/mcp/logger.ts +428 -0
- package/apps/web/lib/mcp/metrics.ts +703 -0
- package/apps/web/lib/mcp/retry.ts +616 -0
- package/apps/web/lib/mcp/session-manager.ts +779 -0
- package/apps/web/lib/mcp/transports.ts +988 -0
- package/apps/web/lib/mcp/types.ts +594 -0
- package/apps/web/lib/mcp-client-enhanced.ts +871 -0
- package/apps/web/lib/mcp-client.ts +778 -0
- package/apps/web/lib/mcp-errors.ts +489 -0
- package/apps/web/lib/mcp-sandbox.ts +593 -0
- package/apps/web/lib/mcp-testing.ts +428 -0
- package/apps/web/lib/mcp-types.ts +448 -0
- package/apps/web/lib/playground-store.tsx +1147 -0
- package/apps/web/lib/utils.ts +439 -0
- package/apps/web/next-env.d.ts +5 -0
- package/apps/web/next.config.js +23 -0
- package/apps/web/package.json +55 -0
- package/apps/web/postcss.config.js +6 -0
- package/apps/web/public/.well-known/ai-plugin.json +17 -0
- package/apps/web/public/logo.svg +6 -0
- package/apps/web/public/robots.txt +22 -0
- package/apps/web/public/schema.json +27 -0
- package/apps/web/tailwind.config.js +26 -0
- package/apps/web/tailwind.config.ts +123 -0
- package/apps/web/tsconfig.json +20 -0
- package/apps/web/types/deploy.ts +139 -0
- package/apps/web/types/index.ts +247 -0
- package/apps/web/vercel.json +39 -0
- package/eslint.config.mjs +23 -0
- package/llms.txt +102 -0
- package/mkdocs/docs/api/core.md +318 -0
- package/mkdocs/docs/api/index.md +128 -0
- package/mkdocs/docs/api/mcp-server.md +301 -0
- package/mkdocs/docs/api/openapi-parser.md +254 -0
- package/mkdocs/docs/assets/logo.svg +7 -0
- package/mkdocs/docs/changelog.md +118 -0
- package/mkdocs/docs/cli/generate.md +148 -0
- package/mkdocs/docs/cli/index.md +52 -0
- package/mkdocs/docs/cli/inspect.md +164 -0
- package/mkdocs/docs/cli/serve.md +136 -0
- package/mkdocs/docs/concepts/classification.md +254 -0
- package/mkdocs/docs/concepts/how-it-works.md +299 -0
- package/mkdocs/docs/concepts/index.md +77 -0
- package/mkdocs/docs/concepts/mcp-protocol.md +362 -0
- package/mkdocs/docs/concepts/tool-types.md +382 -0
- package/mkdocs/docs/contributing/architecture.md +262 -0
- package/mkdocs/docs/contributing/development.md +245 -0
- package/mkdocs/docs/contributing/index.md +73 -0
- package/mkdocs/docs/contributing/testing.md +320 -0
- package/mkdocs/docs/getting-started/configuration.md +235 -0
- package/mkdocs/docs/getting-started/index.md +54 -0
- package/mkdocs/docs/getting-started/installation.md +145 -0
- package/mkdocs/docs/getting-started/quickstart.md +160 -0
- package/mkdocs/docs/guides/batch.md +375 -0
- package/mkdocs/docs/guides/claude-desktop.md +227 -0
- package/mkdocs/docs/guides/cursor.md +188 -0
- package/mkdocs/docs/guides/custom-tools.md +367 -0
- package/mkdocs/docs/guides/index.md +78 -0
- package/mkdocs/docs/guides/private-repos.md +221 -0
- package/mkdocs/docs/guides/vscode.md +247 -0
- package/mkdocs/docs/index.md +175 -0
- package/mkdocs/docs/reference/config.md +223 -0
- package/mkdocs/docs/reference/env.md +192 -0
- package/mkdocs/docs/reference/index.md +102 -0
- package/mkdocs/docs/reference/tools.md +309 -0
- package/mkdocs/docs/stylesheets/extra.css +231 -0
- package/mkdocs/mkdocs.yml +204 -0
- package/mkdocs/overrides/.gitkeep +1 -0
- package/mkdocs/overrides/main.html +7 -0
- package/mkdocs/python-deps.txt +7 -0
- package/mkdocs/vercel.json +11 -0
- package/package.json +63 -0
- package/packages/core/package.json +61 -0
- package/packages/core/src/__tests__/bitbucket-client.test.ts +366 -0
- package/packages/core/src/__tests__/cli.test.ts +235 -0
- package/packages/core/src/__tests__/code-extractor.test.ts +378 -0
- package/packages/core/src/__tests__/docker-generator.test.ts +255 -0
- package/packages/core/src/__tests__/github-client.test.ts +390 -0
- package/packages/core/src/__tests__/gitlab-client.test.ts +319 -0
- package/packages/core/src/__tests__/go-extractor.test.ts +351 -0
- package/packages/core/src/__tests__/graphql-extractor.test.ts +330 -0
- package/packages/core/src/__tests__/java-extractor.test.ts +497 -0
- package/packages/core/src/__tests__/plugins.test.ts +467 -0
- package/packages/core/src/__tests__/readme-extractor.test.ts +258 -0
- package/packages/core/src/__tests__/redis-cache.test.ts +307 -0
- package/packages/core/src/__tests__/rust-extractor.test.ts +252 -0
- package/packages/core/src/__tests__/streaming.test.ts +251 -0
- package/packages/core/src/additional-extractors.ts +333 -0
- package/packages/core/src/cache/cache-interface.ts +179 -0
- package/packages/core/src/cache/index.ts +210 -0
- package/packages/core/src/cache/redis-cache.ts +291 -0
- package/packages/core/src/cache/upstash-cache.ts +379 -0
- package/packages/core/src/cache.ts +251 -0
- package/packages/core/src/cli.ts +822 -0
- package/packages/core/src/code-extractor.ts +696 -0
- package/packages/core/src/docker-generator.ts +470 -0
- package/packages/core/src/edge-compatible.ts +491 -0
- package/packages/core/src/extractors/go-extractor.ts +791 -0
- package/packages/core/src/extractors/index.ts +9 -0
- package/packages/core/src/extractors/java-extractor.ts +937 -0
- package/packages/core/src/extractors/rust-extractor.ts +744 -0
- package/packages/core/src/github-client.ts +319 -0
- package/packages/core/src/go-generator.ts +356 -0
- package/packages/core/src/graphql-extractor.ts +358 -0
- package/packages/core/src/index.ts +797 -0
- package/packages/core/src/langchain-exporter.ts +617 -0
- package/packages/core/src/language-parsers.ts +1114 -0
- package/packages/core/src/mcp-introspector.ts +279 -0
- package/packages/core/src/monorepo-detector.ts +378 -0
- package/packages/core/src/plugins/index.ts +370 -0
- package/packages/core/src/plugins/registry.ts +404 -0
- package/packages/core/src/plugins/types.ts +215 -0
- package/packages/core/src/providers/base-provider.ts +246 -0
- package/packages/core/src/providers/bitbucket-client.ts +464 -0
- package/packages/core/src/providers/gitlab-client.ts +388 -0
- package/packages/core/src/providers/index.ts +176 -0
- package/packages/core/src/python-generator.ts +260 -0
- package/packages/core/src/queue/index.ts +100 -0
- package/packages/core/src/queue/memory-queue.ts +445 -0
- package/packages/core/src/queue/redis-queue.ts +578 -0
- package/packages/core/src/queue/types.ts +251 -0
- package/packages/core/src/readme-extractor.ts +409 -0
- package/packages/core/src/schema-generator.ts +638 -0
- package/packages/core/src/streaming.ts +999 -0
- package/packages/core/src/types.ts +289 -0
- package/packages/core/tsconfig.json +9 -0
- package/packages/core/tsup.config.ts +25 -0
- package/packages/mcp-server/README.md +297 -0
- package/packages/mcp-server/package.json +55 -0
- package/packages/mcp-server/src/__tests__/mcp-server.test.ts +177 -0
- package/packages/mcp-server/src/__tests__/tools.test.ts +217 -0
- package/packages/mcp-server/src/index.ts +1206 -0
- package/packages/mcp-server/src/prompts/index.ts +601 -0
- package/packages/mcp-server/src/tools/export-docker.ts +362 -0
- package/packages/mcp-server/src/tools/generate-openapi.ts +162 -0
- package/packages/mcp-server/src/tools/monitor-mcp-server.ts +448 -0
- package/packages/mcp-server/src/tools/stream-convert.ts +398 -0
- package/packages/mcp-server/src/tools/test-mcp-tool.ts +531 -0
- package/packages/mcp-server/tsconfig.json +12 -0
- package/packages/mcp-server/tsup.config.ts +14 -0
- package/packages/openapi-parser/package-lock.json +3028 -0
- package/packages/openapi-parser/package.json +41 -0
- package/packages/openapi-parser/src/analyzer.ts +700 -0
- package/packages/openapi-parser/src/asyncapi-parser.ts +475 -0
- package/packages/openapi-parser/src/cli.ts +302 -0
- package/packages/openapi-parser/src/generator.ts +570 -0
- package/packages/openapi-parser/src/generators/express-analyzer.ts +649 -0
- package/packages/openapi-parser/src/generators/fastapi-analyzer.ts +960 -0
- package/packages/openapi-parser/src/generators/index.ts +200 -0
- package/packages/openapi-parser/src/generators/nextjs-analyzer.ts +768 -0
- package/packages/openapi-parser/src/generators/openapi-builder.ts +527 -0
- package/packages/openapi-parser/src/generators/types.ts +298 -0
- package/packages/openapi-parser/src/graphql-parser.ts +462 -0
- package/packages/openapi-parser/src/grpc-parser.ts +649 -0
- package/packages/openapi-parser/src/har-parser.ts +723 -0
- package/packages/openapi-parser/src/index.ts +635 -0
- package/packages/openapi-parser/src/insomnia-parser.ts +614 -0
- package/packages/openapi-parser/src/parser.ts +231 -0
- package/packages/openapi-parser/src/postman-parser.ts +611 -0
- package/packages/openapi-parser/src/ref-resolver.ts +313 -0
- package/packages/openapi-parser/src/transformer.ts +459 -0
- package/packages/openapi-parser/tests/generators/express.test.ts +209 -0
- package/packages/openapi-parser/tests/generators/fastapi.test.ts +236 -0
- package/packages/openapi-parser/tests/generators/nextjs.test.ts +273 -0
- package/packages/openapi-parser/tests/parsers.test.ts +847 -0
- package/packages/openapi-parser/tsconfig.json +9 -0
- package/packages/openapi-parser/tsup.config.ts +11 -0
- package/packages/registry/package.json +59 -0
- package/packages/registry/src/cli.ts +456 -0
- package/packages/registry/src/index.ts +44 -0
- package/packages/registry/src/popular/github.json +47 -0
- package/packages/registry/src/popular/index.ts +55 -0
- package/packages/registry/src/popular/linear.json +42 -0
- package/packages/registry/src/popular/notion.json +42 -0
- package/packages/registry/src/popular/openai.json +40 -0
- package/packages/registry/src/popular/resend.json +38 -0
- package/packages/registry/src/popular/slack.json +42 -0
- package/packages/registry/src/popular/stripe.json +163 -0
- package/packages/registry/src/popular/supabase.json +42 -0
- package/packages/registry/src/popular/twilio.json +40 -0
- package/packages/registry/src/popular/vercel.json +40 -0
- package/packages/registry/src/registry.ts +492 -0
- package/packages/registry/src/storage.ts +334 -0
- package/packages/registry/src/types.ts +275 -0
- package/packages/registry/src/updater.ts +208 -0
- package/packages/registry/tsconfig.json +10 -0
- package/packages/registry/tsup.config.ts +11 -0
- package/pnpm-workspace.yaml +3 -0
- package/scripts/build-docs.sh +16 -0
- package/server.json +9 -0
- package/templates/Dockerfile.python.template +60 -0
- package/templates/Dockerfile.typescript.template +60 -0
- package/templates/docker-compose.template.yml +68 -0
- package/tests/fixtures/express-app/index.js +34 -0
- package/tests/fixtures/express-app/routes/posts.js +43 -0
- package/tests/fixtures/express-app/routes/users.js +58 -0
- package/tests/fixtures/fastapi-app/main.py +125 -0
- package/tests/fixtures/fastapi-app/routes/admin.py +42 -0
- package/tests/fixtures/graphql/simple-schema.graphql +65 -0
- package/tests/fixtures/mocks/github-api-responses.json +63 -0
- package/tests/fixtures/nextjs-app/app/api/posts/route.ts +55 -0
- package/tests/fixtures/nextjs-app/app/api/users/[id]/route.ts +63 -0
- package/tests/fixtures/nextjs-app/app/api/users/route.ts +44 -0
- package/tests/fixtures/nextjs-app/pages/api/health.ts +28 -0
- package/tests/fixtures/openapi/petstore.yaml +179 -0
- package/tests/integration/langchain-export.test.ts +405 -0
- package/tests/integration/openapi-conversion.test.ts +221 -0
- package/tsconfig.json +18 -0
- package/vitest.config.ts +32 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Disconnect API Route
|
|
3
|
+
*
|
|
4
|
+
* POST /api/playground/v2/disconnect
|
|
5
|
+
* Closes an MCP server connection and cleans up the session.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
9
|
+
import {
|
|
10
|
+
handleApiError,
|
|
11
|
+
createSuccessResponse,
|
|
12
|
+
SessionExpiredError,
|
|
13
|
+
validateSessionId,
|
|
14
|
+
applyMiddleware,
|
|
15
|
+
corsPreflightResponse,
|
|
16
|
+
createLogContext,
|
|
17
|
+
SessionManager,
|
|
18
|
+
withRequestId,
|
|
19
|
+
} from '@/lib/api';
|
|
20
|
+
import type { DisconnectResponseData } from '@/lib/api';
|
|
21
|
+
|
|
22
|
+
const PATH = '/api/playground/v2/disconnect';
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Handle CORS preflight request
|
|
26
|
+
*/
|
|
27
|
+
export async function OPTIONS(): Promise<NextResponse> {
|
|
28
|
+
return corsPreflightResponse({ methods: ['POST', 'OPTIONS'] });
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* POST /api/playground/v2/disconnect
|
|
33
|
+
*
|
|
34
|
+
* Closes an MCP server connection.
|
|
35
|
+
*
|
|
36
|
+
* Request body:
|
|
37
|
+
* - sessionId: string (required) - The session ID to disconnect
|
|
38
|
+
*
|
|
39
|
+
* Response:
|
|
40
|
+
* - success: boolean
|
|
41
|
+
* - data: { disconnected: boolean }
|
|
42
|
+
*/
|
|
43
|
+
export async function POST(request: NextRequest): Promise<NextResponse> {
|
|
44
|
+
const middleware = await applyMiddleware(request);
|
|
45
|
+
if ('response' in middleware) {
|
|
46
|
+
return middleware.response;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const { context } = middleware;
|
|
50
|
+
const log = createLogContext('POST', PATH, context.requestId, context.clientId);
|
|
51
|
+
|
|
52
|
+
try {
|
|
53
|
+
const body = await request.json();
|
|
54
|
+
const sessionId = validateSessionId(body);
|
|
55
|
+
|
|
56
|
+
const sessionManager = SessionManager.getInstance();
|
|
57
|
+
|
|
58
|
+
// Check if session exists
|
|
59
|
+
const session = await sessionManager.getSession(sessionId);
|
|
60
|
+
if (!session) {
|
|
61
|
+
throw new SessionExpiredError(
|
|
62
|
+
`Session not found or already expired: ${sessionId}`,
|
|
63
|
+
sessionId
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Delete the session
|
|
68
|
+
const deleted = await sessionManager.deleteSession(sessionId);
|
|
69
|
+
|
|
70
|
+
const responseData: DisconnectResponseData = {
|
|
71
|
+
disconnected: deleted,
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
log.log(200, sessionId);
|
|
75
|
+
|
|
76
|
+
return createSuccessResponse(responseData, 200, {
|
|
77
|
+
...context.rateLimitHeaders,
|
|
78
|
+
...withRequestId({}, context.requestId),
|
|
79
|
+
'Access-Control-Allow-Origin': '*',
|
|
80
|
+
});
|
|
81
|
+
} catch (error) {
|
|
82
|
+
const status = error instanceof Error && 'statusCode' in error
|
|
83
|
+
? (error as { statusCode: number }).statusCode
|
|
84
|
+
: 500;
|
|
85
|
+
log.log(status, undefined, error instanceof Error ? error.message : 'Unknown error');
|
|
86
|
+
return handleApiError(error);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Health API Route
|
|
3
|
+
*
|
|
4
|
+
* GET /api/playground/v2/health - Get API health status
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
8
|
+
import {
|
|
9
|
+
handleApiError,
|
|
10
|
+
createSuccessResponse,
|
|
11
|
+
corsPreflightResponse,
|
|
12
|
+
createLogContext,
|
|
13
|
+
SessionManager,
|
|
14
|
+
withRequestId,
|
|
15
|
+
NO_RATE_LIMIT,
|
|
16
|
+
applyMiddleware,
|
|
17
|
+
} from '@/lib/api';
|
|
18
|
+
import type { HealthResponseData } from '@/lib/api';
|
|
19
|
+
|
|
20
|
+
const PATH = '/api/playground/v2/health';
|
|
21
|
+
const startTime = Date.now();
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Handle CORS preflight request
|
|
25
|
+
*/
|
|
26
|
+
export async function OPTIONS(): Promise<NextResponse> {
|
|
27
|
+
return corsPreflightResponse({ methods: ['GET', 'OPTIONS'] });
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* GET /api/playground/v2/health
|
|
32
|
+
*
|
|
33
|
+
* Returns health status of the playground API.
|
|
34
|
+
*
|
|
35
|
+
* Response:
|
|
36
|
+
* - success: boolean
|
|
37
|
+
* - data: { status: string, version: string, uptime: number, sessions: { active: number } }
|
|
38
|
+
*/
|
|
39
|
+
export async function GET(request: NextRequest): Promise<NextResponse> {
|
|
40
|
+
const middleware = await applyMiddleware(request, { rateLimit: NO_RATE_LIMIT });
|
|
41
|
+
if ('response' in middleware) {
|
|
42
|
+
return middleware.response;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const { context } = middleware;
|
|
46
|
+
const log = createLogContext('GET', PATH, context.requestId, context.clientId);
|
|
47
|
+
|
|
48
|
+
try {
|
|
49
|
+
const sessionManager = SessionManager.getInstance();
|
|
50
|
+
const sessions = await sessionManager.listSessions();
|
|
51
|
+
const activeSessions = sessions.length;
|
|
52
|
+
|
|
53
|
+
const uptime = Math.floor((Date.now() - startTime) / 1000);
|
|
54
|
+
|
|
55
|
+
const responseData: HealthResponseData = {
|
|
56
|
+
status: 'healthy',
|
|
57
|
+
version: '2.0.0',
|
|
58
|
+
uptime,
|
|
59
|
+
sessions: {
|
|
60
|
+
active: activeSessions,
|
|
61
|
+
},
|
|
62
|
+
timestamp: new Date().toISOString(),
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
log.log(200, undefined, undefined, { activeSessions, uptime });
|
|
66
|
+
|
|
67
|
+
return createSuccessResponse(responseData, 200, {
|
|
68
|
+
...withRequestId({}, context.requestId),
|
|
69
|
+
'Access-Control-Allow-Origin': '*',
|
|
70
|
+
// Don't cache health checks
|
|
71
|
+
'Cache-Control': 'no-store, no-cache, must-revalidate',
|
|
72
|
+
});
|
|
73
|
+
} catch (error) {
|
|
74
|
+
const status = error instanceof Error && 'statusCode' in error
|
|
75
|
+
? (error as { statusCode: number }).statusCode
|
|
76
|
+
: 500;
|
|
77
|
+
log.log(status, undefined, error instanceof Error ? error.message : 'Unknown error');
|
|
78
|
+
return handleApiError(error);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompts API Route
|
|
3
|
+
*
|
|
4
|
+
* GET /api/playground/v2/prompts - List all prompts
|
|
5
|
+
* POST /api/playground/v2/prompts - Get a prompt
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
9
|
+
import {
|
|
10
|
+
handleApiError,
|
|
11
|
+
createSuccessResponse,
|
|
12
|
+
SessionExpiredError,
|
|
13
|
+
McpExecutionError,
|
|
14
|
+
NotFoundError,
|
|
15
|
+
validatePromptGet,
|
|
16
|
+
validateSessionIdFromQuery,
|
|
17
|
+
applyMiddleware,
|
|
18
|
+
corsPreflightResponse,
|
|
19
|
+
createLogContext,
|
|
20
|
+
SessionManager,
|
|
21
|
+
withRequestId,
|
|
22
|
+
RELAXED_RATE_LIMIT,
|
|
23
|
+
} from '@/lib/api';
|
|
24
|
+
import type { PromptsListResponseData, PromptGetResponseData } from '@/lib/api';
|
|
25
|
+
|
|
26
|
+
const PATH = '/api/playground/v2/prompts';
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Handle CORS preflight request
|
|
30
|
+
*/
|
|
31
|
+
export async function OPTIONS(): Promise<NextResponse> {
|
|
32
|
+
return corsPreflightResponse({ methods: ['GET', 'POST', 'OPTIONS'] });
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* GET /api/playground/v2/prompts
|
|
37
|
+
*
|
|
38
|
+
* Lists all available prompts for a session.
|
|
39
|
+
*
|
|
40
|
+
* Query parameters:
|
|
41
|
+
* - sessionId: string (required) - The session ID
|
|
42
|
+
*
|
|
43
|
+
* Response:
|
|
44
|
+
* - success: boolean
|
|
45
|
+
* - data: { prompts: McpPrompt[] }
|
|
46
|
+
*/
|
|
47
|
+
export async function GET(request: NextRequest): Promise<NextResponse> {
|
|
48
|
+
const middleware = await applyMiddleware(request, { rateLimit: RELAXED_RATE_LIMIT });
|
|
49
|
+
if ('response' in middleware) {
|
|
50
|
+
return middleware.response;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const { context } = middleware;
|
|
54
|
+
const log = createLogContext('GET', PATH, context.requestId, context.clientId);
|
|
55
|
+
|
|
56
|
+
try {
|
|
57
|
+
const { searchParams } = new URL(request.url);
|
|
58
|
+
const sessionId = validateSessionIdFromQuery(searchParams);
|
|
59
|
+
|
|
60
|
+
const sessionManager = SessionManager.getInstance();
|
|
61
|
+
|
|
62
|
+
const session = await sessionManager.getSession(sessionId);
|
|
63
|
+
if (!session) {
|
|
64
|
+
throw new SessionExpiredError(
|
|
65
|
+
`Session not found or expired: ${sessionId}`,
|
|
66
|
+
sessionId
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const prompts = await sessionManager.listPrompts(sessionId);
|
|
71
|
+
|
|
72
|
+
const responseData: PromptsListResponseData = { prompts };
|
|
73
|
+
|
|
74
|
+
log.log(200, sessionId);
|
|
75
|
+
|
|
76
|
+
return createSuccessResponse(responseData, 200, {
|
|
77
|
+
...context.rateLimitHeaders,
|
|
78
|
+
...withRequestId({}, context.requestId),
|
|
79
|
+
'Access-Control-Allow-Origin': '*',
|
|
80
|
+
});
|
|
81
|
+
} catch (error) {
|
|
82
|
+
const status = error instanceof Error && 'statusCode' in error
|
|
83
|
+
? (error as { statusCode: number }).statusCode
|
|
84
|
+
: 500;
|
|
85
|
+
log.log(status, undefined, error instanceof Error ? error.message : 'Unknown error');
|
|
86
|
+
return handleApiError(error);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* POST /api/playground/v2/prompts
|
|
92
|
+
*
|
|
93
|
+
* Gets a prompt with optional arguments.
|
|
94
|
+
*
|
|
95
|
+
* Request body:
|
|
96
|
+
* - sessionId: string (required) - The session ID
|
|
97
|
+
* - name: string (required) - Name of the prompt to get
|
|
98
|
+
* - args: object (optional) - Prompt arguments
|
|
99
|
+
*
|
|
100
|
+
* Response:
|
|
101
|
+
* - success: boolean
|
|
102
|
+
* - data: { description?: string, messages: McpPromptMessage[] }
|
|
103
|
+
*/
|
|
104
|
+
export async function POST(request: NextRequest): Promise<NextResponse> {
|
|
105
|
+
const middleware = await applyMiddleware(request, { rateLimit: RELAXED_RATE_LIMIT });
|
|
106
|
+
if ('response' in middleware) {
|
|
107
|
+
return middleware.response;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const { context } = middleware;
|
|
111
|
+
const log = createLogContext('POST', PATH, context.requestId, context.clientId);
|
|
112
|
+
|
|
113
|
+
try {
|
|
114
|
+
const body = await request.json();
|
|
115
|
+
const { sessionId, name, args } = validatePromptGet(body);
|
|
116
|
+
|
|
117
|
+
const sessionManager = SessionManager.getInstance();
|
|
118
|
+
|
|
119
|
+
const session = await sessionManager.getSession(sessionId);
|
|
120
|
+
if (!session) {
|
|
121
|
+
throw new SessionExpiredError(
|
|
122
|
+
`Session not found or expired: ${sessionId}`,
|
|
123
|
+
sessionId
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
let result;
|
|
128
|
+
|
|
129
|
+
try {
|
|
130
|
+
result = await sessionManager.getPrompt(sessionId, name, args);
|
|
131
|
+
} catch (error) {
|
|
132
|
+
if (error instanceof Error && error.message.includes('not found')) {
|
|
133
|
+
throw new NotFoundError(`Prompt not found: ${name}`, 'prompt');
|
|
134
|
+
}
|
|
135
|
+
throw new McpExecutionError(
|
|
136
|
+
`Prompt retrieval failed: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
137
|
+
{ executionType: 'prompt', name }
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const responseData: PromptGetResponseData = {
|
|
142
|
+
description: result.description,
|
|
143
|
+
messages: result.messages,
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
log.log(200, sessionId, undefined, { promptName: name });
|
|
147
|
+
|
|
148
|
+
return createSuccessResponse(responseData, 200, {
|
|
149
|
+
...context.rateLimitHeaders,
|
|
150
|
+
...withRequestId({}, context.requestId),
|
|
151
|
+
'Access-Control-Allow-Origin': '*',
|
|
152
|
+
});
|
|
153
|
+
} catch (error) {
|
|
154
|
+
const status = error instanceof Error && 'statusCode' in error
|
|
155
|
+
? (error as { statusCode: number }).statusCode
|
|
156
|
+
: 500;
|
|
157
|
+
log.log(status, undefined, error instanceof Error ? error.message : 'Unknown error');
|
|
158
|
+
return handleApiError(error);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resources API Route
|
|
3
|
+
*
|
|
4
|
+
* GET /api/playground/v2/resources - List all resources
|
|
5
|
+
* POST /api/playground/v2/resources - Read a resource
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
9
|
+
import {
|
|
10
|
+
handleApiError,
|
|
11
|
+
createSuccessResponse,
|
|
12
|
+
SessionExpiredError,
|
|
13
|
+
McpExecutionError,
|
|
14
|
+
NotFoundError,
|
|
15
|
+
validateResourceRead,
|
|
16
|
+
validateSessionIdFromQuery,
|
|
17
|
+
applyMiddleware,
|
|
18
|
+
corsPreflightResponse,
|
|
19
|
+
createLogContext,
|
|
20
|
+
SessionManager,
|
|
21
|
+
withRequestId,
|
|
22
|
+
RELAXED_RATE_LIMIT,
|
|
23
|
+
} from '@/lib/api';
|
|
24
|
+
import type { ResourcesListResponseData, ResourceReadResponseData } from '@/lib/api';
|
|
25
|
+
|
|
26
|
+
const PATH = '/api/playground/v2/resources';
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Handle CORS preflight request
|
|
30
|
+
*/
|
|
31
|
+
export async function OPTIONS(): Promise<NextResponse> {
|
|
32
|
+
return corsPreflightResponse({ methods: ['GET', 'POST', 'OPTIONS'] });
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* GET /api/playground/v2/resources
|
|
37
|
+
*
|
|
38
|
+
* Lists all available resources for a session.
|
|
39
|
+
*
|
|
40
|
+
* Query parameters:
|
|
41
|
+
* - sessionId: string (required) - The session ID
|
|
42
|
+
*
|
|
43
|
+
* Response:
|
|
44
|
+
* - success: boolean
|
|
45
|
+
* - data: { resources: McpResource[], resourceTemplates?: McpResourceTemplate[] }
|
|
46
|
+
*/
|
|
47
|
+
export async function GET(request: NextRequest): Promise<NextResponse> {
|
|
48
|
+
const middleware = await applyMiddleware(request, { rateLimit: RELAXED_RATE_LIMIT });
|
|
49
|
+
if ('response' in middleware) {
|
|
50
|
+
return middleware.response;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const { context } = middleware;
|
|
54
|
+
const log = createLogContext('GET', PATH, context.requestId, context.clientId);
|
|
55
|
+
|
|
56
|
+
try {
|
|
57
|
+
const { searchParams } = new URL(request.url);
|
|
58
|
+
const sessionId = validateSessionIdFromQuery(searchParams);
|
|
59
|
+
|
|
60
|
+
const sessionManager = SessionManager.getInstance();
|
|
61
|
+
|
|
62
|
+
const session = await sessionManager.getSession(sessionId);
|
|
63
|
+
if (!session) {
|
|
64
|
+
throw new SessionExpiredError(
|
|
65
|
+
`Session not found or expired: ${sessionId}`,
|
|
66
|
+
sessionId
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const { resources, resourceTemplates } = await sessionManager.listResources(sessionId);
|
|
71
|
+
|
|
72
|
+
const responseData: ResourcesListResponseData = {
|
|
73
|
+
resources,
|
|
74
|
+
resourceTemplates,
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
log.log(200, sessionId);
|
|
78
|
+
|
|
79
|
+
return createSuccessResponse(responseData, 200, {
|
|
80
|
+
...context.rateLimitHeaders,
|
|
81
|
+
...withRequestId({}, context.requestId),
|
|
82
|
+
'Access-Control-Allow-Origin': '*',
|
|
83
|
+
});
|
|
84
|
+
} catch (error) {
|
|
85
|
+
const status = error instanceof Error && 'statusCode' in error
|
|
86
|
+
? (error as { statusCode: number }).statusCode
|
|
87
|
+
: 500;
|
|
88
|
+
log.log(status, undefined, error instanceof Error ? error.message : 'Unknown error');
|
|
89
|
+
return handleApiError(error);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* POST /api/playground/v2/resources
|
|
95
|
+
*
|
|
96
|
+
* Reads a resource.
|
|
97
|
+
*
|
|
98
|
+
* Request body:
|
|
99
|
+
* - sessionId: string (required) - The session ID
|
|
100
|
+
* - uri: string (required) - URI of the resource to read
|
|
101
|
+
*
|
|
102
|
+
* Response:
|
|
103
|
+
* - success: boolean
|
|
104
|
+
* - data: { contents: McpResourceContents[] }
|
|
105
|
+
*/
|
|
106
|
+
export async function POST(request: NextRequest): Promise<NextResponse> {
|
|
107
|
+
const middleware = await applyMiddleware(request, { rateLimit: RELAXED_RATE_LIMIT });
|
|
108
|
+
if ('response' in middleware) {
|
|
109
|
+
return middleware.response;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const { context } = middleware;
|
|
113
|
+
const log = createLogContext('POST', PATH, context.requestId, context.clientId);
|
|
114
|
+
|
|
115
|
+
try {
|
|
116
|
+
const body = await request.json();
|
|
117
|
+
const { sessionId, uri } = validateResourceRead(body);
|
|
118
|
+
|
|
119
|
+
const sessionManager = SessionManager.getInstance();
|
|
120
|
+
|
|
121
|
+
const session = await sessionManager.getSession(sessionId);
|
|
122
|
+
if (!session) {
|
|
123
|
+
throw new SessionExpiredError(
|
|
124
|
+
`Session not found or expired: ${sessionId}`,
|
|
125
|
+
sessionId
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
let contents;
|
|
130
|
+
|
|
131
|
+
try {
|
|
132
|
+
contents = await sessionManager.readResource(sessionId, uri);
|
|
133
|
+
} catch (error) {
|
|
134
|
+
if (error instanceof Error && error.message.includes('not found')) {
|
|
135
|
+
throw new NotFoundError(`Resource not found: ${uri}`, 'resource');
|
|
136
|
+
}
|
|
137
|
+
throw new McpExecutionError(
|
|
138
|
+
`Resource read failed: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
139
|
+
{ executionType: 'resource', name: uri }
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const responseData: ResourceReadResponseData = { contents };
|
|
144
|
+
|
|
145
|
+
log.log(200, sessionId, undefined, { uri });
|
|
146
|
+
|
|
147
|
+
return createSuccessResponse(responseData, 200, {
|
|
148
|
+
...context.rateLimitHeaders,
|
|
149
|
+
...withRequestId({}, context.requestId),
|
|
150
|
+
'Access-Control-Allow-Origin': '*',
|
|
151
|
+
});
|
|
152
|
+
} catch (error) {
|
|
153
|
+
const status = error instanceof Error && 'statusCode' in error
|
|
154
|
+
? (error as { statusCode: number }).statusCode
|
|
155
|
+
: 500;
|
|
156
|
+
log.log(status, undefined, error instanceof Error ? error.message : 'Unknown error');
|
|
157
|
+
return handleApiError(error);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sessions API Route
|
|
3
|
+
*
|
|
4
|
+
* GET /api/playground/v2/sessions - List active sessions
|
|
5
|
+
* DELETE /api/playground/v2/sessions - Remove a session
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
9
|
+
import {
|
|
10
|
+
handleApiError,
|
|
11
|
+
createSuccessResponse,
|
|
12
|
+
ValidationError,
|
|
13
|
+
SessionExpiredError,
|
|
14
|
+
applyMiddleware,
|
|
15
|
+
corsPreflightResponse,
|
|
16
|
+
createLogContext,
|
|
17
|
+
SessionManager,
|
|
18
|
+
withRequestId,
|
|
19
|
+
DEFAULT_RATE_LIMIT,
|
|
20
|
+
RELAXED_RATE_LIMIT,
|
|
21
|
+
} from '@/lib/api';
|
|
22
|
+
import type { SessionsListResponseData, DisconnectResponseData } from '@/lib/api';
|
|
23
|
+
|
|
24
|
+
const PATH = '/api/playground/v2/sessions';
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Handle CORS preflight request
|
|
28
|
+
*/
|
|
29
|
+
export async function OPTIONS(): Promise<NextResponse> {
|
|
30
|
+
return corsPreflightResponse({ methods: ['GET', 'DELETE', 'OPTIONS'] });
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* GET /api/playground/v2/sessions
|
|
35
|
+
*
|
|
36
|
+
* Lists all active sessions.
|
|
37
|
+
*
|
|
38
|
+
* Query parameters:
|
|
39
|
+
* - clientId: string (optional) - Filter by client ID
|
|
40
|
+
*
|
|
41
|
+
* Response:
|
|
42
|
+
* - success: boolean
|
|
43
|
+
* - data: { sessions: SessionInfo[], count: number }
|
|
44
|
+
*/
|
|
45
|
+
export async function GET(request: NextRequest): Promise<NextResponse> {
|
|
46
|
+
const middleware = await applyMiddleware(request, { rateLimit: RELAXED_RATE_LIMIT });
|
|
47
|
+
if ('response' in middleware) {
|
|
48
|
+
return middleware.response;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const { context } = middleware;
|
|
52
|
+
const log = createLogContext('GET', PATH, context.requestId, context.clientId);
|
|
53
|
+
|
|
54
|
+
try {
|
|
55
|
+
const { searchParams } = new URL(request.url);
|
|
56
|
+
const clientId = searchParams.get('clientId');
|
|
57
|
+
|
|
58
|
+
const sessionManager = SessionManager.getInstance();
|
|
59
|
+
let sessions = await sessionManager.listSessions();
|
|
60
|
+
|
|
61
|
+
// Filter by clientId if provided
|
|
62
|
+
if (clientId) {
|
|
63
|
+
sessions = sessions.filter((s) => s.clientId === clientId);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const responseData: SessionsListResponseData = {
|
|
67
|
+
sessions,
|
|
68
|
+
count: sessions.length,
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
log.log(200, undefined, undefined, { sessionCount: sessions.length });
|
|
72
|
+
|
|
73
|
+
return createSuccessResponse(responseData, 200, {
|
|
74
|
+
...context.rateLimitHeaders,
|
|
75
|
+
...withRequestId({}, context.requestId),
|
|
76
|
+
'Access-Control-Allow-Origin': '*',
|
|
77
|
+
});
|
|
78
|
+
} catch (error) {
|
|
79
|
+
const status = error instanceof Error && 'statusCode' in error
|
|
80
|
+
? (error as { statusCode: number }).statusCode
|
|
81
|
+
: 500;
|
|
82
|
+
log.log(status, undefined, error instanceof Error ? error.message : 'Unknown error');
|
|
83
|
+
return handleApiError(error);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* DELETE /api/playground/v2/sessions
|
|
89
|
+
*
|
|
90
|
+
* Removes a session by ID or all sessions for a client.
|
|
91
|
+
*
|
|
92
|
+
* Query parameters:
|
|
93
|
+
* - sessionId: string (optional) - Specific session to remove
|
|
94
|
+
* - clientId: string (optional) - Remove all sessions for this client
|
|
95
|
+
*
|
|
96
|
+
* At least one of sessionId or clientId must be provided.
|
|
97
|
+
*
|
|
98
|
+
* Response:
|
|
99
|
+
* - success: boolean
|
|
100
|
+
* - data: { disconnected: boolean, sessionId?: string, removedCount?: number }
|
|
101
|
+
*/
|
|
102
|
+
export async function DELETE(request: NextRequest): Promise<NextResponse> {
|
|
103
|
+
const middleware = await applyMiddleware(request, { rateLimit: DEFAULT_RATE_LIMIT });
|
|
104
|
+
if ('response' in middleware) {
|
|
105
|
+
return middleware.response;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const { context } = middleware;
|
|
109
|
+
const log = createLogContext('DELETE', PATH, context.requestId, context.clientId);
|
|
110
|
+
|
|
111
|
+
try {
|
|
112
|
+
const { searchParams } = new URL(request.url);
|
|
113
|
+
const sessionId = searchParams.get('sessionId');
|
|
114
|
+
const clientId = searchParams.get('clientId');
|
|
115
|
+
|
|
116
|
+
if (!sessionId && !clientId) {
|
|
117
|
+
throw new ValidationError(
|
|
118
|
+
'Either sessionId or clientId is required',
|
|
119
|
+
'query'
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const sessionManager = SessionManager.getInstance();
|
|
124
|
+
|
|
125
|
+
if (sessionId) {
|
|
126
|
+
// Remove specific session
|
|
127
|
+
const session = await sessionManager.getSession(sessionId);
|
|
128
|
+
if (!session) {
|
|
129
|
+
throw new SessionExpiredError(
|
|
130
|
+
`Session not found or expired: ${sessionId}`,
|
|
131
|
+
sessionId
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const success = await sessionManager.deleteSession(sessionId);
|
|
136
|
+
|
|
137
|
+
const responseData: DisconnectResponseData = {
|
|
138
|
+
disconnected: success,
|
|
139
|
+
sessionId,
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
log.log(200, sessionId);
|
|
143
|
+
|
|
144
|
+
return createSuccessResponse(responseData, 200, {
|
|
145
|
+
...context.rateLimitHeaders,
|
|
146
|
+
...withRequestId({}, context.requestId),
|
|
147
|
+
'Access-Control-Allow-Origin': '*',
|
|
148
|
+
});
|
|
149
|
+
} else if (clientId) {
|
|
150
|
+
// Remove all sessions for this client
|
|
151
|
+
const allSessions = await sessionManager.listSessions();
|
|
152
|
+
const sessions = allSessions.filter((s) => s.clientId === clientId);
|
|
153
|
+
let removedCount = 0;
|
|
154
|
+
|
|
155
|
+
for (const session of sessions) {
|
|
156
|
+
const success = await sessionManager.deleteSession(session.id);
|
|
157
|
+
if (success) removedCount++;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const responseData = {
|
|
161
|
+
disconnected: removedCount > 0,
|
|
162
|
+
removedCount,
|
|
163
|
+
clientId,
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
log.log(200, undefined, undefined, { removedCount });
|
|
167
|
+
|
|
168
|
+
return createSuccessResponse(responseData, 200, {
|
|
169
|
+
...context.rateLimitHeaders,
|
|
170
|
+
...withRequestId({}, context.requestId),
|
|
171
|
+
'Access-Control-Allow-Origin': '*',
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Should never reach here due to validation above
|
|
176
|
+
throw new ValidationError('Invalid request parameters', 'query');
|
|
177
|
+
} catch (error) {
|
|
178
|
+
const status = error instanceof Error && 'statusCode' in error
|
|
179
|
+
? (error as { statusCode: number }).statusCode
|
|
180
|
+
: 500;
|
|
181
|
+
log.log(status, undefined, error instanceof Error ? error.message : 'Unknown error');
|
|
182
|
+
return handleApiError(error);
|
|
183
|
+
}
|
|
184
|
+
}
|