@redocly/realm 0.140.0-next.1 → 0.140.0-next.10
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 +416 -204
- package/dist/api-schemas/mcp-fetch-count.d.ts +2 -18
- package/dist/api-schemas/otel-traces.d.ts +7 -1345
- package/dist/api-schemas/otel-traces.js +1 -1
- package/dist/api-schemas/search-facets.d.ts +3 -31
- package/dist/api-schemas/search.d.ts +6 -52
- package/dist/cli/build/index.js +1 -1
- package/dist/cli/eject/resolveEjectParams.js +1 -1
- package/dist/cli/generate/get-schema-template.js +1 -1
- package/dist/client/app/hooks/markdown/useMarkdocRenderer.js +1 -1
- package/dist/client/app/hooks/markdown/useMarkdownText.js +1 -1
- package/dist/client/app/markdoc/custom-components/openapi/openapi-code-sample.d.ts +2 -0
- package/dist/client/app/markdoc/custom-components/openapi/openapi-code-sample.js +1 -1
- package/dist/client/app/markdoc/custom-components/openapi/use-markdown-adapter.d.ts +1 -33
- package/dist/client/app/useGlobalData.d.ts +1 -1
- package/dist/client/providers/post-message/use-post-message.d.ts +1 -1
- package/dist/compiled/@redocly/pii/index.mjs +1 -0
- package/dist/compiled/@redocly/pii/package.json +1 -0
- package/dist/compiled/svgo/svgo-node.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/attributes/definition-path.d.ts +1 -1
- package/dist/markdoc/attributes/json-example-ref.d.ts +1 -1
- package/dist/markdoc/attributes/json-schema-ref.d.ts +1 -1
- package/dist/markdoc/attributes/parsed-yaml.d.ts +1 -1
- package/dist/markdoc/attributes/raw-content.d.ts +1 -1
- package/dist/markdoc/attributes/sample-from-json-schema.d.ts +1 -1
- package/dist/markdoc/helpers/extract-rbac-from-condition-node.d.ts +1 -1
- package/dist/markdoc/helpers/get-inner-text.d.ts +1 -1
- package/dist/markdoc/helpers/get-node-attribute.d.ts +1 -1
- package/dist/markdoc/helpers/get-variable.d.ts +1 -1
- package/dist/markdoc/helpers/guards/is-conditional-node.d.ts +1 -1
- package/dist/markdoc/helpers/guards/is-function.d.ts +1 -1
- package/dist/markdoc/helpers/guards/is-node.d.ts +1 -1
- package/dist/markdoc/helpers/guards/is-prompt-node.d.ts +1 -1
- package/dist/markdoc/helpers/guards/is-tag.d.ts +1 -1
- package/dist/markdoc/helpers/guards/is-variable.d.ts +1 -1
- package/dist/markdoc/helpers/parse-partials.d.ts +1 -1
- package/dist/markdoc/helpers/parse-partials.js +1 -1
- package/dist/markdoc/helpers/remove-markdoc-tags.js +1 -1
- package/dist/markdoc/helpers/set-node-attribute-value.d.ts +1 -1
- package/dist/markdoc/nodes/fence/index.d.ts +1 -1
- package/dist/markdoc/nodes/fence/index.js +1 -1
- package/dist/markdoc/nodes/gfm-list-item.d.ts +1 -1
- package/dist/markdoc/nodes/gfm-list-item.js +1 -1
- package/dist/markdoc/nodes/heading.d.ts +1 -1
- package/dist/markdoc/nodes/heading.js +1 -1
- package/dist/markdoc/nodes/index.d.ts +6 -165
- package/dist/markdoc/nodes/index.js +1 -1
- package/dist/markdoc/nodes/table.d.ts +1 -1
- package/dist/markdoc/nodes/table.js +1 -1
- package/dist/markdoc/nodes/text.d.ts +1 -1
- package/dist/markdoc/tags/json-example.js +1 -1
- package/dist/markdoc/tags/openapi-code-sample.js +1 -1
- package/dist/server/api-routes/execute-api-route.js +1 -1
- package/dist/server/api-routes/run-api-routes-worker.js +1 -1
- package/dist/server/config/env-config.d.ts +26 -24
- package/dist/server/config/env-schema.d.ts +87 -326
- package/dist/server/config/env-schemas/api-urls.d.ts +2 -14
- package/dist/server/config/env-schemas/auth.d.ts +10 -32
- package/dist/server/config/env-schemas/catalog.d.ts +6 -9
- package/dist/server/config/env-schemas/database.d.ts +2 -8
- package/dist/server/config/env-schemas/environment-detection.d.ts +20 -18
- package/dist/server/config/env-schemas/feature-flags.d.ts +29 -33
- package/dist/server/config/env-schemas/feature-flags.js +1 -1
- package/dist/server/config/env-schemas/organization-project.d.ts +3 -21
- package/dist/server/config/env-schemas/scorecards.d.ts +2 -6
- package/dist/server/config/env-schemas/search.d.ts +9 -15
- package/dist/server/config/env-schemas/server-config.d.ts +6 -31
- package/dist/server/config/env-schemas/site.d.ts +1 -5
- package/dist/server/config/env-schemas/ssr.d.ts +7 -12
- package/dist/server/config/env-schemas/telemetry.d.ts +1 -7
- package/dist/server/constants/common.d.ts +3 -0
- package/dist/server/constants/common.js +1 -1
- package/dist/server/esbuild/plugins/dependency-resolver.js +1 -1
- package/dist/server/esbuild/plugins/themes-resolver.js +3 -3
- package/dist/server/external-plugins/resolve-external-plugins.js +1 -1
- package/dist/server/node-bundle-entry.js +1 -1
- package/dist/server/plugins/api-docs/definition-access.d.ts +22 -0
- package/dist/server/plugins/api-docs/definition-access.js +1 -0
- package/dist/server/plugins/api-docs/index.js +1 -1
- package/dist/server/plugins/api-docs/loader.d.ts +1 -1
- package/dist/server/plugins/api-docs/options.js +1 -1
- package/dist/server/plugins/api-docs/spec-download.api.js +1 -1
- package/dist/server/plugins/config-parser/index.js +1 -1
- package/dist/server/plugins/config-parser/loaders/utils/read-and-validate-config.js +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/code-walkthrough/filesets-resolver.d.ts +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/helpers/load-openapi-bundle.d.ts +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/index.d.ts +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-code-snippet-from-file.d.ts +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-diagram-from-file.d.ts +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-html-href.d.ts +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-html-source-attribute.d.ts +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-image-gallery.d.ts +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-image-src-set.d.ts +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-image-src.d.ts +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-json-example-ref.d.ts +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-json-schema-ref.d.ts +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-link.d.ts +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-native-md-link.d.ts +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-nav-links.d.ts +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-open-api-ref.d.ts +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-openapi-code-samples.d.ts +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-openapi-code-samples.js +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-openapi-response-samples.d.ts +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-parsed-yaml.d.ts +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-raw-content.d.ts +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-relative-or-cdn-icon.d.ts +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-relative-path.d.ts +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-sample-from-json-schema.d.ts +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-svg-content.d.ts +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-tag-raw-content.d.ts +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-tag-raw-content.js +2 -2
- package/dist/server/plugins/markdown/attribute-resolvers/utils.d.ts +1 -1
- package/dist/server/plugins/markdown/compiler.d.ts +1 -1
- package/dist/server/plugins/markdown/compiler.js +1 -1
- package/dist/server/plugins/markdown/errors.d.ts +1 -1
- package/dist/server/plugins/markdown/get-server-props.js +1 -1
- package/dist/server/plugins/markdown/html/normalize-html-headings.d.ts +1 -1
- package/dist/server/plugins/markdown/html/normalize-html-headings.js +1 -1
- package/dist/server/plugins/markdown/markdoc/functions/concat.d.ts +1 -1
- package/dist/server/plugins/markdown/markdoc/markdoc-options.d.ts +5 -165
- package/dist/server/plugins/markdown/markdoc/markdoc-options.js +1 -1
- package/dist/server/plugins/markdown/markdoc/partials.d.ts +1 -1
- package/dist/server/plugins/markdown/markdoc/plugins/headings.d.ts +1 -1
- package/dist/server/plugins/markdown/markdoc/plugins/utils.d.ts +1 -1
- package/dist/server/plugins/markdown/markdoc/reparse-example-fences.d.ts +1 -1
- package/dist/server/plugins/markdown/markdoc/reparse-example-fences.js +1 -1
- package/dist/server/plugins/markdown/runtime-transform.d.ts +2 -2
- package/dist/server/plugins/markdown/runtime-transform.js +1 -1
- package/dist/server/plugins/markdown/search/get-ai-search-documents.js +1 -1
- package/dist/server/plugins/markdown/search/nodes/section-node.d.ts +1 -1
- package/dist/server/plugins/markdown/search/search-resolver.js +1 -1
- package/dist/server/plugins/markdown/search/to-markdown.d.ts +1 -1
- package/dist/server/plugins/markdown/search/walk-sections.d.ts +1 -1
- package/dist/server/plugins/markdown/search/walk-sections.js +1 -1
- package/dist/server/plugins/markdown/utils/stringify-tag-children-objects.d.ts +1 -1
- package/dist/server/plugins/mcp/codemode/tools/describe-tools.d.ts +1 -1
- package/dist/server/plugins/mcp/codemode/tools/describe-tools.js +1 -3
- package/dist/server/plugins/mcp/docs-mcp/tools/graphql/get-graphql-type-list.js +1 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/graphql/list-graphql-apis.js +1 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/graphql/types.d.ts +4 -4
- package/dist/server/plugins/mcp/docs-mcp/tools/openapi/list-apis.js +1 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/openapi/types.d.ts +2 -2
- package/dist/server/plugins/mcp/handlers/docs-mcp-handler.js +1 -1
- package/dist/server/plugins/mcp/handlers/errors.d.ts +0 -5
- package/dist/server/plugins/mcp/handlers/errors.js +1 -1
- package/dist/server/plugins/mcp/handlers/handle-mcp-request.js +1 -1
- package/dist/server/plugins/mcp/handlers/mcp-credentials-handler.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 +10 -0
- package/dist/server/plugins/mcp/utils/available-tools.d.ts +5 -0
- package/dist/server/plugins/mcp/utils/available-tools.js +1 -0
- package/dist/server/plugins/mcp/workers/worker-context.d.ts +4 -0
- package/dist/server/plugins/mcp/workers/worker-context.js +1 -0
- package/dist/server/plugins/scorecard-classic/compute-scorecard.d.ts +2 -2
- package/dist/server/plugins/scorecard-classic/compute-scorecard.js +1 -1
- package/dist/server/plugins/scorecard-classic/index.js +1 -1
- package/dist/server/plugins/scorecard-classic/shared-utils.js +1 -1
- package/dist/server/plugins/scorecard-classic/template/Grid/GridHeader.js +3 -3
- package/dist/server/plugins/scorecard-classic/template/views.js +1 -1
- package/dist/server/plugins/search/engines/typesense/index.js +1 -1
- package/dist/server/store-config.d.ts +33 -0
- package/dist/server/store-config.js +1 -0
- package/dist/server/store.d.ts +11 -16
- package/dist/server/store.js +1 -1
- package/dist/server/tools/notifiers/formatter.js +3 -3
- package/dist/server/tools/notifiers/helpers/colors.d.ts +1 -1
- package/dist/server/types/plugins/api-routes.d.ts +4 -1
- package/dist/server/types/plugins/common.d.ts +1 -1
- package/dist/server/utils/codeframes/codeframes.d.ts +1 -1
- package/dist/server/utils/codeframes/yaml-ast.d.ts +1 -1
- package/dist/server/utils/decode-request-path.d.ts +2 -0
- package/dist/server/utils/decode-request-path.js +1 -0
- package/dist/server/utils/envs/env-boolean-string.d.ts +9 -3
- package/dist/server/utils/envs/get-api-route-allowed-env-variables.d.ts +2 -0
- package/dist/server/utils/envs/get-api-route-allowed-env-variables.js +1 -1
- package/dist/server/utils/envs/interpolate-env-variables.d.ts +5 -1
- package/dist/server/utils/envs/interpolate-env-variables.js +1 -1
- package/dist/server/utils/envs/load-env-variables.js +1 -1
- package/dist/server/utils/envs/replace-env-variables-deep.d.ts +17 -9
- package/dist/server/utils/envs/replace-env-variables-deep.js +1 -1
- package/dist/server/utils/errors.d.ts +3 -0
- package/dist/server/utils/errors.js +1 -1
- package/dist/server/utils/llmstxt/resolve-llms-txt-md.js +1 -1
- package/dist/server/utils/rbac-expand.js +1 -1
- package/dist/server/utils/rbac.d.ts +5 -1
- package/dist/server/utils/rbac.js +1 -1
- package/dist/server/utils/report-all-errors.js +1 -1
- package/dist/server/web-server/auth.d.ts +2 -0
- package/dist/server/web-server/auth.js +2 -2
- package/dist/server/web-server/middleware/jsonValidatorMiddleware.d.ts +5 -325
- package/dist/server/web-server/routes/auth.js +1 -1
- package/dist/server/web-server/routes/dynamic-route.js +1 -1
- package/dist/server/web-server/routes/error.js +1 -1
- package/dist/server/web-server/routes/helpers/process-redirects.js +1 -1
- package/dist/server/web-server/routes/mcp-routes/mcp-consent-page.d.ts +2 -2
- package/dist/server/web-server/routes/mcp-routes/mcp-consent-page.js +18 -18
- package/dist/server/web-server/routes/mcp-routes/mcp-oauth.js +1 -1
- package/dist/server/web-server/utils/ssrf-safe-lookup.d.ts +2 -1
- package/dist/server/web-server/utils/ssrf-safe-lookup.js +1 -1
- package/dist/server/workers/mcp-tool-worker-methods.d.ts +7 -0
- package/dist/server/workers/mcp-tool-worker-methods.js +1 -0
- package/dist/server/workers/mcp-tool-worker-pool.d.ts +0 -1
- package/dist/server/workers/mcp-tool-worker-pool.js +1 -1
- package/dist/server/workers/mcp-tool-worker.js +1 -1
- package/dist/server/workers/types.d.ts +4 -8
- package/dist/server/workers/worker-config.d.ts +33 -0
- package/dist/server/workers/worker-config.js +1 -0
- package/dist/types/errors.d.ts +1 -1
- package/dist/types/markdoc.d.ts +1 -1
- package/package.json +11 -11
- package/dist/server/plugins/markdown/html/html-jsx-attribute-mapping.d.ts +0 -6
- package/dist/server/plugins/markdown/html/html-jsx-attribute-mapping.js +0 -1
- package/dist/server/plugins/markdown/html/process-html-tokens.d.ts +0 -2
- package/dist/server/plugins/markdown/html/process-html-tokens.js +0 -1
- package/dist/server/plugins/markdown/source.d.ts +0 -4
- package/dist/server/plugins/markdown/source.js +0 -1
- package/dist/server/plugins/mcp/utils/available-sandbox-tools.d.ts +0 -4
- package/dist/server/plugins/mcp/utils/available-sandbox-tools.js +0 -1
- package/dist/server/tools/notifiers/helpers/privacy/mask-email.d.ts +0 -25
- package/dist/server/tools/notifiers/helpers/privacy/mask-email.js +0 -1
- package/dist/server/tools/notifiers/helpers/privacy/mask-subject.d.ts +0 -13
- package/dist/server/tools/notifiers/helpers/privacy/mask-subject.js +0 -1
- package/dist/server/tools/notifiers/helpers/privacy/remove-pii-from-url.d.ts +0 -25
- package/dist/server/tools/notifiers/helpers/privacy/remove-pii-from-url.js +0 -1
- package/dist/server/tools/notifiers/helpers/privacy/remove-pii.d.ts +0 -36
- package/dist/server/tools/notifiers/helpers/privacy/remove-pii.js +0 -1
|
@@ -1 +1 @@
|
|
|
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 R,createMcpAuthorizationCode as ae,verifyMcpAuthorizationCode as de,createMcpRefreshToken as K,verifyMcpRefreshToken as ce,createMcpSessionResource as M,oidcRefreshTokenGrant as pe,getOidcMetadata as ue,getUserParamsFromCookies as le,idTokenIsForThisProject as _e}from"../../auth.js";import{isMcpContentProtected as P}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 w}from"../../../../constants/api.js";import{AuthCookieNames as v}from"../../../../constants/common.js";import{withPathPrefix as I}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 we,isClientMetadataDocumentUrl as z,isLoopbackRedirect as W,isRedirectUriRegistered as Ie}from"./mcp-client-metadata.js";import{CONSENT_PAGE_HEADERS as Y,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 Re,redeemAuthorizationCode as Pe,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"];function Ue(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 Le(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 Ne(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 fr(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 t=L(e);return s(e,{resource:`${t}${I("/mcp")}`,authorization_servers:[t],bearer_methods_supported:["header"],resource_documentation:`${t}${w.MCP_OAUTH_AUTHORIZATION_SERVER}`,scopes_supported:[...E],bearer_token_types_supported:["Bearer"]},200,{"Access-Control-Allow-Origin":"*"})}}function hr(r){return async e=>{if(!P(r))return s(e,{error:"not_found"},404);const t=L(e);return s(e,{issuer:t,authorization_endpoint:`${t}${I(w.MCP_AUTHORIZATION)}`,token_endpoint:`${t}${I(w.MCP_TOKEN_PORTAL)}`,scopes_supported:[...E],registration_endpoint:`${t}${I(w.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 mr(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: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 De=new Set(["http:","https:","ws:","wss:","ftp:","file:"]),He=new Set(["javascript:","data:","blob:","about:","vbscript:","intent:","chrome:","view-source:","ms-msdt:","ms-appx-web:"]),be=2048,qe=/[\s\p{Cc}]/u;function Z(r){if(!r||r.length>be||r.includes("#")||qe.test(r))return;const e=URL.parse(r);if(e){if(e.protocol==="https:"||W(e))return r.toLowerCase().startsWith(`${e.protocol}//`)?e:void 0;if(!(De.has(e.protocol)||He.has(e.protocol)))return e}}function X(r){const e=r||{},t=Object.keys(e),n=t.find(a=>R(e[a])&&se(e[a])),i=t.find(a=>R(e[a]));return n||i||t[0]}function gr(r){return async e=>{if(!P(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"),d=n.get("code_challenge"),o=n.get("code_challenge_method"),c=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(!d)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 we(a);if(p=u.client_name,!Ie(i,u.redirect_uris))return s(e,{error:"invalid_request",error_description:"redirect_uri is not registered for this client"},400)}catch(u){const f=u instanceof Error?u.message:String(u);return s(e,{error:"invalid_client",error_description:`Unable to resolve client metadata document: ${f}`},400)}y.sendMcpAuthorizationStartedMessage([{...M(c),redirect_uri:i||null}]);const l=L(e),k={isMcpFlow:!0,originalRedirectUri:i,mcpClientId:a,mcpState:n.get("state"),mcpSessionId:c,mcpCodeChallenge:d,mcpCodeChallengeMethod:o,mcpClientName:p,timestamp:Date.now()};try{const u=await Le(k),f=new URL(I(w.IDP_LOGIN),l);f.searchParams.set("redirectTo",`${w.MCP_CALLBACK}/${u}`);const h=X(r.getConfig().ssoDirect);return h?(f.searchParams.set("idpId",h),e.redirect(f.toString())):s(e,{error:"not_found"},404)}catch(u){const f=u instanceof Error?u.message:String(u),h=u instanceof Error?u.stack:String(u);y.sendMcpAuthorizationFailedMessage([{...M(c),error:f,error_details:h}]);const S=new URL(I(`${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 je(r,e,t){const n=T=>s(r,{error:"invalid_grant",error_description:T},400),i=r.get("logger"),a=t.get("refresh_token"),d=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 ce(a)}catch(T){return i?.warn("MCP refresh token rejected: %s",T instanceof Error?T.message:String(T)),n("Invalid refresh token")}if(d&&d!==o.client_id)return n("Client mismatch");const c=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||!R(c))return n("Unknown identity provider");let _;try{const g=await ue(o.idp_id,c);if(!g?.token_endpoint)return n("Identity provider has no token endpoint");_=await pe(g.token_endpoint,T,c)}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(_.error||!(_.id_token||_.access_token))return i?.warn("MCP refresh rejected by IdP: %s",_.error||"empty token response"),n("Refresh rejected by identity provider");if(_.refresh_token&&(u=V(_.refresh_token,m)),_.access_token&&(k=J(_.access_token,m)),_.id_token){try{const g=C.decode(_.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 f=Math.min(R(c)&&c.tokenExpirationTime||b,b),h=p??o.claims;if(!_e(h,c))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:f}),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 Cr(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,d=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 je(e,r,t);if(!i)return s(e,{error:"invalid_request",error_description:"Missing authorization code"},400);try{const o=await de(i);if(a&&a!==o.redirect_uri)return s(e,{error:"invalid_grant",error_description:"redirect_uri mismatch"},400);if(!d)return s(e,{error:"invalid_grant",error_description:"code_verifier required"},400);if(!Ue(o.code_challenge,o.code_challenge_method,d))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 c=o.id_token;if(typeof c!="string"||c.length===0)return s(e,{error:"invalid_grant",error_description:"Missing id_token in authorization code"},400);const p=await x(c,r.getConfig().ssoDirect);if(!p)return s(e,{error:"invalid_grant",error_description:"Invalid authorization code"},400);if(j()&&!await Pe(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 ze(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 $e(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(I(`${w.MCP_CALLBACK}/`))){const d=n.pathname.split("/");i=d[d.length-1]}if(!i)return t.text("Missing context parameter",400);let a=null;try{const d=await Ne(i);a=d.mcpSessionId||null;const o=d.originalRedirectUri,c=Z(o);if(!d.isMcpFlow||!o||!c)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:d,redirectUri:o,redirectUrl:c,sessionToken:p,session:l})}catch(d){const o=Ke(d);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:d}){const o=H(r,v.IDP_ACCESS_TOKEN),c=H(r,v.IDP_REFRESH_TOKEN),p=await ae({idToken:a,idpId:d.idpId??X(e.getConfig().ssoDirect),idpAccessTokenEnc:o?J(o,m):void 0,idpRefreshTokenEnc:c?V(c,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 Fe(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 Ge({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 Tr(r){return ee(r,async(e,t)=>{const n=te(t);if(W(t.redirectUrl)||n&&await Re(await r.getKv(),n))return re(e,r,t);const{mcpClientId:i,mcpClientName:a}=t.mcpContext,d=ye({site:ne(e,r),user:Ge(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 ze(t)});return new Response(d,{status:200,headers:Y})})}function kr(r){return ee(r,async(e,t)=>{const n=await e.req.formData(),i=n.get("consent");if(typeof i!="string"||!await $e(i,t))return new Response(Ee(ne(e,r)),{status:403,headers:Y});if(n.get("decision")==="allow"){const a=te(t);return a&&await Oe(await r.getKv(),a),re(e,r,t)}return Fe(e,t)})}function Ke(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,Le as createMcpContextToken,gr as mcpAuthorizationHandler,Tr as mcpCallbackHandler,kr as mcpConsentHandler,mr as mcpDynamicClientRegistrationHandler,hr as mcpOAuthAuthorizationServerHandler,fr as mcpOAuthProtectedResourceHandler,Cr as mcpTokenPortalHandler,X as resolveMcpIdpId,Ne as verifyAndParseMcpContextToken,Ue as verifyPkce};
|
|
1
|
+
import{getCookie as v}from"hono/cookie";import{createHash as G,timingSafeEqual as se}from"node:crypto";import{ulid as ae}from"ulid";import{isRedoclySso as ce,isOidcProviderConfig as O,createMcpAuthorizationCode as de,verifyMcpAuthorizationCode as pe,createMcpRefreshToken as B,verifyMcpRefreshToken as ue,createMcpSessionResource as M,oidcRefreshTokenGrant as le,getOidcMetadata as _e,getUserParamsFromCookies as fe,idTokenIsForThisProject as he}from"../../auth.js";import{isMcpContentProtected as U}from"../../../plugins/mcp/auth/auth-handlers.js";import{resolveSiteBranding as me}from"../../../plugins/mcp/handlers/credentials-page/site-branding.js";import{SUPPORTED_MCP_SCOPES as E}from"../../../plugins/mcp/constants.js";import{AUTH_URL as ge,JWT_SECRET_KEY as m,MCP_ACCESS_TOKEN_TTL_SEC as b,MCP_CLAIMS_ONLY_SESSION_LIFETIME_SEC as K,MCP_REFRESH_SESSION_LIFETIME_SEC as Ce}from"../../../constants/common.js";import{ServerRoutes as I}from"../../../../constants/api.js";import{AuthCookieNames as A}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 L,McpAccessTokenMarker as N}from"../../jwt/token-types.js";import{AlgorithmTypes as R,JwtAlgorithmNotImplemented as Te,JwtTokenExpired as ke,JwtTokenInvalid as Se,JwtTokenNotBefore as Ie,JwtTokenSignatureMismatched as we}from"../../jwt/types.js";import{getRequestOrigin as D}from"../../utils/get-request-origin.js";import{encryptClaimValue as J}from"../../../utils/crypto/encrypt-claim-value.js";import{decryptAesGcm as Me}from"../../../utils/crypto/decrypt-aes-gcm.js";import{encryptAesGcm as V}from"../../../utils/crypto/encrypt-aes-gcm.js";import{fetchClientMetadataDocument as Ee,isClientMetadataDocumentUrl as z,isLoopbackRedirect as W,isRedirectUriRegistered as ye}from"./mcp-client-metadata.js";import{CONSENT_PAGE_HEADERS as Y,MCP_CONSENT_TTL_SEC as Ae,consentInvalidPage as Re,consentPage as Pe}from"./mcp-consent-page.js";import{MCP_CONSENT_MEMORY_DAYS as ve,hasConsent as Oe,redeemAuthorizationCode as Ue,redeemRefreshToken as Le,saveConsent as Ne}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"];function De(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:se(i,a)}async function He(r){const e=Math.floor(Date.now()/1e3);return C.sign({type:L.MCP_CONTEXT,...r,iat:e,exp:e+600},m,R.HS256)}async function be(r){await C.verify(r,m,R.HS256);const{payload:e}=C.decode(r);if(e.type!==L.MCP_CONTEXT)throw new Error("Invalid context token type");return e}function gr(r){return async e=>{if(!U(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=D(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 Cr(r){return async e=>{if(!U(r))return s(e,{error:"not_found"},404);const t=D(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 Tr(r){return async e=>{if(!U(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 qe=new Set(["http:","https:","ws:","wss:","ftp:","file:"]),je=new Set(["javascript:","data:","blob:","about:","vbscript:","intent:","chrome:","view-source:","ms-msdt:","ms-appx-web:"]),ze=2048,$e=/[\s\p{Cc}]/u;function Z(r){return r?Ce:K}function X(r){if(!r||r.length>ze||r.includes("#")||$e.test(r))return;const e=URL.parse(r);if(e){if(e.protocol==="https:"||W(e))return r.toLowerCase().startsWith(`${e.protocol}//`)?e:void 0;if(!(qe.has(e.protocol)||je.has(e.protocol)))return e}}function Q(r){const e=r||{},t=Object.keys(e),n=t.find(a=>O(e[a])&&ce(e[a])),i=t.find(a=>O(e[a]));return n||i||t[0]}function kr(r){return async e=>{if(!U(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"),p=ae();if(!i||!X(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 d;if(z(a))try{const u=await Ee(a);if(d=u.client_name,!ye(i,u.redirect_uris))return s(e,{error:"invalid_request",error_description:"redirect_uri is not registered for this client"},400)}catch(u){const h=u instanceof Error?u.message:String(u);return s(e,{error:"invalid_client",error_description:`Unable to resolve client metadata document: ${h}`},400)}y.sendMcpAuthorizationStartedMessage([{...M(p),redirect_uri:i||null}]);const l=D(e),k={isMcpFlow:!0,originalRedirectUri:i,mcpClientId:a,mcpState:n.get("state"),mcpSessionId:p,mcpCodeChallenge:c,mcpCodeChallengeMethod:o,mcpClientName:d,timestamp:Date.now()};try{const u=await He(k),h=new URL(w(I.IDP_LOGIN),l);h.searchParams.set("redirectTo",`${I.MCP_CALLBACK}/${u}`);const _=Q(r.getConfig().ssoDirect);return _?(h.searchParams.set("idpId",_),e.redirect(h.toString())):s(e,{error:"not_found"},404)}catch(u){const h=u instanceof Error?u.message:String(u),_=u instanceof Error?u.stack:String(u);y.sendMcpAuthorizationFailedMessage([{...M(p),error:h,error_details:_}]);const S=new URL(w(`${ge}/oauth2/auth`));return S.search=n.toString(),e.redirect(S.toString())}}}async function x(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,[N.CLAIM]:N.VALUE,...r.idpId?{idpId:r.idpId}:{},...r.idpAccessTokenEnc?{idp_access_token:r.idpAccessTokenEnc}:{},...r.ttlSec?{iat:e}:{},exp:t},m,R.HS256,r.kid),expiresIn:Math.max(t-e,0)}}async function Fe(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 ue(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 p=o.idp_id?e.getConfig().ssoDirect?.[o.idp_id]:void 0;let d,l,k=o.idp_access_token_enc,u=o.idp_refresh_token_enc;if(o.idp_refresh_token_enc){let T;try{T=Me(o.idp_refresh_token_enc,m)}catch{return n("Invalid refresh token")}if(!o.idp_id||!O(p))return n("Unknown identity provider");let f;try{const g=await _e(o.idp_id,p);if(!g?.token_endpoint)return n("Identity provider has no token endpoint");f=await le(g.token_endpoint,T,p)}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);d=g.payload,l=g.header.kid}catch{return n("Invalid token response from identity provider")}if(d.iss!==o.claims.iss||d.sub!==o.claims.sub)return i?.warn("MCP refresh rejected: the id_token names another issuer or subject"),n("Invalid refresh token")}}const h=Math.min(O(p)&&p.tokenExpirationTime||b,b),_=d??o.claims;if(!he(_,p))return i?.warn("MCP refresh rejected: the id_token was issued for another project"),n("Invalid refresh token");const S=d||typeof _.iat!="number"?o.session_exp:Math.min(o.session_exp,_.iat+K);if(S<=Math.floor(Date.now()/1e3))return i?.warn("MCP refresh rejected: the claims snapshot is older than the claims-only window"),n("Refresh token expired");if(j()&&!await Le(await e.getKv(),a,o.exp))return i?.warn("MCP refresh rejected: the refresh token was already used"),n("Refresh token already used");const P=await x({claims:_,kid:l,idpId:o.idp_id,idpAccessTokenEnc:k,ttlSec:d?void 0:h}),ie=await B({clientId:o.client_id,idpId:o.idp_id,claims:_,idpAccessTokenEnc:k,idpRefreshTokenEnc:u,sessionExp:S});return s(r,{access_token:P.accessToken,token_type:"Bearer",expires_in:P.expiresIn,refresh_token:ie,scope:E.join(" ")},200,{"Cache-Control":"no-store",Pragma:"no-cache"})}function Sr(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 Fe(e,r,t);if(!i)return s(e,{error:"invalid_request",error_description:"Missing authorization code"},400);try{const o=await pe(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(!De(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 p=o.id_token;if(typeof p!="string"||p.length===0)return s(e,{error:"invalid_grant",error_description:"Missing id_token in authorization code"},400);const d=await ee(p,r.getConfig().ssoDirect);if(!d)return s(e,{error:"invalid_grant",error_description:"Invalid authorization code"},400);if(j()&&!await Ue(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 x({claims:d.payload,kid:d.kid,idpId:o.idp_id,idpAccessTokenEnc:l}),_=Math.floor(Date.now()/1e3)+Z(!!o.idp_refresh_token_enc),S=await B({clientId:o.client_id,idpId:o.idp_id,claims:d.payload,idpAccessTokenEnc:l,idpRefreshTokenEnc:o.idp_refresh_token_enc,sessionExp:_}),P={access_token:k,token_type:"Bearer",expires_in:u,refresh_token:S,scope:E.join(" ")};return s(e,P,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 ee(r,e){const t=await fe(e||{},{[A.AUTHORIZATION]:r});if(t.isAuthenticated!==!0)return;const{payload:n,header:i}=C.decode(r);if(n[N.CLAIM]!==N.VALUE)return{payload:n,kid:i.kid,idpId:typeof t.idpId=="string"?t.idpId:void 0}}function H(r){return G("sha256").update(r).digest("base64url")}async function Ge(r){const e=Math.floor(Date.now()/1e3);return C.sign({type:L.MCP_CONSENT,session_hash:H(r.sessionToken),context_hash:H(r.contextToken),iat:e,exp:e+Ae},m,R.HS256)}async function Be(r,e){try{await C.verify(r,m,R.HS256)}catch{return!1}const{payload:t}=C.decode(r);return t.type===L.MCP_CONSENT&&t.session_hash===H(e.sessionToken)&&t.context_hash===H(e.contextToken)}function re(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 be(i);a=c.mcpSessionId||null;const o=c.originalRedirectUri,p=X(o);if(!c.isMcpFlow||!o||!p)throw new Error("Invalid MCP context");const d=v(t,A.AUTHORIZATION),l=d?await ee(d,r.getConfig().ssoDirect):void 0;return!d||!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:p,sessionToken:d,session:l})}catch(c){const o=Ve(c);return y.sendMcpAuthorizationFailedMessage([{...M(a),...o}]),t.text(`Invalid MCP callback: ${o.error}`,400)}}}async function te(r,e,{mcpContext:t,redirectUri:n,redirectUrl:i,sessionToken:a,session:c}){const o=v(r,A.IDP_ACCESS_TOKEN),p=v(r,A.IDP_REFRESH_TOKEN),d=await de({idToken:a,idpId:c.idpId??Q(e.getConfig().ssoDirect),idpAccessTokenEnc:o?J(o,m):void 0,idpRefreshTokenEnc:p?V(p,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",d),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 Je({payload:r}){return[r.email,r.name,r.sub].find(e=>typeof e=="string"&&e.length>0)}function ne({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 oe(r,e){const{seo:t,colorMode:n}=e.getConfig(),{logo:i}=e.getGlobalData();return{...me({seo:t,logo:i,colorMode:n}),host:new URL(D(r)).host}}function Ir(r){return re(r,async(e,t)=>{const n=ne(t);if(W(t.redirectUrl)||n&&await Oe(await r.getKv(),n))return te(e,r,t);const{mcpClientId:i,mcpClientName:a}=t.mcpContext,c=Pe({site:oe(e,r),user:Je(t.session),clientName:a||void 0,clientIdHost:z(i)?new URL(i).host:void 0,redirectUrl:t.redirectUrl,scopes:E,accessLifetimeDays:Z(!!v(e,A.IDP_REFRESH_TOKEN))/(1440*60),rememberDays:n?ve:void 0,consentToken:await Ge(t)});return new Response(c,{status:200,headers:Y})})}function wr(r){return re(r,async(e,t)=>{const n=await e.req.formData(),i=n.get("consent");if(typeof i!="string"||!await Be(i,t))return new Response(Re(oe(e,r)),{status:403,headers:Y});if(n.get("decision")==="allow"){const a=ne(t);return a&&await Ne(await r.getKv(),a),te(e,r,t)}return Ke(e,t)})}function Ve(r){return r instanceof Error&&[Te,ke,Se,Ie,we].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,He as createMcpContextToken,kr as mcpAuthorizationHandler,Ir as mcpCallbackHandler,wr as mcpConsentHandler,Tr as mcpDynamicClientRegistrationHandler,Cr as mcpOAuthAuthorizationServerHandler,gr as mcpOAuthProtectedResourceHandler,Sr as mcpTokenPortalHandler,Q as resolveMcpIdpId,be as verifyAndParseMcpContextToken,De as verifyPkce};
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { type LookupFunction } from 'node:net';
|
|
2
2
|
/**
|
|
3
3
|
* Returns a drop-in replacement for `dns.lookup` that errors with
|
|
4
|
-
* {@link SsrfBlockedError} if any resolved address is in the blocklist.
|
|
4
|
+
* {@link SsrfBlockedError} if any resolved address is in the blocklist. The error message names
|
|
5
|
+
* the hostname only, never a resolved address, so callers may show it to the client.
|
|
5
6
|
*
|
|
6
7
|
* Install on an http/https agent (`connect.lookup` for undici, or `lookup` for a node:https Agent)
|
|
7
8
|
* so that every socket connection — including those made while following redirects — is re-validated
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{lookup as
|
|
1
|
+
import{lookup as m}from"node:dns";import{isIP as w}from"node:net";import{isBlockedIp as H,isLoopback as $,SsrfBlockedError as i}from"./ssrf-blocklist.js";function B({allowLoopback:l=!1}={}){const n=r=>H(r)&&!(l&&$(r));return(r,d,o)=>{const f=d,s=t=>{if(f.all){o(null,t);return}const[e]=t;if(!e){o(new i(`Hostname "${r}" did not resolve`),"",0);return}o(null,e.address,e.family)},u=w(r);if(u!==0){if(n(r)){o(new i(`Hostname "${r}" is a blocked address`),"",0);return}s([{address:r,family:u}]);return}m(r,{...f,all:!0},(t,e)=>{if(t){o(t,"",0);return}if(e.some(({address:p})=>n(p))){o(new i(`Hostname "${r}" resolves to a blocked address`),"",0);return}if(!e.length){o(new i(`Hostname "${r}" did not resolve`),"",0);return}s(e)})}}export{B as createSsrfSafeLookup};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { WorkerParams } from './types.js';
|
|
2
|
+
import { MCP_TOOL_AVAILABILITY_KEY, MCP_TOOL_WORKER_KEY } from './mcp-tool-worker-pool.js';
|
|
3
|
+
export declare const mcpToolWorkerMethods: {
|
|
4
|
+
executeMcpTool: (params: WorkerParams<typeof MCP_TOOL_WORKER_KEY>[0]) => Promise<import("../plugins/mcp/types.js").McpToolWorkerResponse>;
|
|
5
|
+
mcpToolAvailability: (params: WorkerParams<typeof MCP_TOOL_AVAILABILITY_KEY>[0]) => Promise<Record<string, boolean>>;
|
|
6
|
+
};
|
|
7
|
+
//# sourceMappingURL=mcp-tool-worker-methods.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{executeMcpTool as e,mcpToolAvailability as r}from"../plugins/mcp/workers/execute-mcp-tool.js";import{fromWorkerContext as t}from"../plugins/mcp/workers/worker-context.js";import{MCP_TOOL_AVAILABILITY_KEY as c,MCP_TOOL_WORKER_KEY as m}from"./mcp-tool-worker-pool.js";const T={[m]:o=>e({...o,context:t(o.context)}),[c]:o=>r({...o,context:t(o.context)})};export{T as mcpToolWorkerMethods};
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { WorkerPool } from './worker-pool.js';
|
|
2
2
|
export declare const MCP_TOOL_WORKER_KEY = "executeMcpTool";
|
|
3
|
-
export declare const MCP_TOOL_IS_AVAILABLE_KEY = "isMcpToolAvailable";
|
|
4
3
|
export declare const MCP_TOOL_AVAILABILITY_KEY = "mcpToolAvailability";
|
|
5
4
|
export declare const mcpToolWorkers: WorkerPool;
|
|
6
5
|
//# sourceMappingURL=mcp-tool-worker-pool.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{getAllowedEnvs as o}from"../utils/envs/get-api-route-allowed-env-variables.js";import{WorkerPool as r}from"./worker-pool.js";const p="executeMcpTool",
|
|
1
|
+
import{getAllowedEnvs as o}from"../utils/envs/get-api-route-allowed-env-variables.js";import{WorkerPool as r}from"./worker-pool.js";const p="executeMcpTool",c="mcpToolAvailability",e=5,l=new r({workerScript:"./mcp-tool-worker",minWorkers:1,maxWorkers:e,workerType:"process",forkOpts:{stdio:"inherit"},resolveForkEnv:o,lazy:!0,sandbox:!0});export{c as MCP_TOOL_AVAILABILITY_KEY,p as MCP_TOOL_WORKER_KEY,l as mcpToolWorkers};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import o from"workerpool";import{
|
|
1
|
+
import o from"workerpool";import{mcpToolWorkerMethods as r}from"./mcp-tool-worker-methods.js";o.worker(r);
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { ApiRoutesWorkerParams, ApiRoutesWorkerResponse } from '../types/plugins/api-routes.js';
|
|
2
2
|
import type { RenderPayload } from '../../types/ssr.js';
|
|
3
3
|
import type { ScorecardsWorkerParams, ScorecardsWorkerResponse } from '../types/plugins/scorecards.js';
|
|
4
|
-
import type {
|
|
4
|
+
import type { McpToolWorkerContext, McpToolWorkerParams, McpToolWorkerResponse } from '../plugins/mcp/types.js';
|
|
5
5
|
import type { SCORECARDS_WORKER_KEY } from './scorecards-worker-pool.js';
|
|
6
6
|
import type { API_ROUTES_WORKER_KEY } from './api-routes-worker-pool.js';
|
|
7
7
|
import type { SSR_WORKER_KEY } from './ssr-worker-pool.js';
|
|
8
|
-
import type { MCP_TOOL_AVAILABILITY_KEY,
|
|
8
|
+
import type { MCP_TOOL_AVAILABILITY_KEY, MCP_TOOL_WORKER_KEY } from './mcp-tool-worker-pool.js';
|
|
9
9
|
export type SsrWorkerResponse = {
|
|
10
10
|
html: string;
|
|
11
11
|
statusCode: 200 | 500;
|
|
@@ -25,17 +25,13 @@ export type WorkerTypeMapping = {
|
|
|
25
25
|
response: ScorecardsWorkerResponse;
|
|
26
26
|
};
|
|
27
27
|
[MCP_TOOL_WORKER_KEY]: {
|
|
28
|
-
params: [
|
|
28
|
+
params: [McpToolWorkerParams];
|
|
29
29
|
response: McpToolWorkerResponse;
|
|
30
30
|
};
|
|
31
|
-
[MCP_TOOL_IS_AVAILABLE_KEY]: {
|
|
32
|
-
params: [Omit<McpToolExecutionParams, 'args' | 'extra'>];
|
|
33
|
-
response: boolean;
|
|
34
|
-
};
|
|
35
31
|
[MCP_TOOL_AVAILABILITY_KEY]: {
|
|
36
32
|
params: [{
|
|
37
33
|
toolNames: string[];
|
|
38
|
-
context:
|
|
34
|
+
context: McpToolWorkerContext;
|
|
39
35
|
}];
|
|
40
36
|
response: Record<string, boolean>;
|
|
41
37
|
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { RedoclyConfig } from '@redocly/config';
|
|
2
|
+
type ConfigFileRef = {
|
|
3
|
+
path: string;
|
|
4
|
+
env: Record<string, string>;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* The store config file of a build output, and the env values that resolve its placeholders in a
|
|
8
|
+
* worker. `env` has no variable that the worker env excludes: those placeholders stay unresolved.
|
|
9
|
+
* Main process only: `config` is the store config that was loaded from the file.
|
|
10
|
+
*/
|
|
11
|
+
export type StoreConfigFile = ConfigFileRef & {
|
|
12
|
+
config: RedoclyConfig;
|
|
13
|
+
};
|
|
14
|
+
/** The config as it crosses to a worker: the config file entries, overridden by `entries`. */
|
|
15
|
+
export type WorkerConfig = {
|
|
16
|
+
file: ConfigFileRef;
|
|
17
|
+
entries: Partial<RedoclyConfig>;
|
|
18
|
+
} | {
|
|
19
|
+
file?: undefined;
|
|
20
|
+
entries: RedoclyConfig;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Sends only the top-level entries of `config` that are not the same values as in the config file.
|
|
24
|
+
* Without a config file (`develop`), sends all of `config`.
|
|
25
|
+
*/
|
|
26
|
+
export declare function toWorkerConfig(config: RedoclyConfig, configFile: StoreConfigFile | undefined): WorkerConfig;
|
|
27
|
+
/**
|
|
28
|
+
* Worker side. Returns a config that the call owns: a change to it, at any depth, is not seen by
|
|
29
|
+
* other calls. Throws when the config file cannot be read.
|
|
30
|
+
*/
|
|
31
|
+
export declare function readWorkerConfig(workerConfig: WorkerConfig): RedoclyConfig;
|
|
32
|
+
export {};
|
|
33
|
+
//# sourceMappingURL=worker-config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{readFileSync as a}from"node:fs";import{MARKDOC_PARTIALS_DATA_KEY as f}from"../constants/common.js";import{resolveStoreConfig as l}from"../store-config.js";let s;function m(n,e){if(!e)return{entries:n};const o=e.config;return{file:{path:e.path,env:e.env},entries:Object.fromEntries(Object.entries(n).filter(([t,r])=>o[t]!==r))}}function j(n){const{file:e,entries:o}=n;if(!e)return o;const t=d(e),r=Object.fromEntries(Object.keys(t).map(i=>[i,()=>structuredClone(t[i])]));return r[f]=()=>u(e)[f],O(r,o)}function d(n){const e=JSON.stringify([n.path,n.env]);if(s?.key!==e){const{[f]:o,...t}=u(n);s={key:e,config:t}}return s.config}function u({path:n,env:e}){let o;try{o=JSON.parse(a(n,"utf8"))}catch(t){throw new Error(`Could not read the store config file "${n}": ${String(t)}`)}return l(o,t=>e[t]).config}function O(n,e){const o={},t=(r,i)=>{Object.defineProperty(o,r,{value:i,writable:!0,enumerable:!0,configurable:!0})};for(const[r,i]of Object.entries(n)){if(Object.hasOwn(e,r)){t(r,e[r]);continue}Object.defineProperty(o,r,{enumerable:!0,configurable:!0,get:()=>{const c=i();return t(r,c),c},set:c=>t(r,c)})}for(const[r,i]of Object.entries(e))Object.hasOwn(o,r)||t(r,i);return o}export{j as readWorkerConfig,m as toWorkerConfig};
|
package/dist/types/errors.d.ts
CHANGED
package/dist/types/markdoc.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Node, Variable, RenderableTreeNode, Function } from '@
|
|
1
|
+
import type { Node, Variable, RenderableTreeNode, Function } from '@redocly/markdoc';
|
|
2
2
|
import type { RenderForLlmsRenderContext } from '@redocly/theme/markdoc/tags/types';
|
|
3
3
|
export type RenderTagFn = (node: Node, context: RenderForLlmsRenderContext) => string | undefined;
|
|
4
4
|
export type GetInnerContentFnOptions = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@redocly/realm",
|
|
3
|
-
"version": "0.140.0-next.
|
|
3
|
+
"version": "0.140.0-next.10",
|
|
4
4
|
"description": "",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -20,8 +20,8 @@
|
|
|
20
20
|
"@hono/zod-validator": "0.8.0",
|
|
21
21
|
"@jitl/quickjs-singlefile-mjs-release-sync": "0.32.0",
|
|
22
22
|
"@libsql/client": "0.17.3",
|
|
23
|
-
"@markdoc/markdoc": "0.
|
|
24
|
-
"@modelcontextprotocol/server": "2.
|
|
23
|
+
"@markdoc/markdoc": "npm:@redocly/markdoc@0.7.0-beta.2",
|
|
24
|
+
"@modelcontextprotocol/server": "2.3.1",
|
|
25
25
|
"@opentelemetry/api": "1.9.1",
|
|
26
26
|
"@opentelemetry/context-zone": "2.0.1",
|
|
27
27
|
"@opentelemetry/core": "2.8.0",
|
|
@@ -33,13 +33,14 @@
|
|
|
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.5.0-next.
|
|
37
|
-
"@redocly/config": "0.
|
|
38
|
-
"@redocly/
|
|
36
|
+
"@redocly/api-docs": "0.5.0-next.7",
|
|
37
|
+
"@redocly/config": "0.70.0",
|
|
38
|
+
"@redocly/markdoc": "0.7.0-beta.2",
|
|
39
|
+
"@redocly/openapi-core": "2.72.1",
|
|
39
40
|
"@redocly/portal-legacy-ui": "0.19.0",
|
|
40
|
-
"@redocly/portal-plugin-mock-server": "0.
|
|
41
|
+
"@redocly/portal-plugin-mock-server": "0.25.0-next.2",
|
|
41
42
|
"@redocly/realm-asyncapi-sdk": "0.17.0",
|
|
42
|
-
"@redocly/theme": "0.72.0-next.
|
|
43
|
+
"@redocly/theme": "0.72.0-next.6",
|
|
43
44
|
"@shikijs/transformers": "3.21.0",
|
|
44
45
|
"@tanstack/react-query": "5.62.3",
|
|
45
46
|
"@tanstack/react-table": "8.21.3",
|
|
@@ -62,7 +63,6 @@
|
|
|
62
63
|
"flexsearch": "0.7.43",
|
|
63
64
|
"graphql": "16.14.2",
|
|
64
65
|
"hono": "4.13.13",
|
|
65
|
-
"htmlparser2": "8.0.2",
|
|
66
66
|
"i18next": "22.4.15",
|
|
67
67
|
"is-glob": "4.0.3",
|
|
68
68
|
"js-yaml": "4.3.2",
|
|
@@ -91,14 +91,14 @@
|
|
|
91
91
|
"tty-browserify": "0.0.1",
|
|
92
92
|
"typesense": "2.1.0",
|
|
93
93
|
"ulid": "^3.0.2",
|
|
94
|
-
"undici": "^6.
|
|
94
|
+
"undici": "^6.29.1",
|
|
95
95
|
"web-vitals": "3.3.1",
|
|
96
96
|
"workerpool": "9.2.0",
|
|
97
97
|
"ws": "^8.21.0",
|
|
98
98
|
"xml-crypto": "6.1.0",
|
|
99
99
|
"xpath": "0.0.34",
|
|
100
100
|
"yaml-ast-parser": "0.0.43",
|
|
101
|
-
"zod": "^
|
|
101
|
+
"zod": "^4.6.6"
|
|
102
102
|
},
|
|
103
103
|
"peerDependencies": {
|
|
104
104
|
"react": "^19.2.7",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
const a={for:"htmlFor",class:"className","accept-charset":"acceptCharset",accesskey:"accessKey",allowfullscreen:"allowFullScreen",allowtransparency:"allowTransparency",autocomplete:"autoComplete",autoplay:"autoPlay",cellpadding:"cellPadding",cellspacing:"cellSpacing",charset:"charSet",classid:"classID",colspan:"colSpan",contenteditable:"contentEditable",contextmenu:"contextMenu",crossorigin:"crossOrigin",datetime:"dateTime",enctype:"encType",formaction:"formAction",formenctype:"formEncType",formmethod:"formMethod",formnovalidate:"formNoValidate",formtarget:"formTarget",frameborder:"frameBorder",hreflang:"hrefLang","http-equiv":"httpEquiv",inputmode:"inputMode",keyparams:"keyParams",keytype:"keyType",marginheight:"marginHeight",marginwidth:"marginWidth",maxlength:"maxLength",mediagroup:"mediaGroup",minlength:"minLength",novalidate:"noValidate",playsinline:"playsInline",radiogroup:"radioGroup",readonly:"readOnly",referrerpolicy:"referrerPolicy",rowspan:"rowSpan",spellcheck:"spellCheck",srcdoc:"srcDoc",srclang:"srcLang",srcset:"srcSet",tabindex:"tabIndex",usemap:"useMap",autocapitalize:"autoCapitalize",autocorrect:"autoCorrect",autosave:"autoSave",itemprop:"itemProp",itemscope:"itemScope",itemtype:"itemType",itemid:"itemID",itemref:"itemRef","accent-height":"accentHeight","alignment-baseline":"alignmentBaseline","arabic-form":"arabicForm","baseline-shift":"baselineShift","cap-height":"capHeight","clip-path":"clipPath","clip-rule":"clipRule","color-interpolation":"colorInterpolation","color-interpolation-filters":"colorInterpolationFilters","color-profile":"colorProfile","color-rendering":"colorRendering","dominant-baseline":"dominantBaseline","enable-background":"enableBackground","fill-opacity":"fillOpacity","fill-rule":"fillRule","flood-color":"floodColor","flood-opacity":"floodOpacity","font-family":"fontFamily","font-size":"fontSize","font-size-adjust":"fontSizeAdjust","font-stretch":"fontStretch","font-style":"fontStyle","font-variant":"fontVariant","font-weight":"fontWeight","glyph-name":"glyphName","glyph-orientation-horizontal":"glyphOrientationHorizontal","glyph-orientation-vertical":"glyphOrientationVertical","horiz-adv-x":"horizAdvX","horiz-origin-x":"horizOriginX","image-rendering":"imageRendering","letter-spacing":"letterSpacing","lighting-color":"lightingColor","marker-end":"markerEnd","marker-mid":"markerMid","marker-start":"markerStart","overline-position":"overlinePosition","overline-thickness":"overlineThickness","paint-order":"paintOrder","panose-1":"panose1","pointer-events":"pointerEvents","rendering-intent":"renderingIntent","shape-rendering":"shapeRendering","stop-color":"stopColor","stop-opacity":"stopOpacity","strikethrough-position":"strikethroughPosition","strikethrough-thickness":"strikethroughThickness","stroke-dasharray":"strokeDasharray","stroke-dashoffset":"strokeDashoffset","stroke-linecap":"strokeLinecap","stroke-linejoin":"strokeLinejoin","stroke-miterlimit":"strokeMiterlimit","stroke-opacity":"strokeOpacity","stroke-width":"strokeWidth","text-anchor":"textAnchor","text-decoration":"textDecoration","text-rendering":"textRendering","underline-position":"underlinePosition","underline-thickness":"underlineThickness","unicode-bidi":"unicodeBidi","unicode-range":"unicodeRange","units-per-em":"unitsPerEm","v-alphabetic":"vAlphabetic","v-hanging":"vHanging","v-ideographic":"vIdeographic","v-mathematical":"vMathematical","vector-effect":"vectorEffect","vert-adv-y":"vertAdvY","vert-origin-x":"vertOriginX","vert-origin-y":"vertOriginY","word-spacing":"wordSpacing","writing-mode":"writingMode","x-height":"xHeight","xlink:actuate":"xlinkActuate","xlink:arcrole":"xlinkArcrole","xlink:href":"xlinkHref","xlink:role":"xlinkRole","xlink:show":"xlinkShow","xlink:title":"xlinkTitle","xlink:type":"xlinkType","xml:base":"xmlBase","xmlns:xlink":"xmlnsXlink","xml:lang":"xmlLang","xml:space":"xmlSpace"};function s(r,t){const e={};for(const[i,n]of Object.entries(r))switch(i){case"value":t==="input"||t==="textarea"?e.defaultValue=n:e.value=n;break;case"checked":t==="input"?e.defaultChecked=!0:e.checked=n;break;case"style":e.style=c(n);break;default:e[a[i]||i]=n}return e}function l(r){return r.match(/^--/)?r:r.replace(/-[a-z]/g,t=>t[1].toUpperCase())}function c(r){return r.split(";").filter(t=>t.trim().length).reduce((t,e)=>{const i=e.indexOf(":"),n=i===-1?e:e.slice(0,i),o=i===-1?"":e.slice(i+1);return t[l(n.trim())]=o.trim(),t},{})}export{s as getJsxConvertedAttributes};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{Parser as p}from"htmlparser2";import{getJsxConvertedAttributes as i}from"./html-jsx-attribute-mapping.js";function l(r){const e=[],n=[];let o=null;const s=new p({onopentag(t,a){n.push({name:t,token:o}),e.push({type:"tag_open",nesting:1,meta:{tag:"html",attributes:[{type:"attribute",name:"name",value:t},{type:"attribute",name:"attrs",value:i(a,t)}]}})},ontext(t){t?.trim().length>0&&e.push({type:"text",content:t})},onclosetag(){n.pop(),e.push({type:"tag_close",nesting:-1,meta:{tag:"html"}})}});for(const t of r){if(t.type.startsWith("html")){o=t,s.write(t.content);continue}t.type==="inline"&&(t.children=l(t.children)),e.push(t)}for(const t of n)e.push({type:"error",meta:{error:{message:`HTML tag <${t.name}> is not closed, opened at`,location:t?.token?.map?{start:{line:t.token.map[0]},end:{line:t.token.map[1]}}:void 0}}}),e.push({type:"tag_close",nesting:-1,meta:{tag:"html"}});return e}export{l as processHtmlTokens};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
function s(e,t){if(e.lines.length===0)return"";let l="",i=[];if(e.location){const n=e.lines[0]+1;if(l+=`#L${n}`,n!==e.lines[e.lines.length-1]){const r=e.lines[e.lines.length-1];l+=`-L${e.lines[e.lines.length-1]}`,i=t.slice(n-1,r)}else i=[t[n-1]]}return{range:l,source:i}}function h(e){let t=5381,l=e.length;for(;l;)t=t*33^e.charCodeAt(--l);return(t>>>0).toString(16)}export{s as getSourceRange,h as hashSourceContent};
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import type { McpToolSchema } from '../../../types';
|
|
2
|
-
import type { McpToolContext } from '../types.js';
|
|
3
|
-
export declare function availableSandboxTools(candidates: McpToolSchema[], context: McpToolContext): Promise<McpToolSchema[]>;
|
|
4
|
-
//# sourceMappingURL=available-sandbox-tools.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{logger as a}from"../../../tools/notifiers/logger.js";import{mcpToolWorkers as n,MCP_TOOL_AVAILABILITY_KEY as m}from"../../../workers/mcp-tool-worker-pool.js";async function p(t,l){if(t.length===0)return t;const e=t.map(o=>o.name);let r;try{r=await n.exec(m,[{toolNames:e,context:l}],{timeout:1e4})}catch(o){return i(t,o instanceof Error?o.message:String(o))}return!r||typeof r!="object"?i(t,"the worker returned no availability map"):t.filter(o=>r[o.name]!==!1)}function i(t,l){const e=t.filter(r=>r.hasAvailabilityGate);return e.length===0?t:(a.warn(`MCP tool availability is unknown (${l}); the sandbox tool list drops the gated tools: ${e.map(r=>r.name).join(", ")}.`),t.filter(r=>!r.hasAvailabilityGate))}export{p as availableSandboxTools};
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Masks the username part of an email address for privacy or anonymization.
|
|
3
|
-
*
|
|
4
|
-
* The function preserves the domain while replacing most characters in the username
|
|
5
|
-
* with asterisks (`*`). It keeps the first two characters visible when the username
|
|
6
|
-
* is longer than two characters. If the input is invalid or not a string containing
|
|
7
|
-
* an `@` symbol, it returns the original value unchanged.
|
|
8
|
-
*
|
|
9
|
-
* @example
|
|
10
|
-
* ```ts
|
|
11
|
-
* maskEmail("john.doe@example.com");
|
|
12
|
-
* // → "jo******@example.com"
|
|
13
|
-
*
|
|
14
|
-
* maskEmail("ab@example.com");
|
|
15
|
-
* // → "ab@example.com"
|
|
16
|
-
*
|
|
17
|
-
* maskEmail("a@example.com");
|
|
18
|
-
* // → "*@example.com"
|
|
19
|
-
* ```
|
|
20
|
-
*
|
|
21
|
-
* @param email - The email address to mask.
|
|
22
|
-
* @returns A masked version of the email, or the original value if invalid.
|
|
23
|
-
*/
|
|
24
|
-
export declare const maskEmail: (email: string) => string;
|
|
25
|
-
//# sourceMappingURL=mask-email.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
const r=e=>{if(!e||typeof e!="string"||!e.includes("@"))return e;const[n,t]=e.split("@");return`${n.length>2?n.slice(0,2)+"*".repeat(n.length-2):"*".repeat(n.length)}@${t}`};export{r as maskEmail};
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Masks all email addresses found within a given subject string.
|
|
3
|
-
*
|
|
4
|
-
* This utility searches the input text for any email-like patterns and replaces
|
|
5
|
-
* each one using the {@link maskEmail} function, preserving the rest of the string.
|
|
6
|
-
* It is typically used to sanitize or anonymize email addresses before logging,
|
|
7
|
-
* displaying, or transmitting text content.
|
|
8
|
-
*
|
|
9
|
-
* @param subject - The text that may contain one or more email addresses.
|
|
10
|
-
* @returns A new string with all detected email addresses masked.
|
|
11
|
-
*/
|
|
12
|
-
export declare const maskSubject: (subject: string) => string;
|
|
13
|
-
//# sourceMappingURL=mask-subject.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{maskEmail as c}from"./mask-email.js";const r=/[a-zA-Z0-9._%+-]/,m=/^[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/,d=e=>{let o="",i=0,a=0;for(;a<e.length;){const n=e.indexOf("@",a);if(n===-1)break;let t=n;for(;t>i&&r.test(e.charAt(t-1));)t--;const s=t<n?m.exec(e.slice(n+1))?.[0]:void 0;if(!s){a=n+1;continue}const l=n+1+s.length;o+=e.slice(i,t)+c(e.slice(t,l)),i=l,a=l}return o+e.slice(i)};export{d as maskSubject};
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Sanitizes personally identifiable information (PII) found within a URL or query string.
|
|
3
|
-
*
|
|
4
|
-
* This function scans all query parameter values and removes or masks any PII using
|
|
5
|
-
* the {@link removePii} function. It gracefully handles both absolute and relative URLs.
|
|
6
|
-
*
|
|
7
|
-
* - If the input is not a string, it is returned unchanged.
|
|
8
|
-
* - If parsing as a URL fails, the function falls back to applying {@link removePii}
|
|
9
|
-
* directly on the raw string.
|
|
10
|
-
* - The output preserves the original format (absolute or relative).
|
|
11
|
-
*
|
|
12
|
-
* @example
|
|
13
|
-
* ```ts
|
|
14
|
-
* removePiiFromUrl('https://example.com?email=john.doe@example.com&phone=555-123-4567');
|
|
15
|
-
* // → 'https://example.com/?email=[email_removed]&phone=[phone_removed]'
|
|
16
|
-
*
|
|
17
|
-
* removePiiFromUrl('/profile?ssn=123-45-6789');
|
|
18
|
-
* // → '/profile?ssn=[SSN_removed]'
|
|
19
|
-
* ```
|
|
20
|
-
*
|
|
21
|
-
* @param url - The input URL string or relative path to sanitize.
|
|
22
|
-
* @returns A sanitized URL string with PII masked, or the input value unchanged if not a string.
|
|
23
|
-
*/
|
|
24
|
-
export declare function removePiiFromUrl(url: unknown): unknown;
|
|
25
|
-
//# sourceMappingURL=remove-pii-from-url.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{isString as n}from"../../../../../utils/string/is-string.js";import{removePii as e}from"./remove-pii.js";function m(t){if(!n(t))return t;try{const r=new URL(t,"http://example.com");for(const[i,s]of r.searchParams.entries()){const a=String(e(s));r.searchParams.set(i,a)}return t.startsWith("http://")||t.startsWith("https://")?r.toString():r.pathname+r.search+r.hash}catch{return String(e(t))}}export{m as removePiiFromUrl};
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Implementation of PII sanitization from @coffeeandfun/remove-pii (MIT licensed) without unnecessary methods
|
|
3
|
-
*/
|
|
4
|
-
type PIIConfigOption = {
|
|
5
|
-
enabled: false;
|
|
6
|
-
replacement?: string;
|
|
7
|
-
pattern?: RegExp;
|
|
8
|
-
} | {
|
|
9
|
-
enabled: true;
|
|
10
|
-
replacement: string;
|
|
11
|
-
pattern?: RegExp;
|
|
12
|
-
};
|
|
13
|
-
type PIIConfig = {
|
|
14
|
-
[key: string]: PIIConfigOption;
|
|
15
|
-
};
|
|
16
|
-
/**
|
|
17
|
-
* Removes or masks personally identifiable information (PII) from a given text string.
|
|
18
|
-
*
|
|
19
|
-
* This function identifies and replaces sensitive data such as email addresses,
|
|
20
|
-
* phone numbers, credit card numbers, and other personal identifiers with
|
|
21
|
-
* configurable placeholder strings. It’s a lightweight implementation inspired by
|
|
22
|
-
* `@coffeeandfun/remove-pii` (MIT licensed), keeping only the essential sanitization logic.
|
|
23
|
-
*
|
|
24
|
-
* By default, all common PII patterns (email, phone, SSN, credit card, address,
|
|
25
|
-
* passport number, driver’s license, ZIP code, bank account, and date of birth)
|
|
26
|
-
* are detected and replaced. Custom configuration can override or disable any pattern.
|
|
27
|
-
*
|
|
28
|
-
* Non-string inputs are returned unchanged.
|
|
29
|
-
*
|
|
30
|
-
* @param text - The input text that may contain personally identifiable information.
|
|
31
|
-
* @param options - Optional configuration to enable, disable, or customize PII replacements.
|
|
32
|
-
* @returns A sanitized string with PII masked or removed; if the input is not a string, returns it unchanged.
|
|
33
|
-
*/
|
|
34
|
-
export declare function removePii(text: unknown, options?: PIIConfig): unknown;
|
|
35
|
-
export {};
|
|
36
|
-
//# sourceMappingURL=remove-pii.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{isString as m}from"../../../../../utils/string/is-string.js";const s={email:{pattern:/\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b/g,replacement:"[email_removed]"},phone:{pattern:/(?:\+?1[-.\s]?)?\(?([0-9]{3})\)?[-.\s]?([0-9]{3})[-.\s]?([0-9]{4})(?:\s?(?:ext|x|extension)\.?\s?(\d+))?/g,replacement:"[phone_removed]"},ssn:{pattern:/\b(?!000|666|9\d{2})\d{3}-?(?!00)\d{2}-?(?!0000)\d{4}\b/g,replacement:"[SSN_removed]"},creditCard:{pattern:/\b\d{4}[\s-]?\d{4}[\s-]?\d{4}[\s-]?\d{4}\b/g,replacement:"[credit_card_removed]"},address:{pattern:/\b\d+\s[A-Za-z0-9\s,.-]+(?:Street|St|Avenue|Ave|Road|Rd|Boulevard|Blvd|Lane|Ln|Drive|Dr|Court|Ct|Circle|Cir|Way|Place|Pl|Parkway|Pkwy|Terrace|Ter)\b/gi,replacement:"[address_removed]"},passport:{pattern:/\b[A-Z]{2}[0-9]{7}\b/g,replacement:"[passport_number_removed]"},driversLicense:{pattern:/\b[A-Z]{1,2}[0-9]{6,9}\b/g,replacement:"[driver_license_removed]"},zipCode:{pattern:/(?<!\d-)\b\d{5}(?:-\d{4})?\b(?!-\d)/g,replacement:"[zip_code_removed]"},bankAccount:{pattern:/\b\d{8,17}\b/g,replacement:"[bank_account_removed]"},dateOfBirth:{pattern:/\b(?:0[1-9]|1[0-2])[-/](?:0[1-9]|[12][0-9]|3[01])[-/](?:19|20)\d{2}\b/g,replacement:"[date_removed]"}};function l(n={}){const e={email:{enabled:!0,replacement:"[email_removed]"},phone:{enabled:!0,replacement:"[phone_removed]"},ssn:{enabled:!0,replacement:"[SSN_removed]"},creditCard:{enabled:!0,replacement:"[credit_card_removed]"},address:{enabled:!0,replacement:"[address_removed]"},passport:{enabled:!0,replacement:"[passport_number_removed]"},driversLicense:{enabled:!0,replacement:"[driver_license_removed]"},zipCode:{enabled:!0,replacement:"[zip_code_removed]"},bankAccount:{enabled:!0,replacement:"[bank_account_removed]"},dateOfBirth:{enabled:!0,replacement:"[date_removed]"}};for(const[r,t]of Object.entries(n))e[r]?e[r]={...e[r],...t}:e[r]=t;return e}function b(n,e={}){if(!m(n))return n;const r=l(e);let t=n;for(const[c,a]of Object.entries(r)){if(!a.enabled)continue;const d=s[c],o=d?.pattern||a.pattern,p=a.replacement||d?.replacement||"[PII removed]";o&&(t=t.replace(o,p))}return t}export{b as removePii};
|