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,1173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Playground Hooks Type Definitions
|
|
3
|
+
* Shared types for MCP playground React hooks
|
|
4
|
+
* @copyright 2024-2026 nirholas
|
|
5
|
+
* @license MIT
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// ============================================================================
|
|
9
|
+
// Constants
|
|
10
|
+
// ============================================================================
|
|
11
|
+
|
|
12
|
+
/** Default request timeout in milliseconds */
|
|
13
|
+
export const DEFAULT_TIMEOUT = 30000;
|
|
14
|
+
|
|
15
|
+
/** Default heartbeat interval in milliseconds */
|
|
16
|
+
export const DEFAULT_HEARTBEAT_INTERVAL = 30000;
|
|
17
|
+
|
|
18
|
+
/** Default debounce delay for reconnection */
|
|
19
|
+
export const DEFAULT_RECONNECT_DEBOUNCE = 1000;
|
|
20
|
+
|
|
21
|
+
/** Default cache TTL in milliseconds */
|
|
22
|
+
export const DEFAULT_CACHE_TTL = 60000;
|
|
23
|
+
|
|
24
|
+
// ============================================================================
|
|
25
|
+
// Transport Configuration Types
|
|
26
|
+
// ============================================================================
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Supported transport types for MCP connections
|
|
30
|
+
*/
|
|
31
|
+
export type TransportType = 'stdio' | 'http' | 'websocket' | 'sse';
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Base transport configuration
|
|
35
|
+
*/
|
|
36
|
+
export interface BaseTransportConfig {
|
|
37
|
+
type: TransportType;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* HTTP/SSE transport configuration
|
|
42
|
+
*/
|
|
43
|
+
export interface HttpTransportConfig extends BaseTransportConfig {
|
|
44
|
+
type: 'http' | 'sse';
|
|
45
|
+
url: string;
|
|
46
|
+
headers?: Record<string, string>;
|
|
47
|
+
timeout?: number;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* WebSocket transport configuration
|
|
52
|
+
*/
|
|
53
|
+
export interface WebSocketTransportConfig extends BaseTransportConfig {
|
|
54
|
+
type: 'websocket';
|
|
55
|
+
url: string;
|
|
56
|
+
protocols?: string[];
|
|
57
|
+
headers?: Record<string, string>;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Stdio transport configuration (for server-side execution)
|
|
62
|
+
*/
|
|
63
|
+
export interface StdioTransportConfig extends BaseTransportConfig {
|
|
64
|
+
type: 'stdio';
|
|
65
|
+
command: string;
|
|
66
|
+
args?: string[];
|
|
67
|
+
env?: Record<string, string>;
|
|
68
|
+
cwd?: string;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Union of all transport configurations
|
|
73
|
+
*/
|
|
74
|
+
export type TransportConfig =
|
|
75
|
+
| HttpTransportConfig
|
|
76
|
+
| WebSocketTransportConfig
|
|
77
|
+
| StdioTransportConfig;
|
|
78
|
+
|
|
79
|
+
// ============================================================================
|
|
80
|
+
// Connection Types
|
|
81
|
+
// ============================================================================
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Connection status states
|
|
85
|
+
*/
|
|
86
|
+
export type ConnectionStatus = 'disconnected' | 'connecting' | 'connected' | 'error';
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* MCP Server capabilities
|
|
90
|
+
*/
|
|
91
|
+
export interface McpCapabilities {
|
|
92
|
+
tools?: {
|
|
93
|
+
listChanged?: boolean;
|
|
94
|
+
};
|
|
95
|
+
resources?: {
|
|
96
|
+
subscribe?: boolean;
|
|
97
|
+
listChanged?: boolean;
|
|
98
|
+
};
|
|
99
|
+
prompts?: {
|
|
100
|
+
listChanged?: boolean;
|
|
101
|
+
};
|
|
102
|
+
logging?: Record<string, unknown>;
|
|
103
|
+
experimental?: Record<string, unknown>;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* MCP Server information
|
|
108
|
+
*/
|
|
109
|
+
export interface ServerInfo {
|
|
110
|
+
name: string;
|
|
111
|
+
version: string;
|
|
112
|
+
protocolVersion?: string;
|
|
113
|
+
instructions?: string;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Session information after successful connection
|
|
118
|
+
*/
|
|
119
|
+
export interface SessionInfo {
|
|
120
|
+
sessionId: string;
|
|
121
|
+
serverInfo: ServerInfo;
|
|
122
|
+
capabilities: McpCapabilities;
|
|
123
|
+
connectedAt: Date;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// ============================================================================
|
|
127
|
+
// Tool Types
|
|
128
|
+
// ============================================================================
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* JSON Schema property for tool input validation
|
|
132
|
+
*/
|
|
133
|
+
export interface JsonSchemaProperty {
|
|
134
|
+
type: string;
|
|
135
|
+
description?: string;
|
|
136
|
+
enum?: (string | number | boolean)[];
|
|
137
|
+
default?: unknown;
|
|
138
|
+
items?: JsonSchemaProperty;
|
|
139
|
+
properties?: Record<string, JsonSchemaProperty>;
|
|
140
|
+
required?: string[];
|
|
141
|
+
minimum?: number;
|
|
142
|
+
maximum?: number;
|
|
143
|
+
minLength?: number;
|
|
144
|
+
maxLength?: number;
|
|
145
|
+
pattern?: string;
|
|
146
|
+
format?: string;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Tool input schema
|
|
151
|
+
*/
|
|
152
|
+
export interface ToolInputSchema {
|
|
153
|
+
type: 'object';
|
|
154
|
+
properties?: Record<string, JsonSchemaProperty>;
|
|
155
|
+
required?: string[];
|
|
156
|
+
additionalProperties?: boolean;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* MCP Tool definition
|
|
161
|
+
*/
|
|
162
|
+
export interface McpTool {
|
|
163
|
+
name: string;
|
|
164
|
+
description?: string;
|
|
165
|
+
inputSchema: ToolInputSchema;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Text content in tool response
|
|
170
|
+
*/
|
|
171
|
+
export interface TextContent {
|
|
172
|
+
type: 'text';
|
|
173
|
+
text: string;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Image content in tool response
|
|
178
|
+
*/
|
|
179
|
+
export interface ImageContent {
|
|
180
|
+
type: 'image';
|
|
181
|
+
data: string;
|
|
182
|
+
mimeType: string;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Resource content embedded in tool response
|
|
187
|
+
*/
|
|
188
|
+
export interface EmbeddedResourceContent {
|
|
189
|
+
type: 'resource';
|
|
190
|
+
resource: {
|
|
191
|
+
uri: string;
|
|
192
|
+
mimeType?: string;
|
|
193
|
+
text?: string;
|
|
194
|
+
blob?: string;
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Tool content types
|
|
200
|
+
*/
|
|
201
|
+
export type ToolContent = TextContent | ImageContent | EmbeddedResourceContent;
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Result from calling a tool
|
|
205
|
+
*/
|
|
206
|
+
export interface ToolCallResult {
|
|
207
|
+
content: ToolContent[];
|
|
208
|
+
isError?: boolean;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Execution status for async operations
|
|
213
|
+
*/
|
|
214
|
+
export type ExecutionStatus = 'pending' | 'running' | 'success' | 'error';
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Tool execution record
|
|
218
|
+
*/
|
|
219
|
+
export interface ToolExecution {
|
|
220
|
+
id: string;
|
|
221
|
+
toolName: string;
|
|
222
|
+
params: Record<string, unknown>;
|
|
223
|
+
status: ExecutionStatus;
|
|
224
|
+
result?: ToolCallResult;
|
|
225
|
+
error?: string;
|
|
226
|
+
startedAt: Date;
|
|
227
|
+
completedAt?: Date;
|
|
228
|
+
executionTime?: number;
|
|
229
|
+
logs: string[];
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// ============================================================================
|
|
233
|
+
// Resource Types
|
|
234
|
+
// ============================================================================
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* MCP Resource definition
|
|
238
|
+
*/
|
|
239
|
+
export interface McpResource {
|
|
240
|
+
uri: string;
|
|
241
|
+
name: string;
|
|
242
|
+
description?: string;
|
|
243
|
+
mimeType?: string;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Resource content
|
|
248
|
+
*/
|
|
249
|
+
export interface ResourceContent {
|
|
250
|
+
uri: string;
|
|
251
|
+
mimeType?: string;
|
|
252
|
+
text?: string;
|
|
253
|
+
blob?: string;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Resource contents wrapper
|
|
258
|
+
*/
|
|
259
|
+
export interface ResourceContents {
|
|
260
|
+
contents: ResourceContent[];
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Resource read status
|
|
265
|
+
*/
|
|
266
|
+
export type ResourceReadStatus = 'pending' | 'loading' | 'success' | 'error';
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Resource read record
|
|
270
|
+
*/
|
|
271
|
+
export interface ResourceRead {
|
|
272
|
+
id: string;
|
|
273
|
+
uri: string;
|
|
274
|
+
status: ResourceReadStatus;
|
|
275
|
+
contents?: ResourceContents;
|
|
276
|
+
error?: string;
|
|
277
|
+
readAt?: Date;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// ============================================================================
|
|
281
|
+
// Prompt Types
|
|
282
|
+
// ============================================================================
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Prompt argument definition
|
|
286
|
+
*/
|
|
287
|
+
export interface PromptArgument {
|
|
288
|
+
name: string;
|
|
289
|
+
description?: string;
|
|
290
|
+
required?: boolean;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* MCP Prompt definition
|
|
295
|
+
*/
|
|
296
|
+
export interface McpPrompt {
|
|
297
|
+
name: string;
|
|
298
|
+
description?: string;
|
|
299
|
+
arguments?: PromptArgument[];
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Prompt message role
|
|
304
|
+
*/
|
|
305
|
+
export type PromptMessageRole = 'user' | 'assistant';
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Prompt message
|
|
309
|
+
*/
|
|
310
|
+
export interface PromptMessage {
|
|
311
|
+
role: PromptMessageRole;
|
|
312
|
+
content: TextContent | ImageContent | EmbeddedResourceContent;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Prompt execution status
|
|
317
|
+
*/
|
|
318
|
+
export type PromptExecutionStatus = 'pending' | 'loading' | 'executing' | 'success' | 'error';
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* Prompt execution record
|
|
322
|
+
*/
|
|
323
|
+
export interface PromptExecution {
|
|
324
|
+
id: string;
|
|
325
|
+
name: string;
|
|
326
|
+
/** Alias for name (for backwards compatibility) */
|
|
327
|
+
promptName?: string;
|
|
328
|
+
args?: Record<string, string>;
|
|
329
|
+
/** Alias for args (for backwards compatibility) */
|
|
330
|
+
arguments?: Record<string, string>;
|
|
331
|
+
status: PromptExecutionStatus;
|
|
332
|
+
messages?: PromptMessage[];
|
|
333
|
+
description?: string;
|
|
334
|
+
error?: string;
|
|
335
|
+
executedAt?: Date;
|
|
336
|
+
/** When execution started */
|
|
337
|
+
startedAt?: Date;
|
|
338
|
+
/** When execution completed */
|
|
339
|
+
completedAt?: Date;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// ============================================================================
|
|
343
|
+
// Execution History Types
|
|
344
|
+
// ============================================================================
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* Type of execution entry
|
|
348
|
+
*/
|
|
349
|
+
export type ExecutionType = 'tool' | 'resource' | 'prompt';
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* Execution history entry
|
|
353
|
+
*/
|
|
354
|
+
export interface ExecutionHistoryEntry {
|
|
355
|
+
id: string;
|
|
356
|
+
type: ExecutionType;
|
|
357
|
+
name: string;
|
|
358
|
+
params?: unknown;
|
|
359
|
+
result?: unknown;
|
|
360
|
+
error?: string;
|
|
361
|
+
success: boolean;
|
|
362
|
+
timestamp: Date;
|
|
363
|
+
executionTime?: number;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// ============================================================================
|
|
367
|
+
// API Response Types
|
|
368
|
+
// ============================================================================
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* Standard API response wrapper
|
|
372
|
+
*/
|
|
373
|
+
export interface ApiResponse<T> {
|
|
374
|
+
success: boolean;
|
|
375
|
+
data?: T;
|
|
376
|
+
error?: string;
|
|
377
|
+
message?: string;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* Connect API response
|
|
382
|
+
*/
|
|
383
|
+
export interface ConnectResponse {
|
|
384
|
+
sessionId: string;
|
|
385
|
+
serverInfo: ServerInfo;
|
|
386
|
+
capabilities: McpCapabilities;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* List tools API response
|
|
391
|
+
*/
|
|
392
|
+
export interface ListToolsResponse {
|
|
393
|
+
tools: McpTool[];
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
/**
|
|
397
|
+
* Execute tool API response
|
|
398
|
+
*/
|
|
399
|
+
export interface ExecuteToolResponse {
|
|
400
|
+
result: ToolCallResult;
|
|
401
|
+
executionTime: number;
|
|
402
|
+
logs?: string[];
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* List resources API response
|
|
407
|
+
*/
|
|
408
|
+
export interface ListResourcesResponse {
|
|
409
|
+
resources: McpResource[];
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* Read resource API response
|
|
414
|
+
*/
|
|
415
|
+
export interface ReadResourceResponse {
|
|
416
|
+
contents: ResourceContents;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
/**
|
|
420
|
+
* List prompts API response
|
|
421
|
+
*/
|
|
422
|
+
export interface ListPromptsResponse {
|
|
423
|
+
prompts: McpPrompt[];
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
/**
|
|
427
|
+
* Get prompt API response
|
|
428
|
+
*/
|
|
429
|
+
export interface GetPromptResponse {
|
|
430
|
+
messages: PromptMessage[];
|
|
431
|
+
description?: string;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
// ============================================================================
|
|
435
|
+
// Hook Return Types
|
|
436
|
+
// ============================================================================
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* Common hook options shared across all hooks
|
|
440
|
+
*/
|
|
441
|
+
export interface CommonHookOptions {
|
|
442
|
+
/** Enable debug logging */
|
|
443
|
+
debug?: boolean;
|
|
444
|
+
/** Request timeout in ms */
|
|
445
|
+
timeout?: number;
|
|
446
|
+
/** Event emitter for subscribing to events outside React */
|
|
447
|
+
eventEmitter?: McpEventEmitter;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
/**
|
|
451
|
+
* Options for useMcpConnection hook
|
|
452
|
+
*/
|
|
453
|
+
export interface UseMcpConnectionOptions extends CommonHookOptions {
|
|
454
|
+
autoConnect?: boolean;
|
|
455
|
+
onConnect?: (session: SessionInfo) => void;
|
|
456
|
+
onDisconnect?: () => void;
|
|
457
|
+
onError?: (error: Error) => void;
|
|
458
|
+
/** Heartbeat interval in ms (0 to disable) */
|
|
459
|
+
heartbeatInterval?: number;
|
|
460
|
+
/** Debounce delay for reconnection in ms */
|
|
461
|
+
reconnectDebounce?: number;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
/**
|
|
465
|
+
* Return type for useMcpConnection hook
|
|
466
|
+
*/
|
|
467
|
+
export interface UseMcpConnectionReturn {
|
|
468
|
+
// State
|
|
469
|
+
status: ConnectionStatus;
|
|
470
|
+
sessionId: string | null;
|
|
471
|
+
capabilities: McpCapabilities | null;
|
|
472
|
+
serverInfo: ServerInfo | null;
|
|
473
|
+
error: string | null;
|
|
474
|
+
/** Last successful heartbeat timestamp */
|
|
475
|
+
lastHeartbeat: Date | null;
|
|
476
|
+
/** Server URL (for HTTP/SSE transports) */
|
|
477
|
+
serverUrl: string | null;
|
|
478
|
+
|
|
479
|
+
// Actions
|
|
480
|
+
connect: (config: TransportConfig) => Promise<void>;
|
|
481
|
+
disconnect: () => Promise<void>;
|
|
482
|
+
reconnect: () => Promise<void>;
|
|
483
|
+
clearError: () => void;
|
|
484
|
+
/** Manually trigger a heartbeat */
|
|
485
|
+
heartbeat: () => Promise<boolean>;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
/**
|
|
489
|
+
* Options for useMcpTools hook
|
|
490
|
+
*/
|
|
491
|
+
export interface UseMcpToolsOptions extends CommonHookOptions {
|
|
492
|
+
sessionId: string | null;
|
|
493
|
+
autoLoad?: boolean;
|
|
494
|
+
/** Cache TTL in ms (0 to disable caching) */
|
|
495
|
+
cacheTtl?: number;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
/**
|
|
499
|
+
* Return type for useMcpTools hook
|
|
500
|
+
*/
|
|
501
|
+
export interface UseMcpToolsReturn {
|
|
502
|
+
// State
|
|
503
|
+
tools: McpTool[];
|
|
504
|
+
isLoading: boolean;
|
|
505
|
+
error: string | null;
|
|
506
|
+
executions: ToolExecution[];
|
|
507
|
+
currentExecution: ToolExecution | null;
|
|
508
|
+
/** Whether data is from cache */
|
|
509
|
+
isStale: boolean;
|
|
510
|
+
|
|
511
|
+
// Actions
|
|
512
|
+
loadTools: () => Promise<void>;
|
|
513
|
+
/** Force refresh, bypassing cache */
|
|
514
|
+
refreshTools: () => Promise<void>;
|
|
515
|
+
executeTool: (name: string, params: Record<string, unknown>) => Promise<ToolExecution>;
|
|
516
|
+
/** Execute multiple tools in parallel */
|
|
517
|
+
executeBatch: (requests: BatchToolRequest[], options?: BatchExecutionOptions) => Promise<BatchToolResult[]>;
|
|
518
|
+
cancelExecution: (id: string) => void;
|
|
519
|
+
clearExecutions: () => void;
|
|
520
|
+
clearError: () => void;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
/**
|
|
524
|
+
* Options for useMcpResources hook
|
|
525
|
+
*/
|
|
526
|
+
export interface UseMcpResourcesOptions extends CommonHookOptions {
|
|
527
|
+
sessionId: string | null;
|
|
528
|
+
autoLoad?: boolean;
|
|
529
|
+
/** Cache TTL in ms (0 to disable caching) */
|
|
530
|
+
cacheTtl?: number;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
/**
|
|
534
|
+
* Return type for useMcpResources hook
|
|
535
|
+
*/
|
|
536
|
+
export interface UseMcpResourcesReturn {
|
|
537
|
+
// State
|
|
538
|
+
resources: McpResource[];
|
|
539
|
+
isLoading: boolean;
|
|
540
|
+
error: string | null;
|
|
541
|
+
reads: ResourceRead[];
|
|
542
|
+
/** Whether data is from cache */
|
|
543
|
+
isStale: boolean;
|
|
544
|
+
|
|
545
|
+
// Actions
|
|
546
|
+
loadResources: () => Promise<void>;
|
|
547
|
+
/** Force refresh, bypassing cache */
|
|
548
|
+
refreshResources: () => Promise<void>;
|
|
549
|
+
readResource: (uri: string) => Promise<ResourceRead>;
|
|
550
|
+
clearReads: () => void;
|
|
551
|
+
clearError: () => void;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
/**
|
|
555
|
+
* Options for useMcpPrompts hook
|
|
556
|
+
*/
|
|
557
|
+
export interface UseMcpPromptsOptions extends CommonHookOptions {
|
|
558
|
+
sessionId: string | null;
|
|
559
|
+
autoLoad?: boolean;
|
|
560
|
+
/** Cache TTL in ms (0 to disable caching) */
|
|
561
|
+
cacheTtl?: number;
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
/**
|
|
565
|
+
* Return type for useMcpPrompts hook
|
|
566
|
+
*/
|
|
567
|
+
export interface UseMcpPromptsReturn {
|
|
568
|
+
// State
|
|
569
|
+
prompts: McpPrompt[];
|
|
570
|
+
isLoading: boolean;
|
|
571
|
+
error: string | null;
|
|
572
|
+
executions: PromptExecution[];
|
|
573
|
+
/** Whether data is from cache */
|
|
574
|
+
isStale: boolean;
|
|
575
|
+
|
|
576
|
+
// Actions
|
|
577
|
+
loadPrompts: () => Promise<void>;
|
|
578
|
+
/** Force refresh, bypassing cache */
|
|
579
|
+
refreshPrompts: () => Promise<void>;
|
|
580
|
+
getPrompt: (name: string, args?: Record<string, string>) => Promise<PromptExecution>;
|
|
581
|
+
/** Execute a prompt (alias for getPrompt) */
|
|
582
|
+
executePrompt: (name: string, args?: Record<string, string>) => Promise<PromptExecution>;
|
|
583
|
+
clearExecutions: () => void;
|
|
584
|
+
clearError: () => void;
|
|
585
|
+
/** Get messages from last successful execution */
|
|
586
|
+
getLastMessages: () => PromptMessage[] | null;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
/**
|
|
590
|
+
* Return type for useExecutionHistory hook
|
|
591
|
+
*/
|
|
592
|
+
export interface UseExecutionHistoryReturn {
|
|
593
|
+
history: ExecutionHistoryEntry[];
|
|
594
|
+
add: (entry: Omit<ExecutionHistoryEntry, 'id' | 'timestamp'>) => void;
|
|
595
|
+
addExecution: (execution: ToolExecution) => void;
|
|
596
|
+
addResourceRead: (read: ResourceRead) => void;
|
|
597
|
+
addPromptExecution: (execution: PromptExecution) => void;
|
|
598
|
+
clear: () => void;
|
|
599
|
+
clearHistory: () => void;
|
|
600
|
+
getByType: (type: ExecutionType) => ExecutionHistoryEntry[];
|
|
601
|
+
getByStatus: (success: boolean) => ExecutionHistoryEntry[];
|
|
602
|
+
export: () => string;
|
|
603
|
+
exportHistory: () => string;
|
|
604
|
+
import: (json: string) => void;
|
|
605
|
+
importHistory: (json: string) => void;
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
/**
|
|
609
|
+
* Options for usePlayground hook
|
|
610
|
+
*/
|
|
611
|
+
export interface UsePlaygroundOptions extends CommonHookOptions {
|
|
612
|
+
initialCode?: string;
|
|
613
|
+
initialTransport?: TransportConfig;
|
|
614
|
+
/** Auto connect on mount */
|
|
615
|
+
autoConnect?: boolean;
|
|
616
|
+
/** Persist history to localStorage */
|
|
617
|
+
persistHistory?: boolean;
|
|
618
|
+
/** Custom storage key for history */
|
|
619
|
+
historyKey?: string;
|
|
620
|
+
/** Cache TTL in ms */
|
|
621
|
+
cacheTtl?: number;
|
|
622
|
+
/** Heartbeat interval in ms */
|
|
623
|
+
heartbeatInterval?: number;
|
|
624
|
+
/** Callback when connected */
|
|
625
|
+
onConnect?: (sessionId: string) => void;
|
|
626
|
+
/** Callback when disconnected */
|
|
627
|
+
onDisconnect?: () => void;
|
|
628
|
+
/** Callback on error */
|
|
629
|
+
onError?: (error: Error) => void;
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
/**
|
|
633
|
+
* Options for useExecutionHistory hook
|
|
634
|
+
*/
|
|
635
|
+
export interface UseExecutionHistoryOptions {
|
|
636
|
+
/** Maximum history items to keep */
|
|
637
|
+
maxItems?: number;
|
|
638
|
+
/** Persist to localStorage */
|
|
639
|
+
persistToStorage?: boolean;
|
|
640
|
+
/** Custom storage key */
|
|
641
|
+
storageKey?: string;
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
/**
|
|
645
|
+
* Active tab type in playground
|
|
646
|
+
*/
|
|
647
|
+
export type PlaygroundTab = 'tools' | 'resources' | 'prompts';
|
|
648
|
+
|
|
649
|
+
/**
|
|
650
|
+
* Return type for usePlayground hook
|
|
651
|
+
*/
|
|
652
|
+
export interface UsePlaygroundReturn {
|
|
653
|
+
// Connection
|
|
654
|
+
connection: UseMcpConnectionReturn;
|
|
655
|
+
|
|
656
|
+
// Data
|
|
657
|
+
tools: UseMcpToolsReturn;
|
|
658
|
+
resources: UseMcpResourcesReturn;
|
|
659
|
+
prompts: UseMcpPromptsReturn;
|
|
660
|
+
|
|
661
|
+
// UI State
|
|
662
|
+
activeTab: PlaygroundTab;
|
|
663
|
+
setActiveTab: (tab: PlaygroundTab) => void;
|
|
664
|
+
selectedTool: McpTool | null;
|
|
665
|
+
setSelectedTool: (tool: McpTool | null) => void;
|
|
666
|
+
selectedResource: McpResource | null;
|
|
667
|
+
setSelectedResource: (resource: McpResource | null) => void;
|
|
668
|
+
selectedPrompt: McpPrompt | null;
|
|
669
|
+
setSelectedPrompt: (prompt: McpPrompt | null) => void;
|
|
670
|
+
|
|
671
|
+
// Transport Config
|
|
672
|
+
transportConfig: TransportConfig | null;
|
|
673
|
+
setTransportConfig: (config: TransportConfig) => void;
|
|
674
|
+
|
|
675
|
+
// Convenience
|
|
676
|
+
isReady: boolean;
|
|
677
|
+
hasCapability: (cap: keyof McpCapabilities) => boolean;
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
// ============================================================================
|
|
681
|
+
// Utility Types
|
|
682
|
+
// ============================================================================
|
|
683
|
+
|
|
684
|
+
/**
|
|
685
|
+
* Generate a unique ID
|
|
686
|
+
*/
|
|
687
|
+
export function generateId(): string {
|
|
688
|
+
return `${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
/**
|
|
692
|
+
* Exponential backoff configuration
|
|
693
|
+
*/
|
|
694
|
+
export interface RetryConfig {
|
|
695
|
+
maxRetries: number;
|
|
696
|
+
baseDelay: number;
|
|
697
|
+
maxDelay: number;
|
|
698
|
+
factor: number;
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
/**
|
|
702
|
+
* Default retry configuration
|
|
703
|
+
*/
|
|
704
|
+
export const DEFAULT_RETRY_CONFIG: RetryConfig = {
|
|
705
|
+
maxRetries: 3,
|
|
706
|
+
baseDelay: 1000,
|
|
707
|
+
maxDelay: 30000,
|
|
708
|
+
factor: 2,
|
|
709
|
+
};
|
|
710
|
+
|
|
711
|
+
/**
|
|
712
|
+
* Calculate delay for exponential backoff
|
|
713
|
+
*/
|
|
714
|
+
export function calculateBackoff(attempt: number, config: RetryConfig = DEFAULT_RETRY_CONFIG): number {
|
|
715
|
+
const delay = Math.min(
|
|
716
|
+
config.baseDelay * Math.pow(config.factor, attempt),
|
|
717
|
+
config.maxDelay
|
|
718
|
+
);
|
|
719
|
+
// Add jitter to prevent thundering herd
|
|
720
|
+
return delay + Math.random() * delay * 0.1;
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
// ============================================================================
|
|
724
|
+
// Debug & Logging Types
|
|
725
|
+
// ============================================================================
|
|
726
|
+
|
|
727
|
+
/**
|
|
728
|
+
* Log levels for debug mode
|
|
729
|
+
*/
|
|
730
|
+
export type LogLevel = 'debug' | 'info' | 'warn' | 'error';
|
|
731
|
+
|
|
732
|
+
/**
|
|
733
|
+
* Debug log entry
|
|
734
|
+
*/
|
|
735
|
+
export interface DebugLogEntry {
|
|
736
|
+
timestamp: Date;
|
|
737
|
+
level: LogLevel;
|
|
738
|
+
source: string;
|
|
739
|
+
message: string;
|
|
740
|
+
data?: unknown;
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
/**
|
|
744
|
+
* Debug options for hooks
|
|
745
|
+
*/
|
|
746
|
+
export interface DebugOptions {
|
|
747
|
+
enabled: boolean;
|
|
748
|
+
logLevel?: LogLevel;
|
|
749
|
+
onLog?: (entry: DebugLogEntry) => void;
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
/**
|
|
753
|
+
* Create a debug logger
|
|
754
|
+
*/
|
|
755
|
+
export function createDebugLogger(source: string, options?: DebugOptions) {
|
|
756
|
+
const logLevels: Record<LogLevel, number> = {
|
|
757
|
+
debug: 0,
|
|
758
|
+
info: 1,
|
|
759
|
+
warn: 2,
|
|
760
|
+
error: 3,
|
|
761
|
+
};
|
|
762
|
+
|
|
763
|
+
const minLevel = logLevels[options?.logLevel ?? 'debug'];
|
|
764
|
+
|
|
765
|
+
return {
|
|
766
|
+
debug: (message: string, data?: unknown) => {
|
|
767
|
+
if (!options?.enabled || logLevels.debug < minLevel) return;
|
|
768
|
+
const entry: DebugLogEntry = { timestamp: new Date(), level: 'debug', source, message, data };
|
|
769
|
+
options.onLog?.(entry);
|
|
770
|
+
console.debug(`[${source}]`, message, data ?? '');
|
|
771
|
+
},
|
|
772
|
+
info: (message: string, data?: unknown) => {
|
|
773
|
+
if (!options?.enabled || logLevels.info < minLevel) return;
|
|
774
|
+
const entry: DebugLogEntry = { timestamp: new Date(), level: 'info', source, message, data };
|
|
775
|
+
options.onLog?.(entry);
|
|
776
|
+
console.info(`[${source}]`, message, data ?? '');
|
|
777
|
+
},
|
|
778
|
+
warn: (message: string, data?: unknown) => {
|
|
779
|
+
if (!options?.enabled || logLevels.warn < minLevel) return;
|
|
780
|
+
const entry: DebugLogEntry = { timestamp: new Date(), level: 'warn', source, message, data };
|
|
781
|
+
options.onLog?.(entry);
|
|
782
|
+
console.warn(`[${source}]`, message, data ?? '');
|
|
783
|
+
},
|
|
784
|
+
error: (message: string, data?: unknown) => {
|
|
785
|
+
if (!options?.enabled || logLevels.error < minLevel) return;
|
|
786
|
+
const entry: DebugLogEntry = { timestamp: new Date(), level: 'error', source, message, data };
|
|
787
|
+
options.onLog?.(entry);
|
|
788
|
+
console.error(`[${source}]`, message, data ?? '');
|
|
789
|
+
},
|
|
790
|
+
};
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
// ============================================================================
|
|
794
|
+
// Event Emitter Types
|
|
795
|
+
// ============================================================================
|
|
796
|
+
|
|
797
|
+
/**
|
|
798
|
+
* Event types for MCP hooks
|
|
799
|
+
*/
|
|
800
|
+
export type McpEventType =
|
|
801
|
+
| 'connection:connecting'
|
|
802
|
+
| 'connection:connected'
|
|
803
|
+
| 'connection:disconnected'
|
|
804
|
+
| 'connection:error'
|
|
805
|
+
| 'connection:heartbeat'
|
|
806
|
+
| 'tools:loading'
|
|
807
|
+
| 'tools:loaded'
|
|
808
|
+
| 'tools:error'
|
|
809
|
+
| 'tool:executing'
|
|
810
|
+
| 'tool:executed'
|
|
811
|
+
| 'tool:error'
|
|
812
|
+
| 'tool:cancelled'
|
|
813
|
+
| 'resources:loading'
|
|
814
|
+
| 'resources:loaded'
|
|
815
|
+
| 'resources:error'
|
|
816
|
+
| 'resource:reading'
|
|
817
|
+
| 'resource:read'
|
|
818
|
+
| 'resource:error'
|
|
819
|
+
| 'prompts:loading'
|
|
820
|
+
| 'prompts:loaded'
|
|
821
|
+
| 'prompts:error'
|
|
822
|
+
| 'prompt:getting'
|
|
823
|
+
| 'prompt:got'
|
|
824
|
+
| 'prompt:error'
|
|
825
|
+
| 'prompt:executing'
|
|
826
|
+
| 'prompt:executed';
|
|
827
|
+
|
|
828
|
+
/**
|
|
829
|
+
* Event payload base
|
|
830
|
+
*/
|
|
831
|
+
export interface McpEventBase {
|
|
832
|
+
type: McpEventType;
|
|
833
|
+
timestamp: Date;
|
|
834
|
+
sessionId?: string | null;
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
/**
|
|
838
|
+
* Connection event payload
|
|
839
|
+
*/
|
|
840
|
+
export interface ConnectionEvent extends McpEventBase {
|
|
841
|
+
type: 'connection:connecting' | 'connection:connected' | 'connection:disconnected' | 'connection:error' | 'connection:heartbeat';
|
|
842
|
+
data?: {
|
|
843
|
+
serverInfo?: ServerInfo;
|
|
844
|
+
capabilities?: McpCapabilities;
|
|
845
|
+
error?: string;
|
|
846
|
+
};
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
/**
|
|
850
|
+
* Tool event payload
|
|
851
|
+
*/
|
|
852
|
+
export interface ToolEvent extends McpEventBase {
|
|
853
|
+
type: 'tools:loading' | 'tools:loaded' | 'tools:error' | 'tool:executing' | 'tool:executed' | 'tool:error' | 'tool:cancelled';
|
|
854
|
+
data?: {
|
|
855
|
+
tools?: McpTool[];
|
|
856
|
+
toolName?: string;
|
|
857
|
+
params?: Record<string, unknown>;
|
|
858
|
+
result?: ToolCallResult;
|
|
859
|
+
error?: string;
|
|
860
|
+
executionTime?: number;
|
|
861
|
+
};
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
/**
|
|
865
|
+
* Resource event payload
|
|
866
|
+
*/
|
|
867
|
+
export interface ResourceEvent extends McpEventBase {
|
|
868
|
+
type: 'resources:loading' | 'resources:loaded' | 'resources:error' | 'resource:reading' | 'resource:read' | 'resource:error';
|
|
869
|
+
data?: {
|
|
870
|
+
resources?: McpResource[];
|
|
871
|
+
uri?: string;
|
|
872
|
+
contents?: ResourceContents;
|
|
873
|
+
error?: string;
|
|
874
|
+
};
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
/**
|
|
878
|
+
* Prompt event payload
|
|
879
|
+
*/
|
|
880
|
+
export interface PromptEvent extends McpEventBase {
|
|
881
|
+
type: 'prompts:loading' | 'prompts:loaded' | 'prompts:error' | 'prompt:getting' | 'prompt:got' | 'prompt:error' | 'prompt:executing' | 'prompt:executed';
|
|
882
|
+
data?: {
|
|
883
|
+
prompts?: McpPrompt[];
|
|
884
|
+
name?: string;
|
|
885
|
+
args?: Record<string, string>;
|
|
886
|
+
arguments?: Record<string, string>;
|
|
887
|
+
messages?: PromptMessage[];
|
|
888
|
+
error?: string;
|
|
889
|
+
};
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
/**
|
|
893
|
+
* Union of all event types
|
|
894
|
+
*/
|
|
895
|
+
export type McpEvent = ConnectionEvent | ToolEvent | ResourceEvent | PromptEvent;
|
|
896
|
+
|
|
897
|
+
/**
|
|
898
|
+
* Event listener function
|
|
899
|
+
*/
|
|
900
|
+
export type McpEventListener<T extends McpEvent = McpEvent> = (event: T) => void;
|
|
901
|
+
|
|
902
|
+
/**
|
|
903
|
+
* Simple event emitter for MCP events
|
|
904
|
+
*/
|
|
905
|
+
export class McpEventEmitter {
|
|
906
|
+
private listeners = new Map<McpEventType | '*', Set<McpEventListener>>();
|
|
907
|
+
|
|
908
|
+
on<T extends McpEvent>(type: T['type'] | '*', listener: McpEventListener<T>): () => void {
|
|
909
|
+
if (!this.listeners.has(type)) {
|
|
910
|
+
this.listeners.set(type, new Set());
|
|
911
|
+
}
|
|
912
|
+
this.listeners.get(type)!.add(listener as McpEventListener);
|
|
913
|
+
|
|
914
|
+
// Return unsubscribe function
|
|
915
|
+
return () => this.off(type, listener);
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
off<T extends McpEvent>(type: T['type'] | '*', listener: McpEventListener<T>): void {
|
|
919
|
+
this.listeners.get(type)?.delete(listener as McpEventListener);
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
/**
|
|
923
|
+
* Subscribe to all events (alias for on('*', ...))
|
|
924
|
+
*/
|
|
925
|
+
subscribe(listener: McpEventListener): () => void {
|
|
926
|
+
return this.on('*', listener);
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
emit<T extends McpEvent>(event: T): void {
|
|
930
|
+
// Emit to specific listeners
|
|
931
|
+
this.listeners.get(event.type)?.forEach(listener => {
|
|
932
|
+
try {
|
|
933
|
+
listener(event);
|
|
934
|
+
} catch (err) {
|
|
935
|
+
console.error('[McpEventEmitter] Error in listener:', err);
|
|
936
|
+
}
|
|
937
|
+
});
|
|
938
|
+
|
|
939
|
+
// Emit to wildcard listeners
|
|
940
|
+
this.listeners.get('*')?.forEach(listener => {
|
|
941
|
+
try {
|
|
942
|
+
listener(event);
|
|
943
|
+
} catch (err) {
|
|
944
|
+
console.error('[McpEventEmitter] Error in wildcard listener:', err);
|
|
945
|
+
}
|
|
946
|
+
});
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
clear(): void {
|
|
950
|
+
this.listeners.clear();
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
/**
|
|
955
|
+
* Create an MCP event emitter instance
|
|
956
|
+
*/
|
|
957
|
+
export function createMcpEventEmitter(): McpEventEmitter {
|
|
958
|
+
return new McpEventEmitter();
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
// ============================================================================
|
|
962
|
+
// Cache Types
|
|
963
|
+
// ============================================================================
|
|
964
|
+
|
|
965
|
+
/**
|
|
966
|
+
* Cache entry with TTL
|
|
967
|
+
*/
|
|
968
|
+
export interface CacheEntry<T> {
|
|
969
|
+
data: T;
|
|
970
|
+
timestamp: number;
|
|
971
|
+
ttl: number;
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
/**
|
|
975
|
+
* Simple cache implementation
|
|
976
|
+
*/
|
|
977
|
+
export class SimpleCache<T> {
|
|
978
|
+
private cache = new Map<string, CacheEntry<T>>();
|
|
979
|
+
|
|
980
|
+
set(key: string, data: T, ttl: number = DEFAULT_CACHE_TTL): void {
|
|
981
|
+
this.cache.set(key, {
|
|
982
|
+
data,
|
|
983
|
+
timestamp: Date.now(),
|
|
984
|
+
ttl,
|
|
985
|
+
});
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
get(key: string): T | null {
|
|
989
|
+
const entry = this.cache.get(key);
|
|
990
|
+
if (!entry) return null;
|
|
991
|
+
|
|
992
|
+
if (Date.now() - entry.timestamp > entry.ttl) {
|
|
993
|
+
this.cache.delete(key);
|
|
994
|
+
return null;
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
return entry.data;
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
has(key: string): boolean {
|
|
1001
|
+
return this.get(key) !== null;
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
delete(key: string): void {
|
|
1005
|
+
this.cache.delete(key);
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
clear(): void {
|
|
1009
|
+
this.cache.clear();
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
isStale(key: string): boolean {
|
|
1013
|
+
const entry = this.cache.get(key);
|
|
1014
|
+
if (!entry) return true;
|
|
1015
|
+
return Date.now() - entry.timestamp > entry.ttl;
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
getStale(key: string): T | null {
|
|
1019
|
+
const entry = this.cache.get(key);
|
|
1020
|
+
return entry?.data ?? null;
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
// ============================================================================
|
|
1025
|
+
// Batch Execution Types
|
|
1026
|
+
// ============================================================================
|
|
1027
|
+
|
|
1028
|
+
/**
|
|
1029
|
+
* Batch tool execution request
|
|
1030
|
+
*/
|
|
1031
|
+
export interface BatchToolRequest {
|
|
1032
|
+
name: string;
|
|
1033
|
+
params: Record<string, unknown>;
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
/**
|
|
1037
|
+
* Batch tool execution result
|
|
1038
|
+
*/
|
|
1039
|
+
export interface BatchToolResult {
|
|
1040
|
+
request: BatchToolRequest;
|
|
1041
|
+
execution: ToolExecution;
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
/**
|
|
1045
|
+
* Batch execution options
|
|
1046
|
+
*/
|
|
1047
|
+
export interface BatchExecutionOptions {
|
|
1048
|
+
/** Maximum concurrent executions */
|
|
1049
|
+
concurrency?: number;
|
|
1050
|
+
/** Stop on first error */
|
|
1051
|
+
stopOnError?: boolean;
|
|
1052
|
+
/** Timeout per execution in ms */
|
|
1053
|
+
timeout?: number;
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
// ============================================================================
|
|
1057
|
+
// Request Deduplication Types
|
|
1058
|
+
// ============================================================================
|
|
1059
|
+
|
|
1060
|
+
/**
|
|
1061
|
+
* Pending request tracker
|
|
1062
|
+
*/
|
|
1063
|
+
export class RequestDeduplicator {
|
|
1064
|
+
private pending = new Map<string, Promise<unknown>>();
|
|
1065
|
+
|
|
1066
|
+
/**
|
|
1067
|
+
* Execute a request with deduplication
|
|
1068
|
+
* If the same key is already in flight, return the existing promise
|
|
1069
|
+
*/
|
|
1070
|
+
async execute<T>(key: string, fn: () => Promise<T>): Promise<T> {
|
|
1071
|
+
const existing = this.pending.get(key);
|
|
1072
|
+
if (existing) {
|
|
1073
|
+
return existing as Promise<T>;
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
const promise = fn().finally(() => {
|
|
1077
|
+
this.pending.delete(key);
|
|
1078
|
+
});
|
|
1079
|
+
|
|
1080
|
+
this.pending.set(key, promise);
|
|
1081
|
+
return promise;
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
has(key: string): boolean {
|
|
1085
|
+
return this.pending.has(key);
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
clear(): void {
|
|
1089
|
+
this.pending.clear();
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1093
|
+
// ============================================================================
|
|
1094
|
+
// Fetch with Timeout
|
|
1095
|
+
// ============================================================================
|
|
1096
|
+
|
|
1097
|
+
/**
|
|
1098
|
+
* Fetch with timeout support
|
|
1099
|
+
*/
|
|
1100
|
+
export async function fetchWithTimeout(
|
|
1101
|
+
url: string,
|
|
1102
|
+
options: RequestInit & { timeout?: number } = {}
|
|
1103
|
+
): Promise<Response> {
|
|
1104
|
+
const { timeout = DEFAULT_TIMEOUT, ...fetchOptions } = options;
|
|
1105
|
+
|
|
1106
|
+
const controller = new AbortController();
|
|
1107
|
+
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
1108
|
+
|
|
1109
|
+
// Combine with existing signal if present
|
|
1110
|
+
const signal = options.signal
|
|
1111
|
+
? anySignal([options.signal, controller.signal])
|
|
1112
|
+
: controller.signal;
|
|
1113
|
+
|
|
1114
|
+
try {
|
|
1115
|
+
const response = await fetch(url, {
|
|
1116
|
+
...fetchOptions,
|
|
1117
|
+
signal,
|
|
1118
|
+
});
|
|
1119
|
+
return response;
|
|
1120
|
+
} finally {
|
|
1121
|
+
clearTimeout(timeoutId);
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
|
|
1125
|
+
/**
|
|
1126
|
+
* Combine multiple AbortSignals into one
|
|
1127
|
+
*/
|
|
1128
|
+
function anySignal(signals: AbortSignal[]): AbortSignal {
|
|
1129
|
+
const controller = new AbortController();
|
|
1130
|
+
|
|
1131
|
+
for (const signal of signals) {
|
|
1132
|
+
if (signal.aborted) {
|
|
1133
|
+
controller.abort(signal.reason);
|
|
1134
|
+
return controller.signal;
|
|
1135
|
+
}
|
|
1136
|
+
signal.addEventListener('abort', () => controller.abort(signal.reason), { once: true });
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1139
|
+
return controller.signal;
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
// ============================================================================
|
|
1143
|
+
// Debounce Utility
|
|
1144
|
+
// ============================================================================
|
|
1145
|
+
|
|
1146
|
+
/**
|
|
1147
|
+
* Create a debounced function
|
|
1148
|
+
*/
|
|
1149
|
+
export function debounce<T extends (...args: Parameters<T>) => void>(
|
|
1150
|
+
fn: T,
|
|
1151
|
+
delay: number
|
|
1152
|
+
): T & { cancel: () => void } {
|
|
1153
|
+
let timeoutId: NodeJS.Timeout | null = null;
|
|
1154
|
+
|
|
1155
|
+
const debounced = ((...args: Parameters<T>) => {
|
|
1156
|
+
if (timeoutId) {
|
|
1157
|
+
clearTimeout(timeoutId);
|
|
1158
|
+
}
|
|
1159
|
+
timeoutId = setTimeout(() => {
|
|
1160
|
+
fn(...args);
|
|
1161
|
+
timeoutId = null;
|
|
1162
|
+
}, delay);
|
|
1163
|
+
}) as T & { cancel: () => void };
|
|
1164
|
+
|
|
1165
|
+
debounced.cancel = () => {
|
|
1166
|
+
if (timeoutId) {
|
|
1167
|
+
clearTimeout(timeoutId);
|
|
1168
|
+
timeoutId = null;
|
|
1169
|
+
}
|
|
1170
|
+
};
|
|
1171
|
+
|
|
1172
|
+
return debounced;
|
|
1173
|
+
}
|