@redocly/revel 0.138.0-next.9 → 0.138.1
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/CHANGELOG.md +276 -0
- package/dist/api-schemas/mcp-fetch-count.d.ts +24 -0
- package/dist/api-schemas/mcp-fetch-count.js +1 -0
- package/dist/bin.js +0 -0
- package/dist/cli/build/analytics/collect-analytics.js +1 -1
- package/dist/cli/build/analytics/collectors/get-processed-config-stats-usage.js +1 -1
- package/dist/cli/build/index.js +1 -1
- package/dist/cli/develop.js +1 -1
- package/dist/cli/eject/ejectTheme.js +1 -1
- package/dist/cli/translations/collect-config-translations.js +1 -1
- package/dist/client/App.js +1 -1
- package/dist/client/app/markdoc/custom-components/openapi/openapi-response-sample.js +1 -1
- package/dist/client/app/markdoc/custom-components/openapi/replay-openapi.js +1 -1
- package/dist/client/app/pages/Invite/Invite.js +1 -1
- package/dist/client/app/utils/loadAndNavigate.js +1 -1
- package/dist/client/polyfills.js +1 -1
- package/dist/client/runtime/loader.js +1 -1
- package/dist/client/utils/catalog/parse-filter-query.js +1 -1
- package/dist/compiled/svgo/svgo-node.js +39 -39
- package/dist/constants/api.d.ts +1 -0
- package/dist/constants/api.js +1 -1
- package/dist/constants/common.d.ts +6 -0
- package/dist/constants/common.js +1 -1
- package/dist/constants/l10n/langs/ar.js +1 -1
- package/dist/constants/l10n/langs/de.js +1 -1
- package/dist/constants/l10n/langs/en.js +1 -1
- package/dist/constants/l10n/langs/es.js +1 -1
- package/dist/constants/l10n/langs/fr.js +1 -1
- package/dist/constants/l10n/langs/hi.js +1 -1
- package/dist/constants/l10n/langs/it.js +1 -1
- package/dist/constants/l10n/langs/ja.js +1 -1
- package/dist/constants/l10n/langs/ko.js +1 -1
- package/dist/constants/l10n/langs/pl.js +1 -1
- package/dist/constants/l10n/langs/pt-BR.js +1 -1
- package/dist/constants/l10n/langs/pt.js +1 -1
- package/dist/constants/l10n/langs/ru.js +1 -1
- package/dist/constants/l10n/langs/uk.js +1 -1
- package/dist/constants/l10n/langs/zh.js +1 -1
- package/dist/markdoc/helpers/get-inner-text.js +2 -2
- package/dist/markdoc/helpers/guards/is-prompt-node.d.ts +13 -0
- package/dist/markdoc/helpers/guards/is-prompt-node.js +1 -0
- package/dist/server/config/env-config.d.ts +0 -2
- package/dist/server/config/env-schema.d.ts +0 -5
- package/dist/server/config/env-schemas/feature-flags.d.ts +0 -4
- package/dist/server/config/env-schemas/feature-flags.js +1 -1
- package/dist/server/constants/entitlements.js +1 -1
- package/dist/server/entitlements/entitlements-provider.js +1 -1
- package/dist/server/esbuild/esbuild.js +3 -3
- package/dist/server/esbuild/plugins/on-rebuild.js +1 -1
- package/dist/server/esbuild/plugins/styled-components-ssr.js +1 -1
- package/dist/server/esbuild/plugins/yaml-loader.js +1 -1
- package/dist/server/fs/content-fs.js +1 -1
- package/dist/server/fs/utils/is-l10n-root-file.d.ts +3 -0
- package/dist/server/fs/utils/is-l10n-root-file.js +1 -0
- package/dist/server/plugins/analytics/amplitude/index.js +1 -1
- package/dist/server/plugins/analytics/heap/browser-hooks.js +1 -1
- package/dist/server/plugins/api-docs/index.js +1 -1
- package/dist/server/plugins/api-docs/loader.js +3 -3
- package/dist/server/plugins/api-docs/spec-download.api.js +1 -1
- package/dist/server/plugins/api-docs/utils/apply-nav-item-to-root.js +1 -1
- package/dist/server/plugins/api-docs/utils/decorators.d.ts +11 -0
- package/dist/server/plugins/api-docs/utils/decorators.js +1 -1
- package/dist/server/plugins/arazzo-docs/arazzo-doc-loader.js +2 -2
- package/dist/server/plugins/catalog-entities/extensions/extractors/api-description/openapi-entities-extractor.js +1 -1
- package/dist/server/plugins/catalog-entities/utils/extract-parts-from-channels-message-ref.js +1 -1
- package/dist/server/plugins/config-parser/format-custom-tags.js +1 -1
- package/dist/server/plugins/config-parser/loaders/content-slugs-loader.js +1 -1
- package/dist/server/plugins/config-parser/loaders/versions-config-loader.js +1 -1
- package/dist/server/plugins/config-parser/resolve-mutual-exclusion.js +1 -1
- package/dist/server/plugins/config-parser/safe-parse.js +1 -1
- package/dist/server/plugins/default-theme/resolve-logo.js +1 -1
- package/dist/server/plugins/dev-onboarding/api/adapters/apigee/adapter.js +2 -2
- package/dist/server/plugins/dev-onboarding/api/adapters/gravitee/client.js +2 -2
- package/dist/server/plugins/dev-onboarding/api/combine.js +1 -1
- package/dist/server/plugins/dev-onboarding/template/components/AppOverview.js +1 -1
- package/dist/server/plugins/dev-onboarding/template/components/useSortableData.js +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/code-walkthrough/file-chunk-parser.d.ts +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/index.js +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-link.js +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-svg-content.js +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-tag-raw-content.d.ts +4 -0
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-tag-raw-content.js +2 -0
- package/dist/server/plugins/markdown/compiler.js +1 -1
- package/dist/server/plugins/markdown/create-source-lines-reader.d.ts +7 -0
- package/dist/server/plugins/markdown/create-source-lines-reader.js +1 -0
- package/dist/server/plugins/markdown/html/normalize-html-headings.d.ts +9 -0
- package/dist/server/plugins/markdown/html/normalize-html-headings.js +1 -0
- package/dist/server/plugins/markdown/markdoc/markdoc-options.js +1 -1
- package/dist/server/plugins/markdown/markdoc/plugins/utils.d.ts +1 -1
- package/dist/server/plugins/markdown/markdoc/plugins/utils.js +1 -1
- package/dist/server/plugins/markdown/markdown-static-data-loader.js +1 -1
- package/dist/server/plugins/markdown/search/get-ai-search-documents.js +1 -1
- package/dist/server/plugins/markdown/search/search-resolver.js +1 -1
- package/dist/server/plugins/markdown/search/to-markdown.js +13 -13
- package/dist/server/plugins/markdown/search/walk-sections.d.ts +3 -1
- package/dist/server/plugins/markdown/search/walk-sections.js +3 -3
- package/dist/server/plugins/markdown/utils/sanitize-malformed-md-content.js +2 -2
- package/dist/server/plugins/mcp/audit/audit-log.d.ts +1 -1
- package/dist/server/plugins/mcp/audit/audit-log.js +1 -1
- package/dist/server/plugins/mcp/audit/code-credentials.d.ts +9 -0
- package/dist/server/plugins/mcp/audit/code-credentials.js +2 -0
- package/dist/server/plugins/mcp/codemode/capabilities/fetch/index.js +5 -5
- package/dist/server/plugins/mcp/codemode/capabilities/types.d.ts +3 -1
- package/dist/server/plugins/mcp/codemode/capabilities/utils.d.ts +2 -1
- package/dist/server/plugins/mcp/codemode/capabilities/utils.js +3 -3
- package/dist/server/plugins/mcp/codemode/code-audit.d.ts +4 -3
- package/dist/server/plugins/mcp/codemode/code-execution-audit.js +1 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/core/utils.js +1 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/openapi/list-apis.js +1 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/openapi/utils.d.ts +12 -3
- package/dist/server/plugins/mcp/docs-mcp/tools/openapi/utils.js +1 -1
- package/dist/server/plugins/mcp/docs-mcp/utils/resolve-refs.d.ts +2 -2
- package/dist/server/plugins/mcp/docs-mcp/utils/resolve-refs.js +1 -1
- package/dist/server/plugins/mcp/gateway-mcp/allowed-http-methods.d.ts +11 -0
- package/dist/server/plugins/mcp/gateway-mcp/allowed-http-methods.js +1 -0
- package/dist/server/plugins/mcp/gateway-mcp/api-call-operations.d.ts +32 -0
- package/dist/server/plugins/mcp/gateway-mcp/api-call-operations.js +1 -0
- package/dist/server/plugins/mcp/gateway-mcp/callable-apis.d.ts +7 -4
- package/dist/server/plugins/mcp/gateway-mcp/callable-apis.js +1 -1
- package/dist/server/plugins/mcp/gateway-mcp/caller-api-calls.d.ts +9 -0
- package/dist/server/plugins/mcp/gateway-mcp/caller-api-calls.js +1 -0
- package/dist/server/plugins/mcp/gateway-mcp/elicitation.d.ts +1 -0
- package/dist/server/plugins/mcp/gateway-mcp/elicitation.js +5 -5
- package/dist/server/plugins/mcp/gateway-mcp/eligibility.d.ts +8 -4
- package/dist/server/plugins/mcp/gateway-mcp/eligibility.js +1 -1
- package/dist/server/plugins/mcp/gateway-mcp/fetch/fetch-audit.d.ts +2 -1
- package/dist/server/plugins/mcp/gateway-mcp/fetch/fetch-audit.js +1 -1
- package/dist/server/plugins/mcp/gateway-mcp/fetch/fetch-bridge.d.ts +11 -1
- package/dist/server/plugins/mcp/gateway-mcp/fetch/fetch-bridge.js +1 -1
- package/dist/server/plugins/mcp/gateway-mcp/fetch/redact.d.ts +11 -0
- package/dist/server/plugins/mcp/gateway-mcp/fetch/redact.js +1 -1
- package/dist/server/plugins/mcp/gateway-mcp/fetch-capability.js +1 -1
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/fetch-limiter/fetch-count-client.d.ts +4 -0
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/fetch-limiter/fetch-count-client.js +1 -0
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/fetch-limiter/fetch-count-secret.d.ts +4 -0
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/fetch-limiter/fetch-count-secret.js +1 -0
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/fetch-limiter/fetch-count.d.ts +11 -0
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/fetch-limiter/fetch-count.js +1 -0
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/fetch-limiter/fetch-counter-repository.d.ts +13 -0
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/fetch-limiter/fetch-counter-repository.js +13 -0
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/{limits.d.ts → fetch-limiter/fetch-limits.d.ts} +1 -1
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/fetch-limiter/fetch-limits.js +1 -0
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/{apply-edge-rate-limit.d.ts → request-limiter/apply-edge-rate-limit.d.ts} +1 -1
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/request-limiter/apply-edge-rate-limit.js +1 -0
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/{edge-limiter.d.ts → request-limiter/edge-limiter.d.ts} +3 -3
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/request-limiter/edge-limiter.js +1 -0
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/request-limiter/rate-limit-telemetry.js +1 -0
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/request-limiter/request-limits.d.ts +6 -0
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/request-limiter/request-limits.js +1 -0
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/utils/ip-key.js +1 -0
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/{window-counter.d.ts → utils/window-counter.d.ts} +1 -1
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/utils/window-counter.js +1 -0
- package/dist/server/plugins/mcp/gateway-mcp/route-pattern.d.ts +18 -0
- package/dist/server/plugins/mcp/gateway-mcp/route-pattern.js +1 -0
- package/dist/server/plugins/mcp/gateway-mcp/secret-store.d.ts +9 -3
- package/dist/server/plugins/mcp/gateway-mcp/secret-store.js +1 -1
- package/dist/server/plugins/mcp/gateway-mcp/subject.js +1 -1
- package/dist/server/plugins/mcp/gateway-mcp/upstream-auth-scheme.d.ts +2 -0
- package/dist/server/plugins/mcp/gateway-mcp/upstream-auth-scheme.js +2 -2
- package/dist/server/plugins/mcp/gateway-mcp/upstream-auth.d.ts +0 -2
- package/dist/server/plugins/mcp/gateway-mcp/upstream-auth.js +1 -1
- package/dist/server/plugins/mcp/handlers/credentials-page/constants.d.ts +7 -0
- package/dist/server/plugins/mcp/handlers/credentials-page/constants.js +1 -0
- package/dist/server/plugins/mcp/handlers/credentials-page/form-contract.d.ts +5 -0
- package/dist/server/plugins/mcp/handlers/credentials-page/form-contract.js +1 -0
- package/dist/server/plugins/mcp/handlers/credentials-page/form-page.d.ts +14 -0
- package/dist/server/plugins/mcp/handlers/credentials-page/form-page.js +62 -0
- package/dist/server/plugins/mcp/handlers/credentials-page/layout.d.ts +17 -0
- package/dist/server/plugins/mcp/handlers/credentials-page/layout.js +11 -0
- package/dist/server/plugins/mcp/handlers/credentials-page/outcome-pages.d.ts +10 -0
- package/dist/server/plugins/mcp/handlers/credentials-page/outcome-pages.js +11 -0
- package/dist/server/plugins/mcp/handlers/credentials-page/site-branding.d.ts +10 -0
- package/dist/server/plugins/mcp/handlers/credentials-page/site-branding.js +1 -0
- package/dist/server/plugins/mcp/handlers/credentials-page/styles.d.ts +4 -0
- package/dist/server/plugins/mcp/handlers/credentials-page/styles.js +186 -0
- package/dist/server/plugins/mcp/handlers/credentials-page/types.d.ts +32 -0
- package/dist/server/plugins/mcp/handlers/credentials-page/types.js +0 -0
- package/dist/server/plugins/mcp/handlers/docs-mcp-handler.js +1 -1
- package/dist/server/plugins/mcp/handlers/handle-mcp-request.js +1 -1
- package/dist/server/plugins/mcp/handlers/mcp-credentials-handler.d.ts +0 -1
- package/dist/server/plugins/mcp/handlers/mcp-credentials-handler.js +1 -1
- package/dist/server/plugins/mcp/index.js +1 -1
- package/dist/server/plugins/mcp/servers/docs-server.js +1 -1
- package/dist/server/plugins/mcp/servers/mcp-server.js +2 -2
- package/dist/server/plugins/mcp/types.d.ts +16 -1
- package/dist/server/plugins/mcp/utils/mode.d.ts +4 -1
- package/dist/server/plugins/mcp/utils/mode.js +1 -1
- package/dist/server/plugins/mcp/utils/xmcp-utils.d.ts +3 -5
- package/dist/server/plugins/mcp/utils/xmcp-utils.js +1 -1
- package/dist/server/plugins/nav-utils.js +1 -1
- package/dist/server/plugins/scorecard-classic/loaders/scorecard.js +1 -1
- package/dist/server/plugins/scorecard-classic/template/components.js +1 -1
- package/dist/server/plugins/scorecard-classic/template/useData.js +1 -1
- package/dist/server/plugins/search/engines/flexsearch/index.js +2 -2
- package/dist/server/plugins/sidebars/index.js +2 -2
- package/dist/server/plugins/sidebars/utils.js +1 -1
- package/dist/server/providers/database/client.d.ts +5 -0
- package/dist/server/providers/database/client.js +1 -1
- package/dist/server/providers/database/copy-migrations.js +1 -1
- package/dist/server/providers/database/database-connections-manager.js +1 -1
- package/dist/server/providers/database/has-project-database.d.ts +3 -0
- package/dist/server/providers/database/has-project-database.js +1 -0
- package/dist/server/store.d.ts +2 -0
- package/dist/server/store.js +1 -1
- package/dist/server/tools/notifiers/formatter.js +1 -1
- package/dist/server/tools/notifiers/helpers/privacy/mask-email.js +1 -1
- package/dist/server/tools/notifiers/logger.js +1 -1
- package/dist/server/types/plugins/markdown.d.ts +2 -0
- package/dist/server/types/web-server.d.ts +1 -0
- package/dist/server/utils/codeframes/codeframes.js +2 -2
- package/dist/server/utils/entitlements/read-entitlement-number.d.ts +3 -0
- package/dist/server/utils/entitlements/read-entitlement-number.js +1 -0
- package/dist/server/utils/fs.js +1 -1
- package/dist/server/utils/is-api-download-link.d.ts +1 -0
- package/dist/server/utils/is-api-download-link.js +1 -1
- package/dist/server/utils/rbac.js +1 -1
- package/dist/server/utils/redact-url.d.ts +3 -2
- package/dist/server/utils/redact-url.js +1 -1
- package/dist/server/utils/sandbox-context.d.ts +7 -4
- package/dist/server/utils/sandbox-context.js +1 -1
- package/dist/server/web-server/auth.d.ts +0 -1
- package/dist/server/web-server/auth.js +4 -4
- package/dist/server/web-server/dev-server.js +1 -1
- package/dist/server/web-server/http.d.ts +2 -1
- package/dist/server/web-server/http.js +2 -2
- package/dist/server/web-server/jwt/token-types.d.ts +1 -0
- package/dist/server/web-server/jwt/token-types.js +1 -1
- package/dist/server/web-server/middleware/catalogAuthMiddleware.js +1 -1
- package/dist/server/web-server/middleware/dynamic-middleware/hono-compose.js +1 -1
- package/dist/server/web-server/middleware/responseHeadersMiddleware.js +1 -1
- package/dist/server/web-server/routes/auth.d.ts +1 -1
- package/dist/server/web-server/routes/auth.js +1 -1
- package/dist/server/web-server/routes/catalog/helpers/create-entity-schema.d.ts +1756 -1756
- package/dist/server/web-server/routes/catalog/helpers/create-entity-update-schema.d.ts +295 -295
- package/dist/server/web-server/routes/cors-proxy.js +2 -2
- package/dist/server/web-server/routes/index.js +1 -1
- package/dist/server/web-server/routes/mcp-routes/mcp-consent-page.d.ts +24 -0
- package/dist/server/web-server/routes/mcp-routes/mcp-consent-page.js +35 -0
- package/dist/server/web-server/routes/mcp-routes/mcp-fetch-count.d.ts +8 -0
- package/dist/server/web-server/routes/mcp-routes/mcp-fetch-count.js +1 -0
- package/dist/server/web-server/routes/mcp-routes/mcp-oauth-store.d.ts +15 -0
- package/dist/server/web-server/routes/mcp-routes/mcp-oauth-store.js +1 -0
- package/dist/server/web-server/routes/mcp-routes/mcp-oauth.d.ts +3 -1
- package/dist/server/web-server/routes/mcp-routes/mcp-oauth.js +1 -1
- package/dist/server/web-server/routes/mcp-routes/mcp-routes.js +1 -1
- package/dist/server/web-server/routes/mcp-routes/mcp-server-card.js +1 -1
- package/dist/server/web-server/routes/resolve-route.js +1 -1
- package/dist/server/workers/worker-pool.js +1 -1
- package/dist/types/entitlements.d.ts +2 -0
- package/dist/utils/time/debounce.js +1 -1
- package/package.json +10 -11
- package/dist/client/app/utils/withLoadProgress.d.ts +0 -2
- package/dist/client/app/utils/withLoadProgress.js +0 -1
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/apply-edge-rate-limit.js +0 -1
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/edge-limiter.js +0 -1
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/ip-key.js +0 -1
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/limits.js +0 -1
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/rate-limit-telemetry.js +0 -1
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/window-counter.js +0 -1
- package/dist/server/plugins/mcp/handlers/mcp-credentials-page.d.ts +0 -12
- package/dist/server/plugins/mcp/handlers/mcp-credentials-page.js +0 -225
- /package/dist/server/plugins/mcp/gateway-mcp/rate-limit/{rate-limit-telemetry.d.ts → request-limiter/rate-limit-telemetry.d.ts} +0 -0
- /package/dist/server/plugins/mcp/gateway-mcp/rate-limit/{ip-key.d.ts → utils/ip-key.d.ts} +0 -0
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import
|
|
2
|
-
Usage: ${e}/https://api.example.com/path`);const
|
|
1
|
+
import D from"node:dns";import{isIP as x}from"node:net";import{Agent as M}from"undici";import{withPathPrefix as $}from"@redocly/theme/core/utils";import{ServerRoutes as N}from"../../../constants/api.js";import{envConfig as S}from"../../config/env-config.js";import{getRequestOrigin as b}from"../utils/get-request-origin.js";import{SsrfBlockedError as U}from"../utils/ssrf-blocklist.js";import{createSsrfSafeLookup as W}from"../utils/ssrf-safe-lookup.js";const z=new Set(["connection","keep-alive","proxy-authenticate","proxy-connection","proxy-authorization","te","trailer","transfer-encoding","upgrade","host"]),Y=new Set(["cookie","cookie2","accept-encoding"]),B=new Set(["set-cookie","set-cookie2","content-encoding","content-length","clear-site-data","strict-transport-security","alt-svc","nel","report-to","reporting-endpoints","set-login","accept-ch","critical-ch","service-worker-allowed"]),v="x-redocly-proxy-streaming",P="x-http-method-override",T="x-redocly-cookie",A="Requests to private network addresses are not allowed",F=new M({connect:{lookup:W()}});function me(t,e=$(N.CORS_PROXY)){const n=async r=>{const s=new URL(r.req.url).pathname;if(s===e||s===`${e}/`)return r.text(`Realm CORS proxy endpoint.
|
|
2
|
+
Usage: ${e}/https://api.example.com/path`);const i=oe(r.req.url,e);if(!i)return r.text("Invalid proxied URL",400);const l=t?.getConfig().corsProxy?.allowedTargets;if(l&&l.length>0&&!l.some(p=>te(i,p)))return r.text("Target URL is not in the allowed list for CORS proxy",403);const m=b(r),g=i.origin===m,w=i.pathname===e||i.pathname.startsWith(`${e}/`);if(g&&!w)return new Response("Please use a direct request",{status:308,headers:{Location:i.toString(),Vary:"origin"}});const u=await J(i.hostname),R=!S.isDevelopMode||S.isReunite;if(R&&u&&K(u))return r.text(A,403);const a=new Headers,C=I(r.req.raw.headers);for(const[o,p]of r.req.raw.headers)C.has(o.toLowerCase())||Y.has(o.toLowerCase())||a.append(o,p);const E=a.get(T);E&&(a.set("cookie",E),a.delete(T));const k=r.req.raw.headers.get("origin")||"";j(k)&&a.delete("origin");let f=r.req.method;const y=a.get(P);y&&(f=y.toUpperCase(),a.delete(P));const h={method:f,headers:a,redirect:"manual"};R&&(h.dispatcher=F),f!=="GET"&&f!=="HEAD"&&r.req.raw.body&&(h.body=r.req.raw.body,h.duplex="half");let c;try{c=await fetch(i,h)}catch(o){if(o instanceof Error&&o.cause instanceof U)return r.text(A,403);const p=o instanceof Error?o.message:"unknown error",L=o instanceof Error&&o.cause instanceof Error?`: ${o.cause.message}`:"";return r.text(`Failed to proxy request: ${p}${L}`,502)}const H=r.req.raw.headers.get("sec-fetch-mode");if((H==="navigate"||H==="no-cors")&&ne(c))return r.text("Direct browser navigation to proxied HTML, JavaScript, or redirect responses is not allowed",403);const d=new Headers(c.headers),q=I(c.headers);for(const o of q)d.delete(o);for(const o of B)d.delete(o);return d.set(v,"1"),d.set("x-content-type-options","nosniff"),d.has("content-type")||d.set("content-type","text/plain"),new Response(c.body,{status:c.status,statusText:c.statusText,headers:d})};return async r=>{const s=await n(r);return s.headers.set("cache-control","no-store"),s}}function G(t){try{return decodeURIComponent(t)}catch{return t}}function V(t){return t.replace(/^(https?):\/(?!\/)/i,"$1://")}function X(t,e){return e?t.includes("?")?e==="?"?t:`${t.endsWith("?")||t.endsWith("&")?t:`${t}&`}${e.slice(1)}`:`${t}${e}`:t}function I(t){const e=new Set(z),n=t.get("connection");if(!n)return e;for(const r of n.split(",")){const s=r.trim().toLowerCase();s&&e.add(s)}return e}function j(t){const e=t.toLowerCase();return e.includes(".redocly.app")||e.includes("localhost")}async function J(t){const e=O(t);if(x(e))return e;try{const{address:n}=await D.promises.lookup(e);return n}catch{return null}}function K(t){const e=O(t).toLowerCase();if(!x(e))return!0;const n=Q(e);return n?_(n):e.includes(":")?Z(e):_(e)}function O(t){return t.startsWith("[")&&t.endsWith("]")?t.slice(1,-1):t}function Q(t){const e=t.match(/^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/i);if(e){const r=parseInt(e[1],16),s=parseInt(e[2],16);return[r>>8&255,r&255,s>>8&255,s&255].join(".")}return t.match(/^::ffff:(\d+\.\d+\.\d+\.\d+)$/i)?.[1]??null}function _(t){const e=t.split(".").map(Number);if(e.length!==4||e.some(s=>isNaN(s)))return!0;const[n,r]=e;return n===0||n===10||n===127||n===172&&r>=16&&r<=31||n===192&&r===168||n===169&&r===254||n===100&&r>=64&&r<=127}function Z(t){const e=ee(t);return t==="::1"||t==="::"||e!==null&&(e&65024)===64512||e!==null&&(e&65472)===65152}function ee(t){const[e]=t.split(":");if(!e)return null;const n=parseInt(e,16);return Number.isNaN(n)?null:n}function te(t,e){let n;try{n=new URL(e)}catch{return!1}if(t.origin!==n.origin)return!1;const r=n.pathname.endsWith("/")?n.pathname:`${n.pathname}/`;return t.pathname.startsWith(r)||t.pathname===n.pathname}function ne(t){const e=t.status>=300&&t.status<400&&t.headers.has("location")||t.headers.has("refresh"),n=t.status===401&&t.headers.has("www-authenticate");return e||n||re(t.headers.get("content-type")||"")}function re(t){const e=t.toLowerCase();return e.includes("text/html")||e.includes("javascript")||e.includes("application/xhtml")||e.includes("application/xml")||e.includes("text/xml")||e.includes("ecmascript")||e.includes("image/svg")}function oe(t,e){const n=new URL(t),r=n.pathname===e,s=n.pathname.startsWith(`${e}/`);if(!r&&!s)return null;const i=n.pathname.slice(e.length).replace(/^\/+/,"");if(!i)return null;const l=[i,G(i)];for(const m of l){const g=V(m),w=X(g,n.search);try{const u=new URL(w);if(u.protocol==="http:"||u.protocol==="https:")return u}catch{continue}}return null}const ge=v;export{ge as CORS_PROXY_STREAM_HEADER,me as corsProxyHandler,K as isPrivateIp,oe as resolveCorsProxyTarget};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{serveStatic as c}from"hono/serve-static";import{withPathPrefix as i,withoutPathPrefix as H}from"@redocly/theme/core/utils";import{ServerRoutes as l}from"../../../constants/api.js";import{LLMS_TXT_FILE_NAME as L,PUBLIC_STATIC_FOLDER as C}from"../../constants/common.js";import{envConfig as I}from"../../config/env-config.js";import{authMiddleware as g}from"../middleware/authMiddleware.js";import{ensureSearchData as h}from"../middleware/ensureSearchData.js";import{dynamicMiddleware as D}from"../middleware/dynamic-middleware/dynamic-middleware.js";import{installRoutes as P}from"../../plugins/dev-onboarding/api/routes/index.js";import{installSkillsRoutes as N}from"./skills/skills-routes.js";import{llmsTxtHandler as M}from"./llms-txt.js";import{authorizeHandler as w,oidcCallbackHandler as B,logoutHandler as E,postLogoutHandler as v,idpLoginHandler as F,redoclyLoginCallbackHandler as G,samlCallbackHandler as U,redoclyTokenLoginHandler as Y,inviteHandler as y}from"./auth.js";import{appDataHandler as K}from"./app-data.js";import{searchFacetsHandler as k,searchHandler as x}from"./search.js";import{dynamicRouteHandler as b}from"./dynamic-route.js";import{pageDataHandler as V,sharedPageDataHandler as q}from"./page-data.js";import{pathPrefixRedirectHandler as X}from"./path-prefix-redirect.js";import{getRoutesByLineHandler as _,resolvePathHandler as S,resolvePathsHandler as $,resolveSlugHandler as f}from"./resolve-route.js";import{feedbackHandler as j}from"./feedback.js";import{loggerMiddleware as z}from"../middleware/loggerMiddleware.js";import{responseHeadersMiddleware as W}from"../middleware/responseHeadersMiddleware.js";import{idleTimeoutMiddleware as Z}from"../middleware/idleTimeoutMiddleware.js";import{otelTracesHandler as u}from"./otel/otel.js";import{healthCheckHandler as J}from"./health.js";import{askAiHandler as Q,aiAssistantEscalationsHandler as aa,aiAssistantFeedbackHandler as ea,AI_ASSISTANT_IDENTITY_STATUS_HEADER as ia}from"./ask-ai.js";import{semanticSearchHandler as la}from"./semantic-search.js";import{replayOauth2RedirectCallbackHandler as ta}from"./replay-oauth2-redirect.js";import{corsProxyHandler as r}from"./cors-proxy.js";import{corsMiddleware as
|
|
1
|
+
import{serveStatic as c}from"hono/serve-static";import{withPathPrefix as i,withoutPathPrefix as H}from"@redocly/theme/core/utils";import{ServerRoutes as l}from"../../../constants/api.js";import{LLMS_TXT_FILE_NAME as L,PUBLIC_STATIC_FOLDER as C}from"../../constants/common.js";import{envConfig as I}from"../../config/env-config.js";import{authMiddleware as g}from"../middleware/authMiddleware.js";import{ensureSearchData as h}from"../middleware/ensureSearchData.js";import{dynamicMiddleware as D}from"../middleware/dynamic-middleware/dynamic-middleware.js";import{installRoutes as P}from"../../plugins/dev-onboarding/api/routes/index.js";import{installSkillsRoutes as N}from"./skills/skills-routes.js";import{llmsTxtHandler as M}from"./llms-txt.js";import{authorizeHandler as w,oidcCallbackHandler as B,logoutHandler as E,postLogoutHandler as v,idpLoginHandler as F,redoclyLoginCallbackHandler as G,samlCallbackHandler as U,redoclyTokenLoginHandler as Y,inviteHandler as y}from"./auth.js";import{appDataHandler as K}from"./app-data.js";import{searchFacetsHandler as k,searchHandler as x}from"./search.js";import{dynamicRouteHandler as b}from"./dynamic-route.js";import{pageDataHandler as V,sharedPageDataHandler as q}from"./page-data.js";import{pathPrefixRedirectHandler as X}from"./path-prefix-redirect.js";import{getRoutesByLineHandler as _,resolvePathHandler as S,resolvePathsHandler as $,resolveSlugHandler as f}from"./resolve-route.js";import{feedbackHandler as j}from"./feedback.js";import{loggerMiddleware as z}from"../middleware/loggerMiddleware.js";import{responseHeadersMiddleware as W}from"../middleware/responseHeadersMiddleware.js";import{idleTimeoutMiddleware as Z}from"../middleware/idleTimeoutMiddleware.js";import{otelTracesHandler as u}from"./otel/otel.js";import{healthCheckHandler as J}from"./health.js";import{askAiHandler as Q,aiAssistantEscalationsHandler as aa,aiAssistantFeedbackHandler as ea,AI_ASSISTANT_IDENTITY_STATUS_HEADER as ia}from"./ask-ai.js";import{semanticSearchHandler as la}from"./semantic-search.js";import{replayOauth2RedirectCallbackHandler as ta}from"./replay-oauth2-redirect.js";import{corsProxyHandler as r}from"./cors-proxy.js";import{corsMiddleware as m}from"../middleware/corsMiddleware.js";import{installApiRoutes as ma}from"./api-routes/api-routes.js";import{cookieMiddleware as oa}from"../middleware/cookieMiddleware.js";import{staticContentHandler as da}from"../routes/static-content.js";import{infoHandler as O}from"./info.js";import{catalogHandler as Aa}from"./catalog/catalog.js";import{catalogRelationsHandler as na}from"./catalog/catalog-relations.js";import{bffCatalogHandler as sa}from"./catalog/bff-catalog.js";import{bffCatalogRevisionsHandler as pa}from"./catalog/bff-catalog-revisions.js";import{bffCatalogRelatedEntitiesHandler as Ta}from"./catalog/bff-catalog-related-entities.js";import{catalogAuthMiddleware as o}from"../middleware/catalogAuthMiddleware.js";import{telemetryMiddleware as Ea}from"../middleware/telemetry-middleware.js";import{errorHandler as _a}from"./error.js";import{installMcpRoutes as Sa}from"./mcp-routes/mcp-routes.js";import{jsonValidatorMiddleware as n}from"../middleware/jsonValidatorMiddleware.js";import{otelTracesRequestSchema as fa}from"../../../api-schemas/otel-traces.js";import{searchFacetsRequestSchema as ra}from"../../../api-schemas/search-facets.js";import{searchRequestSchema as Oa}from"../../../api-schemas/search.js";function Te(a,e,d){const{resolveRouteData:s,readStaticAsset:p,llmsTxtGenerator:A}=d;a.use("*",Z()),a.use("*",oa()),a.use("*",D(e)),a.use("*",g(e)),a.use("*",z()),a.use("*",W(e)),a.use("*",Ea()),a.use(i("*"),c({root:`./${C}`,getContent:(t,R)=>da(t,R,e,p),rewriteRequestPath:t=>H(t)})),a.use(i(l.FEEDBACK),m({allowMethods:["POST"]})),a.use(i(l.ASK_AI),m({allowMethods:["POST"],exposeHeaders:[ia]})),a.use(i(l.AI_ASSISTANT_ESCALATIONS),m({allowMethods:["POST"]})),a.use(i(l.AI_ASSISTANT_FEEDBACK),m({allowMethods:["POST"]})),a.use(i(l.SEMANTIC_SEARCH),m({allowMethods:["POST"]})),a.use("*",Ra(e));const T=h(e);a.use(i(l.INFO),O()),I.NEW_CATALOG_ENABLED&&(a.use(i(l.CATALOG_ENTITIES),o({serverOutDir:e.serverOutDir}),Aa(e)),a.use(i(l.CATALOG_ENTITIES_RELATIONS),o({serverOutDir:e.serverOutDir}),na(e)),a.get(i(l.BFF_CATALOG_ENTITIES),o({serverOutDir:e.serverOutDir,protectReadMethods:!1}),sa(e)),a.get(i(l.BFF_CATALOG_RELATED_ENTITIES),o({serverOutDir:e.serverOutDir,protectReadMethods:!1}),Ta(e)),a.get(i(l.BFF_CATALOG_REVISIONS),o({serverOutDir:e.serverOutDir,protectReadMethods:!1}),pa(e))),a.get(i(l.SHARED_PAGE_DATA),q(e)),a.get(i(l.PAGE_DATA),V(e,s)),a.get(i(l.APP_DATA),K(e)),a.post(i(l.SEARCH),T,n(Oa),x(e)),a.post(i(l.SEARCH_FACETS),T,n(ra),k(e)),a.post(i(l.AUTHORIZATION),t=>w(t,e)),a.post(i(l.LOGOUT),E(e)),a.get(i(l.LOGOUT),E(e)),a.get(i(l.POST_LOGOUT),v(e)),a.get(i(l.OIDC_CALLBACK),B(e)),a.get(i(l.REDOCLY_TOKEN_LOGIN),Y(e)),a.get(i(l.REDOCLY_LOGIN_CALLBACK),G()),a.get(i(l.IDP_LOGIN),F(e)),a.post(i(l.SAML_CALLBACK),U(e)),a.get(i(l.INVITE),y(e)),a.get(i(l.HEALTH),J),Sa(a,e),P(a,e),N(a,e),a.all(i(l.CORS_PROXY),r(e)),a.all(i(`${l.CORS_PROXY}/*`),r(e)),ma(a,e),a.post(i(l.FEEDBACK),j(e)),a.post(i(l.RESOLVE_ROUTE_BY_PATH),S(e)),a.post(i(l.RESOLVE_ROUTES_BY_PATHS),$(e)),a.post(i(l.RESOLVE_ROUTE_BY_SLUG),f(e)),a.post(i(l.ASK_AI),Q(e)),a.post(i(l.AI_ASSISTANT_ESCALATIONS),aa(e)),a.post(i(l.AI_ASSISTANT_FEEDBACK),ea(e)),a.post(i(l.SEMANTIC_SEARCH),la(e)),a.get(i(l.GET_ROUTES_BY_LINE),_(e)),a.post(i(l.OTEL_TRACES),n(fa),u),a.get(i(l.REPLAY_OAUTH2_CALLBACK),ta),A&&a.get(i(`/${L}`),M(A)),a.all(i("/*"),b(e,s,p,A)),a.get("*",X),a.onError(_a)}function Ra(a){return async(e,d)=>{await a.waitForPluginsLifecycle(),await d()}}function Ee(a,e){a.get(i(l.INFO),O()),a.post(i(l.RESOLVE_ROUTE_BY_PATH),S(e)),a.post(i(l.RESOLVE_ROUTE_BY_SLUG),f(e)),a.get(i(l.GET_ROUTES_BY_LINE),_(e))}export{Ee as installDevRoutes,Te as installProdRoutes,Ra as waitForPluginsLifecycle};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { PageSite } from '../../../plugins/mcp/handlers/credentials-page/types.js';
|
|
2
|
+
/** How long the signed consent value on the page stays valid. */
|
|
3
|
+
export declare const MCP_CONSENT_TTL_SEC: number;
|
|
4
|
+
export declare const CONSENT_PAGE_HEADERS: {
|
|
5
|
+
'Content-Type': string;
|
|
6
|
+
'Cache-Control': string;
|
|
7
|
+
'X-Frame-Options': string;
|
|
8
|
+
'Referrer-Policy': string;
|
|
9
|
+
'Content-Security-Policy': string;
|
|
10
|
+
};
|
|
11
|
+
export type ConsentPageProps = {
|
|
12
|
+
site: PageSite;
|
|
13
|
+
user: string | undefined;
|
|
14
|
+
clientName: string | undefined;
|
|
15
|
+
clientIdHost: string | undefined;
|
|
16
|
+
redirectUrl: URL;
|
|
17
|
+
scopes: readonly string[];
|
|
18
|
+
accessLifetimeHours: number;
|
|
19
|
+
rememberDays: number | undefined;
|
|
20
|
+
consentToken: string;
|
|
21
|
+
};
|
|
22
|
+
export declare function consentPage({ site, user, clientName, clientIdHost, redirectUrl, scopes, accessLifetimeHours, rememberDays, consentToken, }: ConsentPageProps): string;
|
|
23
|
+
export declare function consentInvalidPage(site: PageSite): string;
|
|
24
|
+
//# sourceMappingURL=mcp-consent-page.d.ts.map
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import{ICONS as d,code as E,escapeHtml as a,htmlDocument as p,siteHeader as N}from"../../../plugins/mcp/handlers/credentials-page/layout.js";import{statusPage as L}from"../../../plugins/mcp/handlers/credentials-page/outcome-pages.js";const $=300,e={TITLE:"Allow MCP access",INTRO:"An MCP client asks to use this portal with your account.",WARNING:"Allow access only if you started this connection in your MCP client.",REDIRECT_LABEL:"Sends access to",REDIRECT_HINT:"The app receives access at this address.",USER_LABEL:"Signed in as",NOT_PROVIDED:"Not provided",CLIENT_LABEL:"App",CLIENT_UNKNOWN:"The app did not send a name. Continue only if you just started a connection yourself.",CLIENT_NAME_HINT:"The app chose this name itself. We do not check it.",CLIENT_ID_HOST:s=>`App details loaded from ${E(s)}`,PANEL_TITLE:"What the client gets",ACCOUNT_DETAILS:"Your account details, including your name and email address",ACT_AS_YOU:"Use of the MCP server of this portal as you",ACCESS_LIFETIME:s=>`Access that it can renew for up to ${s} hours`,REMEMBER:s=>`If you allow access, we do not ask again for this client for ${s} days.`,SCOPES_LABEL:"Scopes:",ALLOW:"Allow access",DENY:"Deny",INVALID_TITLE:"This request is no longer valid",INVALID_BODY:s=>`An access request works for ${s} minutes. This one has expired or can no longer be used.`,INVALID_NEXT:"Go back to your MCP client and start the connection again."},f={"Content-Type":"text/html; charset=utf-8","Cache-Control":"no-store","X-Frame-Options":"DENY","Referrer-Policy":"no-referrer","Content-Security-Policy":"default-src 'none'; style-src 'unsafe-inline'; img-src 'self'; frame-ancestors 'none'; base-uri 'none'"};function _({protocol:s,host:n,pathname:t,search:o}){return`${s}${n?`//${n}`:""}${t}${o}`}function r(s,n,t){return`<section aria-labelledby="${s}">
|
|
2
|
+
<h2 id="${s}">${a(n)}</h2>
|
|
3
|
+
${t.filter(Boolean).join(`
|
|
4
|
+
`)}
|
|
5
|
+
</section>`}function m(s,n){return r("consent-client",e.CLIENT_LABEL,[s?`<p>${a(s)}</p><p class="muted small">${e.CLIENT_NAME_HINT}</p>`:`<p>${e.CLIENT_UNKNOWN}</p>`,n?`<p class="muted small">${e.CLIENT_ID_HOST(n)}</p>`:""])}function A({scopes:s,accessLifetimeHours:n,rememberDays:t}){const o=`${d.shield}${e.PANEL_TITLE}`,i=`<ol class="steps">
|
|
6
|
+
<li>${e.ACCOUNT_DETAILS}</li>
|
|
7
|
+
<li>${e.ACT_AS_YOU}</li>
|
|
8
|
+
<li>${e.ACCESS_LIFETIME(n)}</li>
|
|
9
|
+
</ol>`,c=t?`<p>${e.REMEMBER(t)}</p>`:"";return`<aside class="panel" aria-labelledby="panel-title">
|
|
10
|
+
<div class="panel-steps"><h2 id="panel-title">${o}</h2>${i}</div>
|
|
11
|
+
<details class="panel-steps-toggle"><summary><h2>${o}</h2></summary>${i}</details>
|
|
12
|
+
<div class="link-facts">
|
|
13
|
+
${c}
|
|
14
|
+
<div class="tags"><span>${e.SCOPES_LABEL}</span>${s.map(l=>`<span class="tag">${a(l)}</span>`).join("")}</div>
|
|
15
|
+
</div>
|
|
16
|
+
</aside>`}function S({site:s,user:n,clientName:t,clientIdHost:o,redirectUrl:i,scopes:c,accessLifetimeHours:l,rememberDays:T,consentToken:u}){const I=`<div class="page">
|
|
17
|
+
<main class="card">
|
|
18
|
+
${N(s)}
|
|
19
|
+
<h1>${e.TITLE}</h1>
|
|
20
|
+
<p class="lede">${e.INTRO}</p>
|
|
21
|
+
<div class="banner warning" role="note">${d.warning}<p>${e.WARNING}</p></div>
|
|
22
|
+
<div class="info-card">
|
|
23
|
+
${m(t,o)}
|
|
24
|
+
${r("consent-user",e.USER_LABEL,[`<p>${a(n||e.NOT_PROVIDED)}</p>`])}
|
|
25
|
+
${r("consent-redirect",e.REDIRECT_LABEL,[`<p>${E(_(i))}</p>`,`<p class="muted small">${e.REDIRECT_HINT}</p>`])}
|
|
26
|
+
</div>
|
|
27
|
+
<form class="credentials" method="post" autocomplete="off">
|
|
28
|
+
<input type="hidden" name="consent" value="${a(u)}">
|
|
29
|
+
<div class="actions">
|
|
30
|
+
<div class="actions-row"><button class="secondary" type="submit" name="decision" value="deny">${e.DENY}</button><button class="primary" type="submit" name="decision" value="allow">${e.ALLOW}</button></div>
|
|
31
|
+
</div>
|
|
32
|
+
</form>
|
|
33
|
+
</main>
|
|
34
|
+
${A({scopes:c,accessLifetimeHours:l,rememberDays:T})}
|
|
35
|
+
</div>`;return p({title:e.TITLE,body:I},s.colorScheme)}function y(s){return p(L("warning",e.INVALID_TITLE,[e.INVALID_BODY($/60),e.INVALID_NEXT]),s.colorScheme)}export{f as CONSENT_PAGE_HEADERS,$ as MCP_CONSENT_TTL_SEC,y as consentInvalidPage,S as consentPage};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Env, Handler, MiddlewareHandler } from 'hono';
|
|
2
|
+
import type { z } from 'zod';
|
|
3
|
+
import type { Store } from '../../../store';
|
|
4
|
+
import type { ValidatedJsonInput } from '../../../types';
|
|
5
|
+
import type { mcpFetchCountRequestSchema } from '../../../../api-schemas/mcp-fetch-count.js';
|
|
6
|
+
export declare function mcpFetchCountAuth(): MiddlewareHandler;
|
|
7
|
+
export declare function mcpFetchCountHandler(store: Store): Handler<Env, string, ValidatedJsonInput<z.infer<typeof mcpFetchCountRequestSchema>>>;
|
|
8
|
+
//# sourceMappingURL=mcp-fetch-count.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{envConfig as o}from"../../../config/env-config.js";import{FetchCounterRepository as n}from"../../../plugins/mcp/gateway-mcp/rate-limit/fetch-limiter/fetch-counter-repository.js";import{isFetchCountSecret as i}from"../../../plugins/mcp/gateway-mcp/rate-limit/fetch-limiter/fetch-count-secret.js";import{applyFetchCount as u}from"../../../plugins/mcp/gateway-mcp/rate-limit/fetch-limiter/fetch-count.js";import{resolveGatewayFetchLimits as m}from"../../../plugins/mcp/gateway-mcp/rate-limit/fetch-limiter/fetch-limits.js";import{extractTokenFromAuthHeader as c}from"../../../plugins/mcp/utils/jwt.js";function D(){return async(e,t)=>{if(!i(c(e.req.header("authorization"))))return e.body(null,403);await t()}}function d(e){return async t=>{const a=await n.create({baseDbDir:e.serverOutDir,sqldRemoteDatabaseUrl:o.SQLD_REMOTE_DATABASE_URL,sqldRemoteDatabaseAuthToken:o.SQLD_REMOTE_DATABASE_AUTH_TOKEN}),r=await u(a,t.req.valid("json").caller,m(),Date.now());return r?t.text(r,429):t.body(null,204)}}export{D as mcpFetchCountAuth,d as mcpFetchCountHandler};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { KvService } from '@redocly/config';
|
|
2
|
+
export declare const MCP_CONSENT_MEMORY_DAYS = 30;
|
|
3
|
+
export type ConsentGrant = {
|
|
4
|
+
idpId: string | undefined;
|
|
5
|
+
subject: string;
|
|
6
|
+
clientId: string;
|
|
7
|
+
redirectUri: string;
|
|
8
|
+
};
|
|
9
|
+
export declare function hasConsent(kv: KvService, grant: ConsentGrant): Promise<boolean>;
|
|
10
|
+
export declare function saveConsent(kv: KvService, grant: ConsentGrant): Promise<void>;
|
|
11
|
+
/** Returns false when the code was already redeemed. */
|
|
12
|
+
export declare function redeemAuthorizationCode(kv: KvService, code: string, expiresAtSec: number): Promise<boolean>;
|
|
13
|
+
/** Returns false when the refresh token was already redeemed. */
|
|
14
|
+
export declare function redeemRefreshToken(kv: KvService, refreshToken: string, expiresAtSec: number): Promise<boolean>;
|
|
15
|
+
//# sourceMappingURL=mcp-oauth-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{createHash as i}from"node:crypto";const u=30;function r(e){return i("sha256").update(e).digest("hex")}function s({idpId:e,subject:t,clientId:n,redirectUri:o}){return["mcp","consent",r(JSON.stringify([e??null,t])),r(JSON.stringify([n,o]))]}async function f(e,t){return await e.get(s(t))!==null}async function m(e,t){await e.set(s(t),{approvedAt:Date.now()},{ttlInSeconds:u*24*60*60})}function p(e,t,n){return c(e,["mcp","redeemed-code",r(t)],n)}function h(e,t,n){return c(e,["mcp","redeemed-refresh-token",r(t)],n)}async function c(e,t,n){const o=Math.max(n-Math.floor(Date.now()/1e3),1);return e.transaction(async a=>await a.get(t)?!1:(await a.set(t,{redeemedAt:Date.now()},{ttlInSeconds:o}),!0))}export{u as MCP_CONSENT_MEMORY_DAYS,f as hasConsent,p as redeemAuthorizationCode,h as redeemRefreshToken,m as saveConsent};
|
|
@@ -9,10 +9,11 @@ export type McpContextPayload = {
|
|
|
9
9
|
mcpSessionId: string;
|
|
10
10
|
mcpCodeChallenge?: string | null;
|
|
11
11
|
mcpCodeChallengeMethod?: string | null;
|
|
12
|
+
mcpClientName?: string | null;
|
|
12
13
|
timestamp: number;
|
|
13
14
|
};
|
|
14
15
|
export declare const SUPPORTED_MCP_GRANT_TYPES: readonly ['authorization_code', 'refresh_token'];
|
|
15
|
-
export declare function verifyPkce(codeChallenge: string, codeChallengeMethod: string | undefined, codeVerifier: string): boolean;
|
|
16
|
+
export declare function verifyPkce(codeChallenge: string | undefined, codeChallengeMethod: string | undefined, codeVerifier: string): boolean;
|
|
16
17
|
export declare function createMcpContextToken(context: McpContextPayload): Promise<string>;
|
|
17
18
|
export declare function verifyAndParseMcpContextToken(token: string): Promise<McpContextPayload>;
|
|
18
19
|
export declare function mcpOAuthProtectedResourceHandler(store: Store): Handler;
|
|
@@ -26,4 +27,5 @@ export declare function resolveMcpIdpId(ssoDirect: SsoConfig | undefined): strin
|
|
|
26
27
|
export declare function mcpAuthorizationHandler(store: Store): Handler;
|
|
27
28
|
export declare function mcpTokenPortalHandler(store: Store): Handler;
|
|
28
29
|
export declare function mcpCallbackHandler(store: Store): Handler;
|
|
30
|
+
export declare function mcpConsentHandler(store: Store): Handler;
|
|
29
31
|
//# sourceMappingURL=mcp-oauth.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{getCookie as U}from"hono/cookie";import{createHash as V,timingSafeEqual as Z}from"node:crypto";import{ulid as Y}from"ulid";import{isRedoclySso as W,isOidcProviderConfig as w,createMcpAuthorizationCode as X,verifyMcpAuthorizationCode as Q,createMcpRefreshToken as $,verifyMcpRefreshToken as x,createMcpSessionResource as S,oidcRefreshTokenGrant as ee,getOidcMetadata as re,getUserParamsFromCookies as te,idTokenIsForThisProject as ne}from"../../auth.js";import{isMcpContentProtected as P}from"../../../plugins/mcp/auth/auth-handlers.js";import{SUPPORTED_MCP_SCOPES as y}from"../../../plugins/mcp/constants.js";import{AUTH_URL as oe,JWT_SECRET_KEY as m,MCP_ACCESS_TOKEN_TTL_SEC as z,MCP_REFRESH_SESSION_LIFETIME_SEC as ie}from"../../../constants/common.js";import{ServerRoutes as T}from"../../../../constants/api.js";import{AuthCookieNames as v}from"../../../../constants/common.js";import{withPathPrefix as I}from"@redocly/theme/core/utils";import{telemetry as A}from"../../../telemetry/index.js";import{envConfig as D}from"../../../config/env-config.js";import*as M from"../../jwt/jwt.js";import{InternalTokenTypes as F,McpAccessTokenMarker as R}from"../../jwt/token-types.js";import{AlgorithmTypes as L,JwtAlgorithmNotImplemented as se,JwtTokenExpired as ce,JwtTokenInvalid as de,JwtTokenNotBefore as ae,JwtTokenSignatureMismatched as le}from"../../jwt/types.js";import{getRequestOrigin as N}from"../../utils/get-request-origin.js";import{encryptClaimValue as q}from"../../../utils/crypto/encrypt-claim-value.js";import{decryptAesGcm as pe}from"../../../utils/crypto/decrypt-aes-gcm.js";import{encryptAesGcm as G}from"../../../utils/crypto/encrypt-aes-gcm.js";import{fetchClientMetadataDocument as _e,isClientMetadataDocumentUrl as H,isRedirectUriRegistered as ue}from"./mcp-client-metadata.js";const s=(r,e,n=200,o)=>r.json(e,n,{"Content-Type":"application/json",...o??{}}),b=new Set(["S256"]),j=["authorization_code","refresh_token"],fe="https://claude.ai/oauth/claude-code-client-metadata";function he(r,e,n){if(!b.has(e||""))return!1;const o=V("sha256").update(n).digest("base64url"),c=Buffer.from(o),i=Buffer.from(r);return c.length!==i.length?!1:Z(c,i)}async function me(r){const e=Math.floor(Date.now()/1e3);return M.sign({type:F.MCP_CONTEXT,...r,iat:e,exp:e+600},m,L.HS256)}async function ge(r){await M.verify(r,m,L.HS256);const{payload:e}=M.decode(r);if(e.type!==F.MCP_CONTEXT)throw new Error("Invalid context token type");return e}function je(r){return async e=>{if(!P(r))return s(e,{error:"not_found"},404);if(e.req.method!=="GET")return s(e,{error:"Method not allowed"},405,{Allow:"GET"});const n=N(e);return s(e,{resource:`${n}${I("/mcp")}`,authorization_servers:[n],bearer_methods_supported:["header"],resource_documentation:`${n}${T.MCP_OAUTH_AUTHORIZATION_SERVER}`,scopes_supported:[...y],bearer_token_types_supported:["Bearer"]},200,{"Access-Control-Allow-Origin":"*"})}}function $e(r){return async e=>{if(!P(r))return s(e,{error:"not_found"},404);const n=N(e);return s(e,{issuer:n,authorization_endpoint:`${n}${I(T.MCP_AUTHORIZATION)}`,token_endpoint:`${n}${I(T.MCP_TOKEN_PORTAL)}`,scopes_supported:[...y],registration_endpoint:`${n}${I(T.MCP_DYNAMIC_CLIENT_REGISTRATION)}`,response_types_supported:["code"],grant_types_supported:[...j],subject_types_supported:["public"],id_token_signing_alg_values_supported:["RS256"],code_challenge_methods_supported:["S256"],token_endpoint_auth_methods_supported:["none"],client_id_metadata_document_supported:!0},200,{"Access-Control-Allow-Origin":"*"})}}function ze(r){return async e=>{if(!P(r))return s(e,{error:"not_found"},404);if(e.req.method!=="POST")return s(e,{error:"Method not allowed"},405);try{return s(e,{client_id:D.OAUTH_CLIENT_ID||"",client_name:"MCP Client",redirect_uris:[],grant_types:[...j],response_types:["code"],scope:y.join(" "),subject_type:"public",token_endpoint_auth_method:"none",created_at:new Date().toISOString(),updated_at:new Date().toISOString()},201,{"Access-Control-Allow-Origin":"*"})}catch(n){return s(e,{error:"invalid_request",error_description:n?.message||"Unable to register client"},500,{"Access-Control-Allow-Origin":"*"})}}}function B(r){const e=r||{},n=Object.keys(e),o=n.find(i=>w(e[i])&&W(e[i])),c=n.find(i=>w(e[i]));return o||c||n[0]}function Fe(r){return async e=>{if(!P(r))return s(e,{error:"not_found"},404);const n=new URL(e.req.url),{searchParams:o}=n,c=o.get("redirect_uri"),i=o.get("client_id"),p=o.get("code_challenge"),t=o.get("code_challenge_method"),l=Y();if(p&&!b.has(t||""))return s(e,{error:"invalid_request",error_description:`Unsupported code_challenge_method. Supported: ${[...b].join(", ")}`},400);if(H(i)&&!p)return s(e,{error:"invalid_request",error_description:"code_challenge is required for client_id_metadata_document clients"},400);if(H(i)&&c)try{const d=await _e(i),a=i===fe;if(!ue(c,d.redirect_uris,{ignorePort:a}))return s(e,{error:"invalid_request",error_description:"redirect_uri is not registered for this client"},400)}catch(d){const a=d instanceof Error?d.message:String(d);return s(e,{error:"invalid_client",error_description:`Unable to resolve client metadata document: ${a}`},400)}A.sendMcpAuthorizationStartedMessage([{...S(l),redirect_uri:c||null}]);const _=N(e),f={isMcpFlow:!0,originalRedirectUri:c,mcpClientId:i,mcpState:o.get("state"),mcpSessionId:l,mcpCodeChallenge:p,mcpCodeChallengeMethod:p?t:null,timestamp:Date.now()};try{const d=await me(f),a=new URL(I(T.IDP_LOGIN),_);a.searchParams.set("redirectTo",`${T.MCP_CALLBACK}/${d}`);const C=B(r.getConfig().ssoDirect);return C?(a.searchParams.set("idpId",C),e.redirect(a.toString())):s(e,{error:"not_found"},404)}catch(d){const a=d instanceof Error?d.message:String(d),C=d instanceof Error?d.stack:String(d);A.sendMcpAuthorizationFailedMessage([{...S(l),error:a,error_details:C}]);const g=new URL(I(`${oe}/oauth2/auth`));return g.search=o.toString(),e.redirect(g.toString())}}}async function K(r){const e=Math.floor(Date.now()/1e3),n=await M.sign({...r.claims,[R.CLAIM]:R.VALUE,...r.idpId?{idpId:r.idpId}:{},...r.idpAccessTokenEnc?{idp_access_token:r.idpAccessTokenEnc}:{},...r.ttlSec?{iat:e,exp:e+r.ttlSec}:{}},m,L.HS256,r.kid),o=r.ttlSec??(typeof r.claims.exp=="number"?Math.max(r.claims.exp-e,0):z);return{accessToken:n,expiresIn:o}}async function ke(r,e,n){const o=k=>s(r,{error:"invalid_grant",error_description:k},400),c=r.get("logger"),i=n.get("refresh_token"),p=n.get("client_id")||void 0;if(!i)return s(r,{error:"invalid_request",error_description:"refresh_token is required"},400);let t;try{t=await x(i)}catch(k){return c?.warn("MCP refresh token rejected: %s",k instanceof Error?k.message:String(k)),o("Invalid refresh token")}if(p&&p!==t.client_id)return o("Client mismatch");const l=t.idp_id?e.getConfig().ssoDirect?.[t.idp_id]:void 0;let _,f,d=t.idp_access_token_enc,a=t.idp_refresh_token_enc;if(t.idp_refresh_token_enc){let k;try{k=pe(t.idp_refresh_token_enc,m)}catch{return o("Invalid refresh token")}if(!t.idp_id||!w(l))return o("Unknown identity provider");let u;try{const h=await re(t.idp_id,l);if(!h?.token_endpoint)return o("Identity provider has no token endpoint");u=await ee(h.token_endpoint,k,l)}catch(h){return c?.warn("MCP refresh failed to reach the IdP token endpoint: %s",h instanceof Error?h.message:String(h)),s(r,{error:"server_error",error_description:"Failed to refresh session"},500)}if(u.error||!(u.id_token||u.access_token))return c?.warn("MCP refresh rejected by IdP: %s",u.error||"empty token response"),o("Refresh rejected by identity provider");if(u.refresh_token&&(a=G(u.refresh_token,m)),u.access_token&&(d=q(u.access_token,m)),u.id_token){try{const h=M.decode(u.id_token);_=h.payload,f=h.header.kid}catch{return o("Invalid token response from identity provider")}if(_.iss!==t.claims.iss||_.sub!==t.claims.sub)return c?.warn("MCP refresh rejected: the id_token names another issuer or subject"),o("Invalid refresh token")}}const C=w(l)&&l.tokenExpirationTime||z,g=_??t.claims;if(!ne(g,l))return c?.warn("MCP refresh rejected: the id_token was issued for another project"),o("Invalid refresh token");const E=await K({claims:g,kid:f,idpId:t.idp_id,idpAccessTokenEnc:d,ttlSec:_?void 0:C}),O=await $({clientId:t.client_id,idpId:t.idp_id,claims:g,idpAccessTokenEnc:d,idpRefreshTokenEnc:a,sessionExp:t.session_exp});return s(r,{access_token:E.accessToken,token_type:"Bearer",expires_in:E.expiresIn,refresh_token:O,scope:y.join(" ")},200,{"Cache-Control":"no-store",Pragma:"no-cache"})}function Ge(r){return async e=>{if(e.req.method!=="POST")return s(e,{error:"Method not allowed"},405);try{const n=await e.req.formData(),o=n.get("grant_type"),c=n.get("code"),i=n.get("redirect_uri")||void 0,p=n.get("code_verifier")||void 0;if(!j.includes(o))return s(e,{error:"invalid_request",error_description:"Invalid grant type"},400);if(o==="refresh_token")return await ke(e,r,n);if(!c)return s(e,{error:"invalid_request",error_description:"Missing authorization code"},400);try{const t=await Q(c);if(i&&i!==t.redirect_uri)return s(e,{error:"invalid_grant",error_description:"redirect_uri mismatch"},400);if(t.code_challenge){if(!p)return s(e,{error:"invalid_grant",error_description:"code_verifier required"},400);if(!he(t.code_challenge,t.code_challenge_method,p))return s(e,{error:"invalid_grant",error_description:"code_verifier mismatch"},400)}if(D.OAUTH_CLIENT_ID&&t.client_id&&!H(t.client_id)&&t.client_id!==D.OAUTH_CLIENT_ID)return s(e,{error:"invalid_client",error_description:"Client mismatch"},400);const l=t.id_token;if(typeof l!="string"||l.length===0)return s(e,{error:"invalid_grant",error_description:"Missing id_token in authorization code"},400);const _=await J(l,r.getConfig().ssoDirect);if(!_)return s(e,{error:"invalid_grant",error_description:"Invalid authorization code"},400);const f=t.idp_access_token_enc??(t.idp_access_token?q(t.idp_access_token,m):void 0),{accessToken:d,expiresIn:a}=await K({claims:_.payload,kid:_.kid,idpId:t.idp_id,idpAccessTokenEnc:f}),g=Math.floor(Date.now()/1e3)+ie,E=await $({clientId:t.client_id,idpId:t.idp_id,claims:_.payload,idpAccessTokenEnc:f,idpRefreshTokenEnc:t.idp_refresh_token_enc,sessionExp:g}),O={access_token:d,token_type:"Bearer",expires_in:a,refresh_token:E,scope:y.join(" ")};return s(e,O,200,{"Cache-Control":"no-store",Pragma:"no-cache"})}catch(t){return e.get("logger")?.warn("MCP token exchange failed: %s",t instanceof Error?t.message:String(t)),s(e,{error:"invalid_grant",error_description:"Invalid authorization code"},400)}}catch(n){const o=n instanceof Error?n.message:String(n);return s(e,{error:"server_error",error_description:"Failed to process token request",error_details:o},500)}}}async function J(r,e){const n=await te(e||{},{[v.AUTHORIZATION]:r});if(n.isAuthenticated!==!0)return;const{payload:o,header:c}=M.decode(r);if(o[R.CLAIM]!==R.VALUE)return{payload:o,kid:c.kid,idpId:typeof n.idpId=="string"?n.idpId:void 0}}function Be(r){return async e=>{const n=new URL(e.req.url);let o=n.searchParams.get("context");if(!o&&n.pathname.startsWith(I(`${T.MCP_CALLBACK}/`))){const i=n.pathname.split("/");o=i[i.length-1]}if(!o)return e.text("Missing context parameter",400);let c=null;try{const i=await ge(o);if(c=i.mcpSessionId||null,!i.isMcpFlow||!i.originalRedirectUri)throw new Error("Invalid MCP context");const p=r.getConfig().ssoDirect,t=U(e,v.AUTHORIZATION),l=t?await J(t,p):void 0,_=U(e,v.IDP_ACCESS_TOKEN),f=U(e,v.IDP_REFRESH_TOKEN);if(!t||!l)return A.sendMcpAuthorizationFailedMessage([{...S(c),error:"Authentication required",error_details:null}]),e.text("Authentication required",401);const d=await X({idToken:t,idpId:l.idpId??B(p),idpAccessTokenEnc:_?q(_,m):void 0,idpRefreshTokenEnc:f?G(f,m):void 0,clientId:i.mcpClientId||"",redirectUri:i.originalRedirectUri,codeChallenge:i.mcpCodeChallenge||void 0,codeChallengeMethod:i.mcpCodeChallengeMethod||void 0,ttlSec:600}),a=new URL(i.originalRedirectUri);return a.searchParams.set("code",d),i.mcpState&&a.searchParams.set("state",i.mcpState),A.sendMcpAuthorizationCompletedMessage([{...S(c),redirect_uri:i.originalRedirectUri||null}]),e.redirect(a.toString())}catch(i){const p=Ce(i);return A.sendMcpAuthorizationFailedMessage([{...S(c),...p}]),e.text(`Invalid MCP callback: ${p.error}`,400)}}}function Ce(r){return r instanceof Error&&[se,ce,de,ae,le].some(e=>r instanceof e)?{error:r.name,error_details:null}:r instanceof Error?{error:r.message,error_details:r.stack??null}:{error:String(r),error_details:null}}export{j as SUPPORTED_MCP_GRANT_TYPES,me as createMcpContextToken,Fe as mcpAuthorizationHandler,Be as mcpCallbackHandler,ze as mcpDynamicClientRegistrationHandler,$e as mcpOAuthAuthorizationServerHandler,je as mcpOAuthProtectedResourceHandler,Ge as mcpTokenPortalHandler,B as resolveMcpIdpId,ge as verifyAndParseMcpContextToken,he as verifyPkce};
|
|
1
|
+
import{getCookie as H}from"hono/cookie";import{createHash as G,timingSafeEqual as oe}from"node:crypto";import{ulid as ie}from"ulid";import{isRedoclySso as se,isOidcProviderConfig as P,createMcpAuthorizationCode as ae,verifyMcpAuthorizationCode as ce,createMcpRefreshToken as K,verifyMcpRefreshToken as de,createMcpSessionResource as M,oidcRefreshTokenGrant as pe,getOidcMetadata as ue,getUserParamsFromCookies as le,idTokenIsForThisProject as _e}from"../../auth.js";import{isMcpContentProtected as R}from"../../../plugins/mcp/auth/auth-handlers.js";import{resolveSiteBranding as fe}from"../../../plugins/mcp/handlers/credentials-page/site-branding.js";import{SUPPORTED_MCP_SCOPES as E}from"../../../plugins/mcp/constants.js";import{AUTH_URL as he,JWT_SECRET_KEY as m,MCP_ACCESS_TOKEN_TTL_SEC as b,MCP_REFRESH_SESSION_LIFETIME_SEC as B}from"../../../constants/common.js";import{ServerRoutes as I}from"../../../../constants/api.js";import{AuthCookieNames as v}from"../../../../constants/common.js";import{withPathPrefix as w}from"@redocly/theme/core/utils";import{telemetry as y}from"../../../telemetry/index.js";import{envConfig as q}from"../../../config/env-config.js";import{hasProjectDatabase as j}from"../../../providers/database/has-project-database.js";import*as C from"../../jwt/jwt.js";import{InternalTokenTypes as O,McpAccessTokenMarker as U}from"../../jwt/token-types.js";import{AlgorithmTypes as A,JwtAlgorithmNotImplemented as me,JwtTokenExpired as ge,JwtTokenInvalid as Ce,JwtTokenNotBefore as Te,JwtTokenSignatureMismatched as ke}from"../../jwt/types.js";import{getRequestOrigin as L}from"../../utils/get-request-origin.js";import{encryptClaimValue as J}from"../../../utils/crypto/encrypt-claim-value.js";import{decryptAesGcm as Se}from"../../../utils/crypto/decrypt-aes-gcm.js";import{encryptAesGcm as V}from"../../../utils/crypto/encrypt-aes-gcm.js";import{fetchClientMetadataDocument as Ie,isClientMetadataDocumentUrl as z,isRedirectUriRegistered as we}from"./mcp-client-metadata.js";import{CONSENT_PAGE_HEADERS as W,MCP_CONSENT_TTL_SEC as Me,consentInvalidPage as Ee,consentPage as ye}from"./mcp-consent-page.js";import{MCP_CONSENT_MEMORY_DAYS as Ae,hasConsent as Pe,redeemAuthorizationCode as Re,redeemRefreshToken as ve,saveConsent as Oe}from"./mcp-oauth-store.js";const s=(r,e,t=200,n)=>r.json(e,t,{"Content-Type":"application/json",...n??{}}),$=new Set(["S256"]),F=["authorization_code","refresh_token"],Ue="https://claude.ai/oauth/claude-code-client-metadata";function Le(r,e,t){if(!r||!$.has(e||""))return!1;const n=G("sha256").update(t).digest("base64url"),i=Buffer.from(n),a=Buffer.from(r);return i.length!==a.length?!1:oe(i,a)}async function Ne(r){const e=Math.floor(Date.now()/1e3);return C.sign({type:O.MCP_CONTEXT,...r,iat:e,exp:e+600},m,A.HS256)}async function De(r){await C.verify(r,m,A.HS256);const{payload:e}=C.decode(r);if(e.type!==O.MCP_CONTEXT)throw new Error("Invalid context token type");return e}function mr(r){return async e=>{if(!R(r))return s(e,{error:"not_found"},404);if(e.req.method!=="GET")return s(e,{error:"Method not allowed"},405,{Allow:"GET"});const t=L(e);return s(e,{resource:`${t}${w("/mcp")}`,authorization_servers:[t],bearer_methods_supported:["header"],resource_documentation:`${t}${I.MCP_OAUTH_AUTHORIZATION_SERVER}`,scopes_supported:[...E],bearer_token_types_supported:["Bearer"]},200,{"Access-Control-Allow-Origin":"*"})}}function gr(r){return async e=>{if(!R(r))return s(e,{error:"not_found"},404);const t=L(e);return s(e,{issuer:t,authorization_endpoint:`${t}${w(I.MCP_AUTHORIZATION)}`,token_endpoint:`${t}${w(I.MCP_TOKEN_PORTAL)}`,scopes_supported:[...E],registration_endpoint:`${t}${w(I.MCP_DYNAMIC_CLIENT_REGISTRATION)}`,response_types_supported:["code"],grant_types_supported:[...F],subject_types_supported:["public"],id_token_signing_alg_values_supported:["RS256"],code_challenge_methods_supported:["S256"],token_endpoint_auth_methods_supported:["none"],client_id_metadata_document_supported:!0},200,{"Access-Control-Allow-Origin":"*"})}}function Cr(r){return async e=>{if(!R(r))return s(e,{error:"not_found"},404);if(e.req.method!=="POST")return s(e,{error:"Method not allowed"},405);try{return s(e,{client_id:q.OAUTH_CLIENT_ID||"",client_name:"MCP Client",redirect_uris:[],grant_types:[...F],response_types:["code"],scope:E.join(" "),subject_type:"public",token_endpoint_auth_method:"none",created_at:new Date().toISOString(),updated_at:new Date().toISOString()},201,{"Access-Control-Allow-Origin":"*"})}catch(t){return s(e,{error:"invalid_request",error_description:t?.message||"Unable to register client"},500,{"Access-Control-Allow-Origin":"*"})}}}const He=new Set(["127.0.0.1","localhost","[::1]"]),be=new Set(["http:","https:","ws:","wss:","ftp:","file:"]),qe=new Set(["javascript:","data:","blob:","about:","vbscript:","intent:","chrome:","view-source:","ms-msdt:","ms-appx-web:"]),je=2048,ze=/[\s\p{Cc}]/u;function Y(r){return r.protocol==="http:"&&He.has(r.hostname)}function Z(r){if(!r||r.length>je||r.includes("#")||ze.test(r))return;const e=URL.parse(r);if(e){if(e.protocol==="https:"||Y(e))return r.toLowerCase().startsWith(`${e.protocol}//`)?e:void 0;if(!(be.has(e.protocol)||qe.has(e.protocol)))return e}}function X(r){const e=r||{},t=Object.keys(e),n=t.find(a=>P(e[a])&&se(e[a])),i=t.find(a=>P(e[a]));return n||i||t[0]}function Tr(r){return async e=>{if(!R(r))return s(e,{error:"not_found"},404);const t=new URL(e.req.url),{searchParams:n}=t,i=n.get("redirect_uri"),a=n.get("client_id"),c=n.get("code_challenge"),o=n.get("code_challenge_method"),d=ie();if(!i||!Z(i))return s(e,{error:"invalid_request",error_description:"redirect_uri must be an https URL, a loopback http URL, or a private-use scheme"},400);if(!c)return s(e,{error:"invalid_request",error_description:"code_challenge is required"},400);if(!$.has(o||""))return s(e,{error:"invalid_request",error_description:`Unsupported code_challenge_method. Supported: ${[...$].join(", ")}`},400);let p;if(z(a))try{const u=await Ie(a);p=u.client_name;const _=a===Ue;if(!we(i,u.redirect_uris,{ignorePort:_}))return s(e,{error:"invalid_request",error_description:"redirect_uri is not registered for this client"},400)}catch(u){const _=u instanceof Error?u.message:String(u);return s(e,{error:"invalid_client",error_description:`Unable to resolve client metadata document: ${_}`},400)}y.sendMcpAuthorizationStartedMessage([{...M(d),redirect_uri:i||null}]);const l=L(e),k={isMcpFlow:!0,originalRedirectUri:i,mcpClientId:a,mcpState:n.get("state"),mcpSessionId:d,mcpCodeChallenge:c,mcpCodeChallengeMethod:o,mcpClientName:p,timestamp:Date.now()};try{const u=await Ne(k),_=new URL(w(I.IDP_LOGIN),l);_.searchParams.set("redirectTo",`${I.MCP_CALLBACK}/${u}`);const h=X(r.getConfig().ssoDirect);return h?(_.searchParams.set("idpId",h),e.redirect(_.toString())):s(e,{error:"not_found"},404)}catch(u){const _=u instanceof Error?u.message:String(u),h=u instanceof Error?u.stack:String(u);y.sendMcpAuthorizationFailedMessage([{...M(d),error:_,error_details:h}]);const S=new URL(w(`${he}/oauth2/auth`));return S.search=n.toString(),e.redirect(S.toString())}}}async function Q(r){const e=Math.floor(Date.now()/1e3),t=r.ttlSec?e+r.ttlSec:Math.min(typeof r.claims.exp=="number"?r.claims.exp:1/0,e+b);return{accessToken:await C.sign({...r.claims,[U.CLAIM]:U.VALUE,...r.idpId?{idpId:r.idpId}:{},...r.idpAccessTokenEnc?{idp_access_token:r.idpAccessTokenEnc}:{},...r.ttlSec?{iat:e}:{},exp:t},m,A.HS256,r.kid),expiresIn:Math.max(t-e,0)}}async function $e(r,e,t){const n=T=>s(r,{error:"invalid_grant",error_description:T},400),i=r.get("logger"),a=t.get("refresh_token"),c=t.get("client_id")||void 0;if(!a)return s(r,{error:"invalid_request",error_description:"refresh_token is required"},400);let o;try{o=await de(a)}catch(T){return i?.warn("MCP refresh token rejected: %s",T instanceof Error?T.message:String(T)),n("Invalid refresh token")}if(c&&c!==o.client_id)return n("Client mismatch");const d=o.idp_id?e.getConfig().ssoDirect?.[o.idp_id]:void 0;let p,l,k=o.idp_access_token_enc,u=o.idp_refresh_token_enc;if(o.idp_refresh_token_enc){let T;try{T=Se(o.idp_refresh_token_enc,m)}catch{return n("Invalid refresh token")}if(!o.idp_id||!P(d))return n("Unknown identity provider");let f;try{const g=await ue(o.idp_id,d);if(!g?.token_endpoint)return n("Identity provider has no token endpoint");f=await pe(g.token_endpoint,T,d)}catch(g){return i?.warn("MCP refresh failed to reach the IdP token endpoint: %s",g instanceof Error?g.message:String(g)),s(r,{error:"server_error",error_description:"Failed to refresh session"},500)}if(f.error||!(f.id_token||f.access_token))return i?.warn("MCP refresh rejected by IdP: %s",f.error||"empty token response"),n("Refresh rejected by identity provider");if(f.refresh_token&&(u=V(f.refresh_token,m)),f.access_token&&(k=J(f.access_token,m)),f.id_token){try{const g=C.decode(f.id_token);p=g.payload,l=g.header.kid}catch{return n("Invalid token response from identity provider")}if(p.iss!==o.claims.iss||p.sub!==o.claims.sub)return i?.warn("MCP refresh rejected: the id_token names another issuer or subject"),n("Invalid refresh token")}}const _=Math.min(P(d)&&d.tokenExpirationTime||b,b),h=p??o.claims;if(!_e(h,d))return i?.warn("MCP refresh rejected: the id_token was issued for another project"),n("Invalid refresh token");if(j()&&!await ve(await e.getKv(),a,o.exp))return i?.warn("MCP refresh rejected: the refresh token was already used"),n("Refresh token already used");const S=await Q({claims:h,kid:l,idpId:o.idp_id,idpAccessTokenEnc:k,ttlSec:p?void 0:_}),D=await K({clientId:o.client_id,idpId:o.idp_id,claims:h,idpAccessTokenEnc:k,idpRefreshTokenEnc:u,sessionExp:o.session_exp});return s(r,{access_token:S.accessToken,token_type:"Bearer",expires_in:S.expiresIn,refresh_token:D,scope:E.join(" ")},200,{"Cache-Control":"no-store",Pragma:"no-cache"})}function kr(r){return async e=>{if(e.req.method!=="POST")return s(e,{error:"Method not allowed"},405);try{const t=await e.req.formData(),n=t.get("grant_type"),i=t.get("code"),a=t.get("redirect_uri")||void 0,c=t.get("code_verifier")||void 0;if(!F.includes(n))return s(e,{error:"invalid_request",error_description:"Invalid grant type"},400);if(n==="refresh_token")return await $e(e,r,t);if(!i)return s(e,{error:"invalid_request",error_description:"Missing authorization code"},400);try{const o=await ce(i);if(a&&a!==o.redirect_uri)return s(e,{error:"invalid_grant",error_description:"redirect_uri mismatch"},400);if(!c)return s(e,{error:"invalid_grant",error_description:"code_verifier required"},400);if(!Le(o.code_challenge,o.code_challenge_method,c))return s(e,{error:"invalid_grant",error_description:"code_verifier mismatch"},400);if(q.OAUTH_CLIENT_ID&&o.client_id&&!z(o.client_id)&&o.client_id!==q.OAUTH_CLIENT_ID)return s(e,{error:"invalid_client",error_description:"Client mismatch"},400);const d=o.id_token;if(typeof d!="string"||d.length===0)return s(e,{error:"invalid_grant",error_description:"Missing id_token in authorization code"},400);const p=await x(d,r.getConfig().ssoDirect);if(!p)return s(e,{error:"invalid_grant",error_description:"Invalid authorization code"},400);if(j()&&!await Re(await r.getKv(),i,o.exp))return s(e,{error:"invalid_grant",error_description:"Authorization code already used"},400);const l=o.idp_access_token_enc,{accessToken:k,expiresIn:u}=await Q({claims:p.payload,kid:p.kid,idpId:o.idp_id,idpAccessTokenEnc:l}),h=Math.floor(Date.now()/1e3)+B,S=await K({clientId:o.client_id,idpId:o.idp_id,claims:p.payload,idpAccessTokenEnc:l,idpRefreshTokenEnc:o.idp_refresh_token_enc,sessionExp:h}),D={access_token:k,token_type:"Bearer",expires_in:u,refresh_token:S,scope:E.join(" ")};return s(e,D,200,{"Cache-Control":"no-store",Pragma:"no-cache"})}catch(o){return e.get("logger")?.warn("MCP token exchange failed: %s",o instanceof Error?o.message:String(o)),s(e,{error:"invalid_grant",error_description:"Invalid authorization code"},400)}}catch(t){const n=t instanceof Error?t.message:String(t);return s(e,{error:"server_error",error_description:"Failed to process token request",error_details:n},500)}}}async function x(r,e){const t=await le(e||{},{[v.AUTHORIZATION]:r});if(t.isAuthenticated!==!0)return;const{payload:n,header:i}=C.decode(r);if(n[U.CLAIM]!==U.VALUE)return{payload:n,kid:i.kid,idpId:typeof t.idpId=="string"?t.idpId:void 0}}function N(r){return G("sha256").update(r).digest("base64url")}async function Fe(r){const e=Math.floor(Date.now()/1e3);return C.sign({type:O.MCP_CONSENT,session_hash:N(r.sessionToken),context_hash:N(r.contextToken),iat:e,exp:e+Me},m,A.HS256)}async function Ge(r,e){try{await C.verify(r,m,A.HS256)}catch{return!1}const{payload:t}=C.decode(r);return t.type===O.MCP_CONSENT&&t.session_hash===N(e.sessionToken)&&t.context_hash===N(e.contextToken)}function ee(r,e){return async t=>{const n=new URL(t.req.url);let i=n.searchParams.get("context");if(!i&&n.pathname.startsWith(w(`${I.MCP_CALLBACK}/`))){const c=n.pathname.split("/");i=c[c.length-1]}if(!i)return t.text("Missing context parameter",400);let a=null;try{const c=await De(i);a=c.mcpSessionId||null;const o=c.originalRedirectUri,d=Z(o);if(!c.isMcpFlow||!o||!d)throw new Error("Invalid MCP context");const p=H(t,v.AUTHORIZATION),l=p?await x(p,r.getConfig().ssoDirect):void 0;return!p||!l?(y.sendMcpAuthorizationFailedMessage([{...M(a),error:"Authentication required",error_details:null}]),t.text("Authentication required",401)):await e(t,{contextToken:i,mcpContext:c,redirectUri:o,redirectUrl:d,sessionToken:p,session:l})}catch(c){const o=Je(c);return y.sendMcpAuthorizationFailedMessage([{...M(a),...o}]),t.text(`Invalid MCP callback: ${o.error}`,400)}}}async function re(r,e,{mcpContext:t,redirectUri:n,redirectUrl:i,sessionToken:a,session:c}){const o=H(r,v.IDP_ACCESS_TOKEN),d=H(r,v.IDP_REFRESH_TOKEN),p=await ae({idToken:a,idpId:c.idpId??X(e.getConfig().ssoDirect),idpAccessTokenEnc:o?J(o,m):void 0,idpRefreshTokenEnc:d?V(d,m):void 0,clientId:t.mcpClientId||"",redirectUri:n,codeChallenge:t.mcpCodeChallenge||void 0,codeChallengeMethod:t.mcpCodeChallengeMethod||void 0,ttlSec:600}),l=new URL(i);return l.searchParams.set("code",p),t.mcpState&&l.searchParams.set("state",t.mcpState),y.sendMcpAuthorizationCompletedMessage([{...M(t.mcpSessionId||null),redirect_uri:n}]),r.redirect(l.toString())}function Ke(r,{mcpContext:e,redirectUrl:t}){const n=new URL(t);return n.searchParams.set("error","access_denied"),e.mcpState&&n.searchParams.set("state",e.mcpState),y.sendMcpAuthorizationFailedMessage([{...M(e.mcpSessionId||null),error:"access_denied",error_details:null}]),r.redirect(n.toString())}function Be({payload:r}){return[r.email,r.name,r.sub].find(e=>typeof e=="string"&&e.length>0)}function te({mcpContext:r,redirectUri:e,session:t}){const{sub:n}=t.payload;if(!(!j()||typeof n!="string"||n.length===0))return{idpId:t.idpId,subject:n,clientId:r.mcpClientId||"",redirectUri:e}}function ne(r,e){const{seo:t,colorMode:n}=e.getConfig(),{logo:i}=e.getGlobalData();return{...fe({seo:t,logo:i,colorMode:n}),host:new URL(L(r)).host}}function Sr(r){return ee(r,async(e,t)=>{const n=te(t);if(Y(t.redirectUrl)||n&&await Pe(await r.getKv(),n))return re(e,r,t);const{mcpClientId:i,mcpClientName:a}=t.mcpContext,c=ye({site:ne(e,r),user:Be(t.session),clientName:a||void 0,clientIdHost:z(i)?new URL(i).host:void 0,redirectUrl:t.redirectUrl,scopes:E,accessLifetimeHours:B/3600,rememberDays:n?Ae:void 0,consentToken:await Fe(t)});return new Response(c,{status:200,headers:W})})}function Ir(r){return ee(r,async(e,t)=>{const n=await e.req.formData(),i=n.get("consent");if(typeof i!="string"||!await Ge(i,t))return new Response(Ee(ne(e,r)),{status:403,headers:W});if(n.get("decision")==="allow"){const a=te(t);return a&&await Oe(await r.getKv(),a),re(e,r,t)}return Ke(e,t)})}function Je(r){return r instanceof Error&&[me,ge,Ce,Te,ke].some(e=>r instanceof e)?{error:r.name,error_details:null}:r instanceof Error?{error:r.message,error_details:r.stack??null}:{error:String(r),error_details:null}}export{F as SUPPORTED_MCP_GRANT_TYPES,Ne as createMcpContextToken,Tr as mcpAuthorizationHandler,Sr as mcpCallbackHandler,Ir as mcpConsentHandler,Cr as mcpDynamicClientRegistrationHandler,gr as mcpOAuthAuthorizationServerHandler,mr as mcpOAuthProtectedResourceHandler,kr as mcpTokenPortalHandler,X as resolveMcpIdpId,De as verifyAndParseMcpContextToken,Le as verifyPkce};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{corsMiddleware as o}from"../../middleware/corsMiddleware.js";import{ServerRoutes as
|
|
1
|
+
import{corsMiddleware as o}from"../../middleware/corsMiddleware.js";import{ServerRoutes as t}from"../../../../constants/api.js";import{EntitlementsProvider as A}from"../../../entitlements/entitlements-provider.js";import{withPathPrefix as e}from"@redocly/theme/core/utils";import{AGENT_CARD_SLUG as d,A2A_SLUG as i,MCP_SERVER_CARD_SLUG as l}from"../../../../constants/common.js";import{mcpOAuthProtectedResourceHandler as _,mcpOAuthAuthorizationServerHandler as r,mcpDynamicClientRegistrationHandler as M,mcpAuthorizationHandler as P,mcpTokenPortalHandler as R,mcpCallbackHandler as p,mcpConsentHandler as c}from"./mcp-oauth.js";import{mcpServerCardHandler as s}from"./mcp-server-card.js";import{mcpFetchCountAuth as T,mcpFetchCountHandler as f}from"./mcp-fetch-count.js";import{jsonValidatorMiddleware as E}from"../../middleware/jsonValidatorMiddleware.js";import{mcpFetchCountRequestSchema as H}from"../../../../api-schemas/mcp-fetch-count.js";import{agentCardHandler as h}from"./agent-card.js";import{a2aHandler as O}from"./a2a.js";function $(m,n){const a=n.getConfig().mcp,C=A.instance().canAccessFeature("mcp");!a?.hide&&!a?.docs?.hide&&C&&(m.get(e(l),s(n)),m.get(e(d),h(n)),m.use(e(i),o({allowMethods:["POST"],exposeHeaders:["Link"]})),m.post(e(i),O(n)),m.get(`${t.MCP_OAUTH_PROTECTED_RESOURCE}${e("/mcp")}`,_(n)),m.get(t.MCP_OAUTH_AUTHORIZATION_SERVER,r(n)),m.post(e(t.MCP_DYNAMIC_CLIENT_REGISTRATION),M(n)),m.get(e(t.MCP_AUTHORIZATION),P(n)),m.post(e(t.MCP_TOKEN_PORTAL),R(n)),m.get(e(t.MCP_CALLBACK),p(n)),m.get(e(`${t.MCP_CALLBACK}/*`),p(n)),m.post(e(t.MCP_CALLBACK),c(n)),m.post(e(`${t.MCP_CALLBACK}/*`),c(n)),m.post(e(t.MCP_FETCH_COUNT),T(),E(H),f(n)))}export{$ as installMcpRoutes};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{combineUrls as b,withPathPrefix as u}from"@redocly/theme/core/utils";import{DEFAULT_DOCS_MCP_SERVER_NAME as S,MCP_PROTOCOL_VERSION as T}from"../../../plugins/mcp/constants.js";import{RESERVED_ROUTES as g}from"../../../plugins/get-reserved-routes.js";import{isMcpCodeModeEnabled as v}from"../../../plugins/mcp/utils/mode.js";import{CODE_MODE_TOOL_NAMES as M,FETCH_TOOL_NAME as O}from"../../../plugins/mcp/codemode/constants.js";import{EXECUTE_TOOL_SCHEMA as R}from"../../../plugins/mcp/codemode/tools/execute-schema.js";import{describeToolsSchema as L}from"../../../plugins/mcp/codemode/tools/describe-tools.js";import{normalizeToolDisplayName as y}from"../../../plugins/mcp/utils/tool-registration.js";import{buildCodeModeInstructions as D,buildExecuteDescription as I}from"../../../plugins/mcp/codemode/prompts.js";import{toToolListEntries as P}from"../../../plugins/mcp/codemode/build-tool-list.js";import{composeExecuteAnnotations as U}from"../../../plugins/mcp/codemode/capabilities/index.js";import{ALL_CAPABILITIES as V}from"../../../plugins/mcp/codemode/capabilities/registry.js";import{isGatewayCapabilityEnabled as H}from"../../../plugins/mcp/gateway-mcp/eligibility.js";import{shouldHandleMcpAuth as x}from"../../../utils/rbac/should-handle-mcp-auth.js";import{resolvePublicBaseUrl as N}from"../../../web-server/utils/resolve-public-base-url.js";import{telemetryTraceStep as w}from"../../../telemetry/helpers/trace-step.js";import{MCP_AUTH_SCHEMES as j}from"./constants.js";const k="https://static.modelcontextprotocol.io/schemas/mcp-server-card/v1.json",q="1.0";function ne(r){const n=v(),C=new Date().toISOString().slice(0,10);return async m=>await w("com.redocly.mcpServerCard.served",async
|
|
1
|
+
import{combineUrls as b,withPathPrefix as u}from"@redocly/theme/core/utils";import{DEFAULT_DOCS_MCP_SERVER_NAME as S,MCP_PROTOCOL_VERSION as T}from"../../../plugins/mcp/constants.js";import{RESERVED_ROUTES as g}from"../../../plugins/get-reserved-routes.js";import{isMcpCodeModeEnabled as v}from"../../../plugins/mcp/utils/mode.js";import{CODE_MODE_TOOL_NAMES as M,FETCH_TOOL_NAME as O}from"../../../plugins/mcp/codemode/constants.js";import{EXECUTE_TOOL_SCHEMA as R}from"../../../plugins/mcp/codemode/tools/execute-schema.js";import{describeToolsSchema as L}from"../../../plugins/mcp/codemode/tools/describe-tools.js";import{normalizeToolDisplayName as y}from"../../../plugins/mcp/utils/tool-registration.js";import{buildCodeModeInstructions as D,buildExecuteDescription as I}from"../../../plugins/mcp/codemode/prompts.js";import{toToolListEntries as P}from"../../../plugins/mcp/codemode/build-tool-list.js";import{composeExecuteAnnotations as U}from"../../../plugins/mcp/codemode/capabilities/index.js";import{ALL_CAPABILITIES as V}from"../../../plugins/mcp/codemode/capabilities/registry.js";import{isGatewayCapabilityEnabled as H}from"../../../plugins/mcp/gateway-mcp/eligibility.js";import{shouldHandleMcpAuth as x}from"../../../utils/rbac/should-handle-mcp-auth.js";import{resolvePublicBaseUrl as N}from"../../../web-server/utils/resolve-public-base-url.js";import{telemetryTraceStep as w}from"../../../telemetry/helpers/trace-step.js";import{MCP_AUTH_SCHEMES as j}from"./constants.js";const k="https://static.modelcontextprotocol.io/schemas/mcp-server-card/v1.json",q="1.0";function ne(r){const n=v(),C=new Date().toISOString().slice(0,10);return async m=>await w("com.redocly.mcpServerCard.served",async o=>{o?.setAttribute("id","mcpServerCardId"),o?.setAttribute("object","mcpServerCard"),o?.setAttribute("uri","urn:redocly:realm:api:mcpServerCard:mcpServerCardId");const e=r.getConfig(),a=e.mcp?.docs?.name||S,i=r.getMcpTools().filter(t=>!M.has(t.name)&&!t.hasAvailabilityGate),s=H(e.mcp)?[...V]:[],l=s.some(t=>t.id===O),d=P(i,s),c=(n?[{...R,description:I(l,d),annotations:U(i,s,e.mcp)},L(i,s)]:i).map(y).map(({name:t,title:f,description:h,schema:_,annotations:A})=>({name:t,title:f,description:h,inputSchema:_,annotations:A})),E=e.skills?.hide===!0?[]:r.getSkills(),p={$schema:k,version:q,protocolVersion:T,serverInfo:{name:a,title:a,version:C},description:e.seo?.description,documentationUrl:b(N(r,m),u("/")),transport:{type:"streamable-http",endpoint:u(g.mcp)},capabilities:{logging:{},tools:{listChanged:!0},...E.length>0?{resources:{listChanged:!0},completions:{}}:{}},authentication:x(!!e.access?.requiresLogin,e.access?.rbac)?{required:!0,schemes:j}:void 0,instructions:n?D(l,d):void 0,tools:c.length>0?c:["dynamic"]};return o?.setAttribute("mode",n?"code":"tools"),o?.setAttribute("toolsCount",c.length),o?.setAttribute("authRequired",p.authentication!==void 0),m.json(p,200,{"Access-Control-Allow-Origin":"*","Cache-Control":"public, max-age=3600"})})}export{ne as mcpServerCardHandler};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{Source as P}from"@redocly/openapi-core";import y from"node:fs/promises";import S from"node:path";import{withPathPrefix as j,getPathPrefix as h,combineUrls as w}from"@redocly/theme/core/utils";import{API_DOCS_SHARED_DATA_PREFIX as d}from"../../constants/plugins/api-docs.js";import{CATALOG_BASE_SLUG as b,CATALOG_SLUGS as $}from"../../../constants/catalog-entities.js";import{CATALOG_ENTITIES_FILES_REGEX as I}from"../../constants/plugins/catalog-entities.js";import{removeTrailingSlash as E}from"../../../utils/url/remove-trailing-slash.js";import{normalizeRouteSlug as N}from"../../../utils/path/normalize-route-slug.js";import{promiseMapLimit as T}from"../../utils/async/promise-map-limit.js";import{getRoutesByLines as L,getPointerPosition as U}from"../../plugins/api-docs/utils/ast-utils.js";import{readSharedData as m}from"../../utils/index.js";const q=new Set(["openapi","asyncapi"]);function K(n){return async t=>{const i=await t.req.json(),r=decodeURI(E(i.split("?")[0])),[o]=r.split("#"),g=h(),f=N(o.slice(g.length)),u=f.startsWith(b)?b:f,e=n.getRouteBySlug(u);if(e){const p=n.getRouteByFsPath(e.fsPath);if(p?.metadata?.type&&q.has(p.metadata.type)){const a=await m(`${d}${e.fsPath}`,n.outdir);if(!a?.routesMapping)return t.json({route:e},200);const s=Object.keys(a.routesMapping).find(c=>w(e.baseSlug,a.routesMapping[c])===r);if(!a.sourcePath)return t.json({route:e},200);let l;if(s){const c=S.join(n.contentDir,e.fsPath),R=await y.readFile(c,"utf-8"),_=new P(c,R);l=U(s,_)}return t.json({route:{fsPath:e.fsPath,pointer:s,position:l}},200)}if(p?.metadata?.type==="graphql"){const a=await m(`${d}${e.fsPath}`,n.outdir);if(!a?.graphqlPositions)return t.json({route:e},200);const s=Object.keys(a.graphqlPositions).find(c=>w(e.baseSlug,c)===r),l=s?a.graphqlPositions[s].position:void 0;return t.json({route:{fsPath:e.fsPath,position:l}},200)}}return t.json({route:e},200)}}function X(n){return async t=>{const i=await t.req.json(),r=await T(i,5,async o=>A(o,n));return t.json({routes:r},200)}}function Y(n){return async t=>{const i=await t.req.json(),r=await A(i,n);return t.json(r,200)}}function J(n){return async t=>{const i=(t.req.query("lines")||"").split(",").map(f=>parseInt(f)),r=t.req.query("file");if(!r)return t.json("No data",400);const o=await m(`${d}${r}`,n.outdir),g=S.join(n.contentDir,r);try{const f=await y.readFile(g,"utf-8");if(!o)return t.json("No data",400);const u=new P(g,f),e=L(i,u,o.routesMapping,o.baseSlug);return t.json(e,200)}catch{return t.json("No data",400)}}}async function A(n,t){const[i,r]=n.split(":");if(I.test(i))return{route:{slug:`${b}/${$.ALL}`}};
|
|
1
|
+
import{Source as P}from"@redocly/openapi-core";import y from"node:fs/promises";import S from"node:path";import{withPathPrefix as j,getPathPrefix as h,combineUrls as w}from"@redocly/theme/core/utils";import{API_DOCS_SHARED_DATA_PREFIX as d}from"../../constants/plugins/api-docs.js";import{CATALOG_BASE_SLUG as b,CATALOG_SLUGS as $}from"../../../constants/catalog-entities.js";import{CATALOG_ENTITIES_FILES_REGEX as I}from"../../constants/plugins/catalog-entities.js";import{removeTrailingSlash as E}from"../../../utils/url/remove-trailing-slash.js";import{normalizeRouteSlug as N}from"../../../utils/path/normalize-route-slug.js";import{promiseMapLimit as T}from"../../utils/async/promise-map-limit.js";import{getRoutesByLines as L,getPointerPosition as U}from"../../plugins/api-docs/utils/ast-utils.js";import{readSharedData as m}from"../../utils/index.js";const q=new Set(["openapi","asyncapi"]);function K(n){return async t=>{const i=await t.req.json(),r=decodeURI(E(i.split("?")[0])),[o]=r.split("#"),g=h(),f=N(o.slice(g.length)),u=f.startsWith(b)?b:f,e=n.getRouteBySlug(u);if(e){const p=n.getRouteByFsPath(e.fsPath);if(p?.metadata?.type&&q.has(p.metadata.type)){const a=await m(`${d}${e.fsPath}`,n.outdir);if(!a?.routesMapping)return t.json({route:e},200);const s=Object.keys(a.routesMapping).find(c=>w(e.baseSlug,a.routesMapping[c])===r);if(!a.sourcePath)return t.json({route:e},200);let l;if(s){const c=S.join(n.contentDir,e.fsPath),R=await y.readFile(c,"utf-8"),_=new P(c,R);l=U(s,_)}return t.json({route:{fsPath:e.fsPath,pointer:s,position:l}},200)}if(p?.metadata?.type==="graphql"){const a=await m(`${d}${e.fsPath}`,n.outdir);if(!a?.graphqlPositions)return t.json({route:e},200);const s=Object.keys(a.graphqlPositions).find(c=>w(e.baseSlug,c)===r),l=s?a.graphqlPositions[s].position:void 0;return t.json({route:{fsPath:e.fsPath,position:l}},200)}}return t.json({route:e},200)}}function X(n){return async t=>{const i=await t.req.json(),r=await T(i,5,async o=>A(o,n));return t.json({routes:r},200)}}function Y(n){return async t=>{const i=await t.req.json(),r=await A(i,n);return t.json(r,200)}}function J(n){return async t=>{const i=(t.req.query("lines")||"").split(",").map(f=>parseInt(f)),r=t.req.query("file");if(!r)return t.json("No data",400);const o=await m(`${d}${r}`,n.outdir),g=S.join(n.contentDir,r);try{const f=await y.readFile(g,"utf-8");if(!o)return t.json("No data",400);const u=new P(g,f),e=L(i,u,o.routesMapping,o.baseSlug);return t.json(e,200)}catch{return t.json("No data",400)}}}async function A(n,t){const[i,r]=n.split(":");if(I.test(i))return{route:{slug:`${b}/${$.ALL}`}};const o=t.getRouteByFsPath(i);if(o?.metadata?.type&&q.has(o.metadata.type)){const u=await m(`${d}${i}`,t.outdir);if(u?.sourcePath){const e=S.join(t.contentDir,o.fsPath),p=await y.readFile(e,"utf-8"),a=new P(e,p),s=L([parseInt(r,10)],a,u.routesMapping,o.baseSlug);if(s.length)return{route:{slug:h()?j(s[0]):s[0],filePath:n}}}}if(o?.metadata?.type==="graphql"){const u=await m(`${d}${i}`,t.outdir),e=parseInt(r,10);if(u?.sourcePath&&u.graphqlPositions&&!Number.isNaN(e)){let p,a=1/0;for(const[s,{startLine:l,endLine:c}]of Object.entries(u.graphqlPositions))l<=e&&e<=c&&c-l<a&&(a=c-l,p=s);if(p){const s=w(o.baseSlug,p);return{route:{slug:h()?j(s):s,filePath:n}}}}}const g=o?.slug?h()?j(o?.slug):o?.slug:"";return{route:{...o,pageName:o?await o?.getNavText?.():"",slug:g,filePath:n}}}export{J as getRoutesByLineHandler,Y as resolvePathHandler,X as resolvePathsHandler,K as resolveSlugHandler};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import
|
|
1
|
+
import a from"workerpool";import{mkdirSync as m}from"node:fs";import{basename as u,dirname as l,resolve as p}from"node:path";import{fileURLToPath as f}from"node:url";import{envConfig as c}from"../config/env-config.js";import{SandboxContext as v}from"../utils/sandbox-context.js";const h=(()=>{const o=l(f(import.meta.url));return u(o)==="chunks"?l(o):o})();class b{#t=null;#r;constructor(r){this.#r=r,this.#r.lazy||(this.#t=this.#e())}#e(){const{workerScript:r,lazy:t,sandbox:i,resolveForkEnv:s,...e}=this.#r,n=this.#s(r);return s&&e.forkOpts&&(e.forkOpts={...e.forkOpts,env:s()}),this.#o(i)?a.pool(n,{...e,forkOpts:this.#i(e.forkOpts)}):a.pool(n,{...e})}#o(r){return!!r&&c.isReunite}#i(r){const t=v.resolve(h);try{m(t.tmpDir,{recursive:!0})}catch{}return{...r,cwd:t.serverOutDir,execArgv:[...t.execArgv,...r?.execArgv??[]],env:{...r?.env,...t.env}}}#s(r){let t=r;return!t.endsWith(".js")&&!t.endsWith(".mjs")&&(t=`${t}.${c.isDevelopMode?"js":"mjs"}`),t.startsWith(".")?p(h,t):t}#n(){return this.#t||(this.#t=this.#e()),this.#t}async exec(r,t,i){let e=this.#n().exec(r,t);return i?.timeout&&(e=e.timeout(i.timeout)),await e}async terminate(){this.#t&&(await this.#t.terminate(),this.#t=null)}}export{b as WorkerPool,h as workerBaseDir};
|
|
@@ -40,6 +40,8 @@ export type PlanGates = {
|
|
|
40
40
|
[FEATURE.gatewayFetchRatePerMin]: number;
|
|
41
41
|
[FEATURE.gatewayFetchQuotaPerDay]: number;
|
|
42
42
|
[FEATURE.gatewayFetchBudgetPerExec]: number;
|
|
43
|
+
[FEATURE.mcpRequestRatePerMin]: number;
|
|
44
|
+
[FEATURE.mcpRequestQuotaPerDay]: number;
|
|
43
45
|
[FEATURE.cookieConsent]: boolean;
|
|
44
46
|
};
|
|
45
47
|
export type Entitlements = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
function c(e,i=50,
|
|
1
|
+
function c(e,i=50,o=!1){let t;return function(...n){const l=()=>{t=void 0,o||e.apply(this,n)},u=o&&!t;clearTimeout(t),t=setTimeout(l,i),u&&e.apply(this,n)}}export{c as debounce};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@redocly/revel",
|
|
3
|
-
"version": "0.138.
|
|
3
|
+
"version": "0.138.1",
|
|
4
4
|
"description": "",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -33,13 +33,13 @@
|
|
|
33
33
|
"@opentelemetry/sdk-trace-web": "2.8.0",
|
|
34
34
|
"@opentelemetry/semantic-conventions": "1.40.0",
|
|
35
35
|
"@redocly/ajv": "8.18.0",
|
|
36
|
-
"@redocly/api-docs": "0.3.
|
|
37
|
-
"@redocly/config": "0.
|
|
38
|
-
"@redocly/openapi-core": "2.
|
|
36
|
+
"@redocly/api-docs": "0.3.1",
|
|
37
|
+
"@redocly/config": "0.65.0",
|
|
38
|
+
"@redocly/openapi-core": "2.62.1",
|
|
39
39
|
"@redocly/portal-legacy-ui": "0.19.0",
|
|
40
|
-
"@redocly/portal-plugin-mock-server": "0.23.0
|
|
41
|
-
"@redocly/realm-asyncapi-sdk": "0.16.0
|
|
42
|
-
"@redocly/theme": "0.70.
|
|
40
|
+
"@redocly/portal-plugin-mock-server": "0.23.0",
|
|
41
|
+
"@redocly/realm-asyncapi-sdk": "0.16.0",
|
|
42
|
+
"@redocly/theme": "0.70.1",
|
|
43
43
|
"@shikijs/transformers": "3.21.0",
|
|
44
44
|
"@tanstack/react-query": "5.62.3",
|
|
45
45
|
"@tanstack/react-table": "8.21.3",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"ajv-formats": "^3.0.1",
|
|
51
51
|
"anser": "^2.3.2",
|
|
52
52
|
"babel-plugin-styled-components": "2.1.4",
|
|
53
|
-
"chokidar": "3.6.0",
|
|
53
|
+
"chokidar": "npm:@redocly/chokidar@3.6.0",
|
|
54
54
|
"colorette": "2.0.20",
|
|
55
55
|
"copy-to-clipboard": "3.3.3",
|
|
56
56
|
"dotenv": "16.4.5",
|
|
@@ -70,7 +70,6 @@
|
|
|
70
70
|
"minimatch": "10.2.4",
|
|
71
71
|
"mri": "1.2.0",
|
|
72
72
|
"nanoid": "5.1.16",
|
|
73
|
-
"nprogress": "0.2.0",
|
|
74
73
|
"openapi-sampler": "^1.7.6",
|
|
75
74
|
"os-browserify": "0.3.0",
|
|
76
75
|
"path-browserify": "1.0.1",
|
|
@@ -85,7 +84,7 @@
|
|
|
85
84
|
"reactjs-popup": "2.0.6",
|
|
86
85
|
"semver": "7.7.3",
|
|
87
86
|
"shiki": "3.21.0",
|
|
88
|
-
"simple-git": "
|
|
87
|
+
"simple-git": "4.0.2",
|
|
89
88
|
"sitemap": "7.1.1",
|
|
90
89
|
"stream-http": "3.2.0",
|
|
91
90
|
"styled-components": "^6.4.2",
|
|
@@ -114,7 +113,7 @@
|
|
|
114
113
|
"clean": "rimraf \"dist\"",
|
|
115
114
|
"compile": "tsgo --build tsconfig.json && tsc-alias -p tsconfig.json",
|
|
116
115
|
"build": "npm run clean && npm run compile && npm run post-build && npm run build:minify",
|
|
117
|
-
"post-build": "cross-env PACKAGE=revel node --
|
|
116
|
+
"post-build": "cross-env PACKAGE=revel node --import tsx ../../scripts/post-build.ts",
|
|
118
117
|
"build:minify": "esbuild-minify-dir \"dist\""
|
|
119
118
|
}
|
|
120
119
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import e from"nprogress";e.configure({trickleSpeed:100,template:'<div class="bar" role="bar"><div class="peg"></div></div>'});let l;async function i(o){const r=Symbol();return l=r,e.done(),e.start(),o.finally(()=>{l===r&&(e.done(),e.remove())})}export{i as withLoadProgress};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{envConfig as o}from"../../../../config/env-config.js";import{KvRepository as s}from"../../../../persistence/kv/repositories/kv-repository.js";import{logger as m}from"../../../../tools/notifiers/logger.js";import{ipRateLimitKey as p}from"./ip-key.js";import{checkEdgeRateLimit as c}from"./edge-limiter.js";import{resolveGatewayFetchLimits as d}from"./limits.js";import{reportMcpRateLimited as f}from"./rate-limit-telemetry.js";async function S(n,a){const i=p(n);if(!i)return;let e,t;try{const r=await s.create({baseDbDir:a.serverOutDir,sqldRemoteDatabaseUrl:o.SQLD_REMOTE_DATABASE_URL,sqldRemoteDatabaseAuthToken:o.SQLD_REMOTE_DATABASE_AUTH_TOKEN});t=d(),e=await c({kv:r,ip:i,limits:t,now:Date.now()})}catch(r){m.warn(`gateway rate-limit init error, failing open: ${String(r)}`);return}if(!e.allowed)return f({scope:e.scope,retryAfterSeconds:e.retryAfterSeconds,limit:e.scope==="rate"?t.ratePerMin:t.quotaPerDay}),new Response(JSON.stringify({jsonrpc:"2.0",error:{code:-32029,message:`Rate limit exceeded (${e.scope}); retry after ${e.retryAfterSeconds}s`},id:null}),{status:429,headers:{"Content-Type":"application/json","Retry-After":String(e.retryAfterSeconds)}})}export{S as applyEdgeRateLimit};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{checkAndIncrement as c}from"./window-counter.js";const s=60,d=86400;async function w(i){const{kv:e,ip:t,limits:o,now:r}=i;await e.sync();const n=await c({kv:e,ip:t,windowSeconds:s,limit:o.ratePerMin,now:r});if(!n.allowed)return{allowed:!1,retryAfterSeconds:n.retryAfterSeconds,scope:"rate"};const a=await c({kv:e,ip:t,windowSeconds:d,limit:o.quotaPerDay,now:r});return a.allowed?{allowed:!0}:{allowed:!1,retryAfterSeconds:a.retryAfterSeconds,scope:"quota"}}export{w as checkEdgeRateLimit};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{isIP as l}from"node:net";import{getFeedbackClientIp as a}from"../../../../web-server/utils/feedback-ip.js";import{extractMappedIpv4 as c}from"../../../../web-server/utils/ssrf-blocklist.js";function I(t){const n=a(t);if(n)return f(n)}function f(t){if(l(t)===6){const n=c(t);return n||`${u(t)}::/64`}return t}function u(t){const n=t.split("%")[0],[e,i=""]=n.split("::"),r=e?e.split(":"):[],o=i?i.split(":"):[],s=8-r.length-o.length;return[...r,...Array(Math.max(0,s)).fill("0"),...o].slice(0,4).map(p=>parseInt(p||"0",16).toString(16)).join(":")}export{I as ipRateLimitKey};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{EntitlementsProvider as u}from"../../../../entitlements/entitlements-provider.js";import{FEATURE as r,GATEWAY_FETCH_LIMIT_DEFAULTS as a}from"../../../../../constants/common.js";function n(e,i,o){const t=e.entitlements?.[i];return typeof t=="number"&&Number.isFinite(t)?t:o}function P(){const e=u.instance();return{ratePerMin:n(e,r.gatewayFetchRatePerMin,a.ratePerMin),quotaPerDay:n(e,r.gatewayFetchQuotaPerDay,a.quotaPerDay),budgetPerExec:n(e,r.gatewayFetchBudgetPerExec,a.budgetPerExec)}}export{P as resolveGatewayFetchLimits};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{telemetry as o}from"../../../../telemetry/index.js";import{logger as i}from"../../../../tools/notifiers/logger.js";import{McpServerType as m}from"../../constants.js";import{serverAttributes as p}from"../../utils/telemetry-attributes.js";function d({scope:e,retryAfterSeconds:r,limit:t}){try{o.sendMcpRateLimitedMessage([{...p(m.Docs),scope:e,retry_after_seconds:r,limit:t}])}catch{}i.warn(`Gateway MCP rate limited [scope=${e}] retryAfterSeconds=${r} limit=${t}`)}export{d as reportMcpRateLimited};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{logger as g}from"../../../../tools/notifiers/logger.js";function u(e,t,o){return["mcp","gateway-fetch-rl",e,String(t),String(o)]}async function S(e){const{kv:t,ip:o,windowSeconds:n,limit:w,now:l}=e,r=Math.floor(l/1e3),c=Math.floor(r/n),i=u(o,n,c);try{const s=(await t.get(i))?.count??0;if(s>=w){const d=(c+1)*n-r;return{allowed:!1,retryAfterSeconds:Math.max(1,d)}}return await t.set(i,{count:s+1},{ttlInSeconds:n}),{allowed:!0}}catch(a){return g.warn(`gateway rate-limit store error, failing open: ${String(a)}`),{allowed:!0}}}export{S as checkAndIncrement};
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import type { ElicitationTarget } from '../gateway-mcp/secret-store.js';
|
|
2
|
-
export declare function formPage(target: ElicitationTarget, token: string, error?: string): string;
|
|
3
|
-
export declare function clearedPage(target: ElicitationTarget): string;
|
|
4
|
-
export type MultiOutcome = {
|
|
5
|
-
saved: readonly string[];
|
|
6
|
-
removed: readonly string[];
|
|
7
|
-
stored: readonly string[];
|
|
8
|
-
};
|
|
9
|
-
export declare function multiOutcomePage(target: ElicitationTarget, outcome: MultiOutcome): string;
|
|
10
|
-
export declare function successPage(target: ElicitationTarget): string;
|
|
11
|
-
export declare function notFoundPage(): string;
|
|
12
|
-
//# sourceMappingURL=mcp-credentials-page.d.ts.map
|