@redocly/realm 0.136.0-next.9 → 0.137.0-next.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +217 -0
- package/dist/client/App.js +1 -1
- package/dist/client/ScriptLoader.js +1 -1
- package/dist/client/TestProvider.js +1 -1
- package/dist/client/app/Link.js +1 -1
- package/dist/client/app/Sidebar/useBreadcrumbs.js +1 -1
- package/dist/client/app/Sidebar/useSidebarItems.js +1 -1
- package/dist/client/app/Sidebar/utils.d.ts +1 -1
- package/dist/client/app/hooks/catalog/useCatalogClassic.js +1 -1
- package/dist/client/app/hooks/catalog/useCatalogFilter.js +1 -1
- package/dist/client/app/hooks/catalog/useCatalogSearch.js +1 -1
- package/dist/client/app/hooks/catalog/useCatalogSort.js +1 -1
- package/dist/client/app/hooks/products/useCurrentProduct.js +1 -1
- package/dist/client/app/hooks/useAutoScroll.js +1 -1
- package/dist/client/app/hooks/useBanner.js +1 -1
- package/dist/client/app/hooks/useL10nConfig.js +1 -1
- package/dist/client/app/hooks/useLoginUrl.js +1 -1
- package/dist/client/app/hooks/usePageTimeTracker.js +1 -1
- package/dist/client/app/hooks/useRouteChangeTracker.js +1 -1
- package/dist/client/app/markdoc/custom-components/openapi/replay-openapi.js +1 -1
- package/dist/client/app/pages/DevLogin/DevLogin.js +1 -1
- package/dist/client/app/search/useSearch.d.ts +1 -0
- package/dist/client/app/search/useSearch.js +1 -1
- package/dist/client/app/seo/hooks/useHreflangLinks.js +1 -1
- package/dist/client/app/useMobileMenu.js +1 -1
- package/dist/client/app/usePreloadHistory.d.ts +1 -1
- package/dist/client/app/usePreloadHistory.js +1 -1
- package/dist/client/app/utils/loadAndNavigate.d.ts +1 -1
- package/dist/client/browser-entry.js +2 -2
- package/dist/client/providers/hooks.d.ts +1 -1
- package/dist/client/providers/hooks.js +1 -1
- package/dist/client/providers/page-data/hooks.js +1 -1
- package/dist/client/providers/post-message/PostMessageProvider.js +1 -1
- package/dist/constants/api.d.ts +2 -0
- package/dist/constants/api.js +1 -1
- package/dist/server/constants/common.d.ts +2 -0
- package/dist/server/constants/common.js +1 -1
- package/dist/server/constants/plugins/search.d.ts +1 -1
- package/dist/server/constants/plugins/search.js +1 -1
- package/dist/server/esbuild/esbuild.js +1 -1
- package/dist/server/esbuild/plugins/themes-resolver.js +4 -2
- package/dist/server/plugins/dev-onboarding/template/App.js +1 -1
- package/dist/server/plugins/dev-onboarding/template/AppsList.js +1 -1
- package/dist/server/plugins/dev-onboarding/template/components/ApiKeyItem.js +1 -1
- package/dist/server/plugins/dev-onboarding/template/components/ApiLogDetails.js +1 -1
- package/dist/server/plugins/dev-onboarding/template/components/ApiLogs.js +1 -1
- package/dist/server/plugins/dev-onboarding/template/components/CreateApiKey.js +1 -1
- package/dist/server/plugins/dev-onboarding/template/components/DeleteAppDialog.js +1 -1
- package/dist/server/plugins/dev-onboarding/template/components/EditApis.js +1 -1
- package/dist/server/plugins/dev-onboarding/template/components/EditAppDescriptionDialog.js +1 -1
- package/dist/server/plugins/dev-onboarding/template/components/EditAppDialog.js +1 -1
- package/dist/server/plugins/dev-onboarding/template/components/EditCallbackUrlDialog.js +1 -1
- package/dist/server/plugins/dev-onboarding/template/components/RevokeAPIKey.js +1 -1
- package/dist/server/plugins/dev-onboarding/template/components/RollAPIKey.js +1 -1
- package/dist/server/plugins/dev-onboarding/template/components/UpdateApiKey.js +1 -1
- package/dist/server/plugins/dev-onboarding/template/index.js +1 -1
- package/dist/server/plugins/mcp/audit/audit-log.d.ts +36 -0
- package/dist/server/plugins/mcp/audit/audit-log.js +1 -0
- package/dist/server/plugins/mcp/audit/constants.d.ts +6 -0
- package/dist/server/plugins/mcp/audit/constants.js +1 -0
- package/dist/server/plugins/mcp/audit/secret-patterns.d.ts +2 -0
- package/dist/server/plugins/mcp/audit/secret-patterns.js +1 -0
- package/dist/server/plugins/mcp/auth/auth-handlers.d.ts +1 -1
- package/dist/server/plugins/mcp/auth/auth-handlers.js +1 -1
- package/dist/server/plugins/mcp/codemode/build-tool-list.d.ts +12 -0
- package/dist/server/plugins/mcp/codemode/build-tool-list.js +2 -0
- package/dist/server/plugins/mcp/codemode/capabilities/fetch/index.js +4 -4
- package/dist/server/plugins/mcp/codemode/capabilities/types.d.ts +1 -0
- package/dist/server/plugins/mcp/codemode/capabilities/utils.js +3 -3
- package/dist/server/plugins/mcp/codemode/code-execution-audit.d.ts +17 -0
- package/dist/server/plugins/mcp/codemode/code-execution-audit.js +1 -0
- package/dist/server/plugins/mcp/codemode/constants.js +1 -1
- package/dist/server/plugins/mcp/codemode/prompts.d.ts +6 -3
- package/dist/server/plugins/mcp/codemode/prompts.js +7 -4
- package/dist/server/plugins/mcp/codemode/sandbox/create-sandbox-setup.js +1 -1
- package/dist/server/plugins/mcp/codemode/sandbox/polyfills/fetch-shim.d.ts +6 -0
- package/dist/server/plugins/mcp/codemode/sandbox/polyfills/fetch-shim.js +54 -0
- package/dist/server/plugins/mcp/codemode/sandbox/polyfills/form-data.d.ts +3 -0
- package/dist/server/plugins/mcp/codemode/sandbox/polyfills/form-data.js +17 -0
- package/dist/server/plugins/mcp/codemode/sandbox/polyfills/index.d.ts +3 -0
- package/dist/server/plugins/mcp/codemode/sandbox/polyfills/index.js +2 -0
- package/dist/server/plugins/mcp/codemode/sandbox/polyfills/url-search-params.d.ts +3 -0
- package/dist/server/plugins/mcp/codemode/sandbox/polyfills/url-search-params.js +64 -0
- package/dist/server/plugins/mcp/codemode/sandbox/polyfills/url.d.ts +3 -0
- package/dist/server/plugins/mcp/codemode/sandbox/polyfills/url.js +239 -0
- package/dist/server/plugins/mcp/codemode/tools/describe-tools.js +1 -1
- package/dist/server/plugins/mcp/codemode/tools/execute.js +1 -1
- package/dist/server/plugins/mcp/codemode/tools/manage-credentials.d.ts +19 -0
- package/dist/server/plugins/mcp/codemode/tools/manage-credentials.js +2 -0
- package/dist/server/plugins/mcp/codemode/tools/tool-errors.d.ts +4 -0
- package/dist/server/plugins/mcp/codemode/tools/tool-errors.js +1 -0
- package/dist/server/plugins/mcp/constants.d.ts +2 -0
- package/dist/server/plugins/mcp/constants.js +1 -1
- package/dist/server/plugins/mcp/docs-mcp/tool-schemas.js +1 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/core/search.js +3 -3
- package/dist/server/plugins/mcp/docs-mcp/tools/openapi/constants.d.ts +1 -0
- package/dist/server/plugins/mcp/docs-mcp/tools/openapi/constants.js +1 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/openapi/endpoint-suggestions.d.ts +11 -0
- package/dist/server/plugins/mcp/docs-mcp/tools/openapi/endpoint-suggestions.js +1 -0
- package/dist/server/plugins/mcp/docs-mcp/tools/openapi/get-endpoint-info.js +1 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/openapi/get-endpoints.js +1 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/openapi/get-full-api-description.js +1 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/openapi/get-security-schemes.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/load-api-description.d.ts +5 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/openapi/load-api-description.js +1 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/openapi/types.d.ts +2 -0
- package/dist/server/plugins/mcp/docs-mcp/tools/openapi/utils.js +1 -1
- package/dist/server/plugins/mcp/docs-mcp/utils/api-name-matching.d.ts +8 -0
- package/dist/server/plugins/mcp/docs-mcp/utils/api-name-matching.js +1 -0
- package/dist/server/plugins/mcp/docs-mcp/{utils.d.ts → utils/resolve-refs.d.ts} +1 -4
- package/dist/server/plugins/mcp/docs-mcp/utils/resolve-refs.js +1 -0
- package/dist/server/plugins/mcp/gateway-mcp/elicitation.d.ts +35 -15
- package/dist/server/plugins/mcp/gateway-mcp/elicitation.js +3 -2
- package/dist/server/plugins/mcp/gateway-mcp/fetch/fetch-audit.d.ts +24 -0
- package/dist/server/plugins/mcp/gateway-mcp/fetch/fetch-audit.js +1 -0
- package/dist/server/plugins/mcp/gateway-mcp/fetch/fetch-bridge.js +1 -1
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/apply-edge-rate-limit.js +1 -1
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/edge-limiter.d.ts +2 -2
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/edge-limiter.js +1 -1
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/window-counter.d.ts +2 -2
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/window-counter.js +1 -1
- package/dist/server/plugins/mcp/gateway-mcp/secret-store.d.ts +3 -0
- package/dist/server/plugins/mcp/gateway-mcp/secret-store.js +1 -1
- package/dist/server/plugins/mcp/gateway-mcp/upstream-auth.d.ts +1 -0
- package/dist/server/plugins/mcp/gateway-mcp/upstream-auth.js +1 -1
- 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.js +47 -24
- 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.d.ts +1 -0
- package/dist/server/plugins/mcp/servers/mcp-server.js +3 -1
- package/dist/server/plugins/mcp/types.d.ts +2 -0
- package/dist/server/plugins/mcp/utils/xmcp-utils.d.ts +4 -0
- package/dist/server/plugins/mcp/utils/xmcp-utils.js +1 -1
- package/dist/server/plugins/mcp/utils.d.ts +11 -0
- package/dist/server/plugins/mcp/utils.js +1 -1
- package/dist/server/plugins/mcp/workers/execute-mcp-tool.js +1 -1
- package/dist/server/plugins/mcp/workers/mcp-tool-telemetry.d.ts +11 -0
- package/dist/server/plugins/mcp/workers/mcp-tool-telemetry.js +1 -1
- package/dist/server/plugins/scorecard-classic/template/ApiDetailsPage.js +1 -1
- package/dist/server/plugins/scorecard-classic/template/RuleDetailsPage.js +1 -1
- package/dist/server/plugins/scorecard-classic/template/index.js +1 -1
- package/dist/server/plugins/scorecard-classic/template/utils.d.ts +1 -1
- 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/ssr/render.js +1 -1
- package/dist/server/tools/notifiers/formatter.d.ts +1 -0
- package/dist/server/tools/notifiers/formatter.js +3 -3
- package/dist/server/tools/notifiers/logger.d.ts +1 -0
- package/dist/server/tools/notifiers/logger.js +2 -2
- package/dist/server/types/plugin-hooks.d.ts +1 -1
- package/dist/server/utils/llmstxt/agent-feedback-llms-footer.js +1 -1
- package/dist/server/web-server/routes/ask-ai.d.ts +11 -0
- package/dist/server/web-server/routes/ask-ai.js +1 -1
- package/dist/server/web-server/routes/index.js +1 -1
- package/dist/server/web-server/routes/mcp-routes/mcp-oauth.js +1 -1
- package/dist/server/web-server/routes/mcp-routes/mcp-server-card.js +1 -1
- package/dist/server/web-server/utils/get-request-origin.d.ts +1 -0
- package/dist/server/web-server/utils/get-request-origin.js +1 -1
- package/dist/types/api.d.ts +3 -0
- package/package.json +20 -20
- package/dist/server/plugins/mcp/codemode/sandbox/polyfills.d.ts +0 -2
- package/dist/server/plugins/mcp/codemode/sandbox/polyfills.js +0 -99
- package/dist/server/plugins/mcp/docs-mcp/utils.js +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{secretStore as
|
|
1
|
+
import{secretStore as s,ELICITATION_TTL_MS as x}from"../gateway-mcp/secret-store.js";import{buildAllowedHostMatchers as P}from"../gateway-mcp/fetch/allowed-hosts.js";import{assertUrlAllowed as _}from"../gateway-mcp/fetch/ssrf-guard.js";import{readCappedBody as E,getDefaultAgent as T}from"../gateway-mcp/fetch/fetch-bridge.js";const p={"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'; form-action 'self'"},R=3e4,z=64*1024;let $=fetch;function Q(e){$=e}const F=async(e,t)=>{const n=await t.getKv();if(e.method==="GET"){const o=new URL(e.url).searchParams.get("token")??"",r=await s.peekElicitation(n,o);return r?new Response(j(r,o),{status:200,headers:p}):u()}if(e.method==="POST"){const o=await e.formData(),r=String(o.get("token")??""),m=String(o.get("mode")??"token");return m==="client-credentials"?M(n,o,r):m==="clear"?B(n,r):O(n,o,r)}return new Response("Method Not Allowed",{status:405,headers:{Allow:"GET, POST"}})};async function O(e,t,n){const o=String(t.get("secret")??"");if(!o)return u();const r=await s.consumeElicitation(e,n);return r?(await s.setSecret(e,r.subject,r.api,H(r.auth,o)),new Response(A(r.name),{status:200,headers:p})):u()}async function B(e,t){const n=await s.consumeElicitation(e,t);return n?(await s.deleteSecret(e,n.subject,n.api),new Response(D(n.name),{status:200,headers:p})):u()}async function M(e,t,n){const o=String(t.get("client_id")??"").trim(),r=String(t.get("client_secret")??"").trim();if(!o||!r)return u();const m=await s.peekElicitation(e,n);if(!m||m.auth.kind!=="oauth2ClientCredentials")return u();const i=await s.consumeElicitation(e,n);if(!i||i.auth.kind!=="oauth2ClientCredentials")return u();const b=i.auth;try{const S=P([{url:b.tokenUrl}]),C=_(b.tokenUrl,S),k=new AbortController,I=setTimeout(()=>k.abort(),R);let g;try{g=await $(C,{method:"POST",headers:{"content-type":"application/x-www-form-urlencoded"},body:new URLSearchParams({grant_type:"client_credentials",client_id:o,client_secret:r,...b.scopes.length>0?{scope:b.scopes.join(" ")}:{}}),redirect:"manual",signal:k.signal,dispatcher:T()})}finally{clearTimeout(I)}if(!g.ok)return f(i.name);let v;try{v=await E(g,z)}catch{return f(i.name)}let h;try{h=JSON.parse(v)}catch{return f(i.name)}const w=typeof h=="object"&&h!==null&&"access_token"in h?h.access_token:void 0;return typeof w!="string"||!w?f(i.name):(await s.setSecret(e,i.subject,i.api,{header:"Authorization",value:`Bearer ${w}`}),new Response(A(i.name),{status:200,headers:p}))}catch{return f(i.name)}}function H(e,t){return e.kind==="apiKey"?{header:e.header,value:t}:e.kind==="bearer"||e.kind==="oauth2ClientCredentials"?{header:"Authorization",value:N(t)}:{header:"Authorization",value:t}}function N(e){const t=e.trim();return t.toLowerCase().startsWith("bearer")?t:`Bearer ${t}`}function a(e){return e.replaceAll("&","&").replaceAll("<","<").replaceAll(">",">").replaceAll('"',""")}function c(e){return`<!doctype html>
|
|
2
2
|
<html lang="en">
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="utf-8">
|
|
@@ -20,6 +20,9 @@ input:focus{outline:none;border-color:#4f46e5;box-shadow:0 0 0 3px rgba(79,70,22
|
|
|
20
20
|
button{margin-top:1.25rem;padding:.625rem 1.5rem;font-size:1rem;font-weight:600;color:#fff;background:#4f46e5;border:none;border-radius:.5rem;cursor:pointer}
|
|
21
21
|
button:hover{background:#4338ca}
|
|
22
22
|
button:focus-visible{outline:2px solid #4f46e5;outline-offset:2px}
|
|
23
|
+
button.danger{background:#b91c1c}
|
|
24
|
+
button.danger:hover{background:#991b1b}
|
|
25
|
+
button.danger:focus-visible{outline-color:#b91c1c}
|
|
23
26
|
code{background:#f3f4f6;padding:.125rem .375rem;border-radius:.25rem;font-size:.85em}
|
|
24
27
|
footer{margin-top:1.5rem;padding-top:1rem;border-top:1px solid #e5e7eb;font-size:.75rem;color:#9ca3af;text-align:center}
|
|
25
28
|
@media (prefers-color-scheme:dark){
|
|
@@ -34,34 +37,47 @@ footer{border-top-color:#1f2937;color:#6b7280}
|
|
|
34
37
|
</style>
|
|
35
38
|
</head>
|
|
36
39
|
<body><div class="card">${e}</div></body>
|
|
37
|
-
</html>`}function
|
|
38
|
-
|
|
40
|
+
</html>`}function d(e){return`<h1>\u{1F512} ${a(e)}</h1>`}function l(){return"<footer>Secured by Redocly · credentials never enter the AI conversation</footer>"}function y(){return`<p class="hint">This link expires ${Math.round(x/6e4)} minutes after it was issued. If it stops working, ask your AI client for a new one.</p>`}function j(e,t){const n=e.hasExistingSecret?q(t):"";switch(e.auth.kind){case"bearer":return L(e.name,t,n);case"apiKey":return U(e.name,t,e.auth.header,n);case"oauth2ClientCredentials":return G(e.name,t,e.auth.scopes,n);default:return K(e.name,t,n)}}function q(e){return`
|
|
41
|
+
<div class="section">
|
|
42
|
+
<h2>Remove stored credentials</h2>
|
|
43
|
+
<p class="hint">This API already has credentials stored. Save above to replace them, or remove them to make calls anonymous again.</p>
|
|
44
|
+
<form method="post" action="/mcp/credentials" autocomplete="off">
|
|
45
|
+
<input type="hidden" name="token" value="${a(e)}">
|
|
46
|
+
<input type="hidden" name="mode" value="clear">
|
|
47
|
+
<button class="danger" type="submit">Remove credentials</button>
|
|
48
|
+
</form>
|
|
49
|
+
</div>`}function L(e,t,n){return c(`
|
|
50
|
+
${d(`Credentials for ${e}`)}
|
|
39
51
|
<p class="hint">Stored encrypted for you only (24 hours for anonymous callers, 30 days when signed in) and sent to the API as the <code>Authorization</code> header. It never passes through the AI conversation.</p>
|
|
40
52
|
<form method="post" action="/mcp/credentials" autocomplete="off">
|
|
41
|
-
<input type="hidden" name="token" value="${
|
|
53
|
+
<input type="hidden" name="token" value="${a(t)}">
|
|
42
54
|
<input type="hidden" name="mode" value="token">
|
|
43
55
|
<label for="secret">API token</label>
|
|
44
56
|
<input type="password" id="secret" name="secret" placeholder="your API token" required autofocus>
|
|
45
57
|
<p class="hint">Paste the raw token or one already prefixed with <code>Bearer</code> — we add the prefix automatically if it is missing.</p>
|
|
46
58
|
<button type="submit">Save credentials</button>
|
|
47
59
|
</form>
|
|
48
|
-
${
|
|
49
|
-
${
|
|
50
|
-
|
|
60
|
+
${n}
|
|
61
|
+
${y()}
|
|
62
|
+
${l()}`)}function U(e,t,n,o){return c(`
|
|
63
|
+
${d(`Credentials for ${e}`)}
|
|
64
|
+
<p class="hint">Stored encrypted for you only (24 hours for anonymous callers, 30 days when signed in) and sent to the API as the <code>${a(n)}</code> header. It never passes through the AI conversation.</p>
|
|
51
65
|
<form method="post" action="/mcp/credentials" autocomplete="off">
|
|
52
|
-
<input type="hidden" name="token" value="${
|
|
66
|
+
<input type="hidden" name="token" value="${a(t)}">
|
|
53
67
|
<input type="hidden" name="mode" value="token">
|
|
54
|
-
<label for="secret">${
|
|
68
|
+
<label for="secret">${a(n)} value</label>
|
|
55
69
|
<input type="password" id="secret" name="secret" placeholder="value" required autofocus>
|
|
56
70
|
<button type="submit">Save credentials</button>
|
|
57
71
|
</form>
|
|
58
|
-
${
|
|
59
|
-
${
|
|
72
|
+
${o}
|
|
73
|
+
${y()}
|
|
74
|
+
${l()}`)}function G(e,t,n,o){const r=n.length>0?n.map(a).join(", "):"default scopes";return c(`
|
|
75
|
+
${d(`Credentials for ${e}`)}
|
|
60
76
|
<p class="hint">Paste a token you already have, or let us exchange client credentials for one via OAuth2 client_credentials.</p>
|
|
61
77
|
<div class="section">
|
|
62
78
|
<h2>I have a token</h2>
|
|
63
79
|
<form method="post" action="/mcp/credentials" autocomplete="off">
|
|
64
|
-
<input type="hidden" name="token" value="${
|
|
80
|
+
<input type="hidden" name="token" value="${a(t)}">
|
|
65
81
|
<input type="hidden" name="mode" value="token">
|
|
66
82
|
<label for="secret">API token</label>
|
|
67
83
|
<input type="password" id="secret" name="secret" placeholder="your API token" required autofocus>
|
|
@@ -71,9 +87,9 @@ ${c(`Credentials for ${e}`)}
|
|
|
71
87
|
</div>
|
|
72
88
|
<div class="section">
|
|
73
89
|
<h2>Exchange client credentials</h2>
|
|
74
|
-
<p class="hint">We request a token from the API on your behalf. Scopes: ${
|
|
90
|
+
<p class="hint">We request a token from the API on your behalf. Scopes: ${r}.</p>
|
|
75
91
|
<form method="post" action="/mcp/credentials" autocomplete="off">
|
|
76
|
-
<input type="hidden" name="token" value="${
|
|
92
|
+
<input type="hidden" name="token" value="${a(t)}">
|
|
77
93
|
<input type="hidden" name="mode" value="client-credentials">
|
|
78
94
|
<label for="client_id">Client ID</label>
|
|
79
95
|
<input type="text" id="client_id" name="client_id" required>
|
|
@@ -82,20 +98,27 @@ ${c(`Credentials for ${e}`)}
|
|
|
82
98
|
<button type="submit">Exchange & save</button>
|
|
83
99
|
</form>
|
|
84
100
|
</div>
|
|
85
|
-
${
|
|
86
|
-
${
|
|
101
|
+
${o}
|
|
102
|
+
${y()}
|
|
103
|
+
${l()}`)}function K(e,t,n){return c(`
|
|
104
|
+
${d(`Credentials for ${e}`)}
|
|
87
105
|
<p class="hint">The value is stored encrypted for you only (24 hours for anonymous callers, 30 days when signed in) and is sent to the API as the <code>Authorization</code> header. It never passes through the AI conversation.</p>
|
|
88
106
|
<form method="post" action="/mcp/credentials" autocomplete="off">
|
|
89
|
-
<input type="hidden" name="token" value="${
|
|
107
|
+
<input type="hidden" name="token" value="${a(t)}">
|
|
90
108
|
<input type="hidden" name="mode" value="token">
|
|
91
109
|
<label for="secret">Authorization header value</label>
|
|
92
110
|
<input type="password" id="secret" name="secret" placeholder="Bearer <your token>" required autofocus>
|
|
93
111
|
<button type="submit">Save credentials</button>
|
|
94
112
|
</form>
|
|
95
|
-
${
|
|
96
|
-
${
|
|
97
|
-
|
|
98
|
-
${d()}
|
|
99
|
-
${
|
|
100
|
-
|
|
101
|
-
${d(
|
|
113
|
+
${n}
|
|
114
|
+
${y()}
|
|
115
|
+
${l()}`)}function D(e){return c(`
|
|
116
|
+
${d("Credentials removed")}
|
|
117
|
+
<p>The stored credentials for ${a(e)} are gone. Calls to that API are anonymous again until you add new ones.</p>
|
|
118
|
+
${l()}`)}function A(e){return c(`
|
|
119
|
+
${d("Credentials saved")}
|
|
120
|
+
<p>Credentials for ${a(e)} are saved. Go back to your AI client and ask it to retry - or confirm the prompt it left open, if there is one. You can close this tab.</p>
|
|
121
|
+
${l()}`)}function f(e){return new Response(c(`
|
|
122
|
+
${d("Exchange failed")}
|
|
123
|
+
<p>We could not exchange your client credentials for a token for ${a(e)}. This link has been used up - go back to your AI client and request a new link, then try again.</p>
|
|
124
|
+
${l()}`),{status:502,headers:p})}function u(){return new Response(c(`${d("Link expired")}<p>This credentials link is invalid, already used, or older than ${Math.round(x/6e4)} minutes. Retry the request in your AI client to get a fresh link.</p>${l()}`),{status:404,headers:p})}var V=F;export{V as default,Q as setCredentialsFetchImpl};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{fileURLToPath as
|
|
1
|
+
import{fileURLToPath as q}from"node:url";import{dirname as I,join as p}from"node:path";import{logger as l}from"../../tools/notifiers/logger.js";import{reporter as G}from"../../tools/notifiers/reporter.js";import{isDefined as N}from"../../../utils/guards/is-defined.js";import{bundledOpenApiDocumentsToMcpOpenApi as H,bundledGraphqlDocumentsToMcpOpenApi as U,buildGraphqlDescriptions as j,collectIgnoredRoutes as x,filterIgnoredApiDescriptions as _,getCleanedUpApiDescriptions as F,isMcpInRedirects as B}from"./utils.js";import{getMcpMode as V,isMcpElicitationEnabled as J}from"./utils/mode.js";import{getDefaultToolSchemas as W}from"./docs-mcp/tool-schemas.js";import{EXECUTE_TOOL_SCHEMA as X}from"./codemode/tools/execute-schema.js";import{isGatewayCapabilityEnabled as $,isGatewayEligible as k}from"./gateway-mcp/eligibility.js";import{resolveGatewayFetchLimits as z}from"./gateway-mcp/rate-limit/limits.js";import{telemetryTraceStep as K}from"../../../cli/telemetry/helpers/trace-step.js";import{DEFAULT_DOCS_MCP_SERVER_NAME as v,MCP_NOT_ALLOWED_TEMPLATE_ID as Q}from"./constants.js";const y="mcp-docs-server-handler",Y="/mcp",A="mcp-credentials-handler",Z="/mcp/credentials",m=I(q(import.meta.url));async function ee(){let o=!1;return{id:"mcp",async processContent(t,r){o||await K("com.redocly.build.plugin.mcp",async a=>{const n=H(await t.loadApiDocuments(r)),f=U(await t.loadApiDocuments(r)),s=await r.getConfig(),{mcp:i,redirects:d}=s;if(a?.setAttribute("config",JSON.stringify(i||{})),!(i?.hide||i?.docs?.hide)&&(B(d)&&await G.panicOnBuildContentError('The reserved route "/mcp" cannot be used in redirect configuration. Please remove any redirects involving "/mcp" from your redocly.yaml config.'),t.createTemplate(Q,"@redocly/theme/layouts/McpNotAllowed"),!i?.docs?.hide)){l.info("Configuring MCP servers...");const u=p(m,"./handlers/docs-mcp-handler.js"),c=i?.docs?.ignore||[],h=F(_(n,c)),g=!!s?.access?.requiresLogin,D=s?.access?.rbac||{},R=$(i),E=new Map;for(const e of h){const L=e.definition.info?.title||"",w=e.definition.info?.version||"";E.set(e.relativePath,{name:L,description:typeof e.definition.info?.description=="string"?e.definition.info.description:"",version:w,servers:e.definition.servers||[],relativePath:e.relativePath,...R&&k(e.definition.info,e.relativePath,D)?{fetchEligible:!0}:{}})}const M=j(_(f,c)),b=Object.values(s.products||{}).map(e=>e?.name).filter(N),S=s.l10n?.locales?.map(e=>e.code)??r.fs.localeFolders,C=V(),P=J(),{budgetPerExec:T}=z(),O=W({products:b,locales:S,requiresLogin:g,rbac:D,hasGraphqlApis:M.length>0,elicitationEnabled:P});t.addMcpTools(p(m,"./docs-mcp/tools/index.js"),O),C==="code"&&t.addMcpTools(p(m,"./codemode/tools/execute.js"),[X]),await te({actions:t,handlerPath:u,apiDescriptionsMap:Object.fromEntries(E),graphqlDescriptions:M,mcpConfig:i,mcpMode:C,elicitationEnabled:P,gatewayFetchBudgetPerExec:T}),o=!0}})},async afterRoutesCreated(t,r){const a=await r.getConfig(),{mcp:n}=a;t.setGlobalData({mcpData:{docs:{enabled:!n?.hide&&!n?.docs?.hide,name:n?.docs?.name||v}}})}}}var ge=ee;async function te({actions:o,handlerPath:t,apiDescriptionsMap:r,graphqlDescriptions:a,mcpConfig:n,mcpMode:f,elicitationEnabled:s,gatewayFetchBudgetPerExec:i}){if(o.createRequestHandler(y,t),o.addApiRoute({slug:Y,requestHandlerId:y,httpMethod:"all",getStaticData:async(d,u)=>{const c=x(u.getAllRoutes(),n?.docs?.ignore||[]);return c.length>0&&l.verbose(`mcp.docs.ignore: hiding ${c.length} page routes from MCP search`),{props:{config:{apiDescriptionsMap:r,graphqlDescriptions:a,mcpDocsServerName:n?.docs?.name||v,mcpMode:f,elicitationEnabled:s,gatewayFetchBudgetPerExec:i,searchIgnoredRoutes:c},serverOutDir:o.serverOutDir,tools:o.getMcpTools().map(({importPath:h,...g})=>g)}}}}),l.info("Registered Docs MCP Server endpoint at /mcp"),s){const d=p(m,"./handlers/mcp-credentials-handler.js");o.createRequestHandler(A,d),o.addApiRoute({slug:Z,requestHandlerId:A,httpMethod:"all",getStaticData:async()=>({props:{}})}),l.info("Registered MCP credentials endpoint at /mcp/credentials")}}export{A as MCP_CREDENTIALS_HANDLER_ID,y as MCP_DOCS_SERVER_HANDLER_ID,ge as default,ee as mcpServerPlugin};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{fromJsonSchema as
|
|
1
|
+
import{fromJsonSchema as A}from"@modelcontextprotocol/server";import{logger as b}from"../../../tools/notifiers/logger.js";import{mcpToolWorkers as g,MCP_TOOL_IS_AVAILABLE_KEY as M}from"../../../workers/mcp-tool-worker-pool.js";import{CREATE_ANONYMOUS_SESSION_TOOL_NAME as L}from"../constants.js";import{isAnonymousSessionToolAvailable as T}from"../docs-mcp/tools/core/create-anonymous-session.js";import{isManageApiCredentialsToolAvailable as v,manageApiCredentials as D,manageApiCredentialsSchema as y}from"../codemode/tools/manage-credentials.js";import{EXECUTE_TOOL_SCHEMA as I}from"../codemode/tools/execute-schema.js";import{EXECUTE_TOOL_NAME as O,DESCRIBE_TOOLS_TOOL_NAME as N,CODE_MODE_TOOL_NAMES as H,FETCH_TOOL_NAME as k}from"../codemode/constants.js";import{buildCodeModeInstructions as w,buildExecuteDescription as x,DESCRIBE_TOOLS_DESCRIPTION as F}from"../codemode/prompts.js";import{toToolListEntries as R}from"../codemode/build-tool-list.js";import{composeExecuteAnnotations as P,getActiveCapabilities as B}from"../codemode/capabilities/index.js";import{describeToolsSchema as U,describeTools as z}from"../codemode/tools/describe-tools.js";import{mcpJsonSchemaValidator as J}from"../utils/json-schema-validator.js";import{connectMcpServer as V,createMcpServer as X,createToolDispatch as Y,extractSerializableContext as $}from"./mcp-server.js";function K(r){const t=I.schema;if(T(r))return t;const{sessionHandle:i,...m}=t.properties;return{...t,properties:m}}function W(r,t){const i=t.schema;if(T(r))return i;const{sessionHandle:m,...p}=i.properties;return{...i,properties:p}}async function me({name:r,tools:t,context:i,skills:m=[],getKv:p}){const s=i.mcpMode==="code",a=s?B(i):[],E=a.some(e=>e.id===k),l=s?t.filter(e=>!H.has(e.name)):[],u=R(l,a),_=s&&v(i),{server:n,transport:C}=X(r,s?w(E,u):void 0),c=e=>A(e,J),d=$(i),S={getClientCapabilities:()=>n.server.getClientCapabilities(),getKv:p},f=Y(d,S),h=async e=>{try{return await g.exec(M,[{toolName:e,context:d}],{timeout:1e4})}catch(o){return b.error(`Failed to check MCP tool availability for "${e}": ${o instanceof Error?o.message:String(o)}`),!1}};if(s){n.registerTool(O,{description:x(E,u),inputSchema:c(K(i)),annotations:P(a)},f(O)),n.registerTool(N,{description:F,inputSchema:c(U(l,a))},z(l,h,a,i));const e=t.find(o=>o.name===L);if(e&&T(i)&&n.registerTool(e.name,{description:e.description,inputSchema:c(e.schema),annotations:e.annotations??{title:e.name}},f(e.name)),_){const o=y(i);n.registerTool(o.name,{description:o.description,inputSchema:c(W(i,o)),annotations:o.annotations??{title:o.name}},D(d,S))}}else await Promise.all(t.map(async e=>{const o=n.registerTool(e.name,{description:e.description,inputSchema:c(e.schema),annotations:e.annotations||{title:e.name}},f(e.name));await h(e.name)||o.disable()}));for(const e of m)n.registerResource(e.slug,e.uri,{title:e.name,description:e.description,mimeType:"text/markdown"},async()=>({contents:[{uri:e.uri,mimeType:"text/markdown",text:e.content}]}));return V(n,C)}export{me as createDocsMcpServer};
|
|
@@ -1 +1,3 @@
|
|
|
1
|
-
import{McpServer as
|
|
1
|
+
import{McpServer as T,WebStandardStreamableHTTPServerTransport as q}from"@modelcontextprotocol/server";import{logger as g}from"../../../tools/notifiers/logger.js";import{mcpToolWorkers as I,MCP_TOOL_WORKER_KEY as v}from"../../../workers/mcp-tool-worker-pool.js";import{SSE_KEEPALIVE_INTERVAL_MS as R}from"../constants.js";import{secretStore as _}from"../gateway-mcp/secret-store.js";import{readAuthRequiredMeta as A,stripAuthRequiredMeta as b}from"../gateway-mcp/upstream-auth.js";import{buildCredentialsToolHint as O,buildUpstreamCredentialFallback as w,buildUpstreamCredentialInputRequired as U,isCredentialElicitationDeclined as C,targetOf as D}from"../gateway-mcp/elicitation.js";import{resolveUpstreamAuthScheme as j}from"../gateway-mcp/upstream-auth-scheme.js";import{MISSING_SESSION_HANDLE_MESSAGE as K,resolveSecretSubject as P}from"../gateway-mcp/subject.js";const L=6e4,S=new Map;function $(e,t){const r=S.get(e);if(r)return r;const n=t().finally(()=>{S.delete(e)});return S.set(e,n),n}function ee(e,t){const r=new T({name:e,version:new Date().toISOString().slice(0,10)},{capabilities:{logging:{}},...t?{instructions:t}:{}}),n=new q({keepAliveMs:R,sessionIdGenerator:void 0});return{server:r,transport:n}}async function te(e,t){return await e.connect(t),{server:e,transport:t,cleanup:async()=>{t.close()}}}function re(e,t){return r=>async(n,a)=>{g.info(`MCP tool called: ${r}`);const i=e.elicitationEnabled??!1,s=a.mcpReq.envelope!==void 0,c=i?P(e.user,n.sessionHandle):{kind:"anonymous"},o=c.kind==="resolved"?c.subject:void 0;if(c.kind==="invalid")return{content:[{type:"text",text:c.message}],isError:!0};const d=async()=>{if(!(!i||!o||!t?.getKv))try{const u=await t.getKv();return await _.getSecretsForSubject(u,o)}catch(u){g.warn(`gateway mcp secret store error, continuing unauthenticated: ${String(u)}`);return}};let m;const E=async()=>{m=await d();const u={toolName:r,args:n,context:{...e,upstreamSecrets:m},extra:N(a)};return await I.exec(v,[u],{timeout:L})};let p=await E();const l=A(p);if(l.length>0&&i&&!o)return b({...p,content:[{type:"text",text:K}],isError:!0});if(l.length>0&&i&&o&&t?.getKv){g.info(`gateway mcp credentials prompt: era=${s?"2026-07-28":"2025"} clientElicitation=${H(t)}`);const u=await t.getKv(),h=new Set(Object.keys(m??{})),f=s?await x(e,a,l,o,u,h,t):await B(e,l,o,u,h);switch(f.kind){case"inputRequired":return f.result;case"retry":p=await E();break;case"prependText":p={...p,content:[{type:"text",text:f.text},...p.content],isError:!0};break;case"none":break}}return b(p)}}function F(e){return!!e?.getClientCapabilities()?.elicitation?.url}function H(e){const t=e?.getClientCapabilities()?.elicitation;if(!t)return"none";const r=[t.form?"form":void 0,t.url?"url":void 0].filter(Boolean);return r.length>0?r.join("+"):"none"}function k(e,t){return e.status===401&&!t.has(e.api)}function y(e){return e.map(O).join(`
|
|
2
|
+
|
|
3
|
+
`)}async function M(e,t,r,n){const[a,...i]=t;return{subject:r,baseUrl:e.baseUrl??"",target:D(a),auth:await j(e,a.api),kv:n,hasExistingSecret:!1,reason:{kind:"authFailure",status:a.status,otherApiNames:i.map(s=>s.name)}}}async function x(e,t,r,n,a,i,s){if(C(t.mcpReq.inputResponses))return{kind:"none"};const c=r.filter(d=>k(d,i));if(c.length===0)return{kind:"prependText",text:y(r)};const o=await M(e,c,n,a);return F(s)?{kind:"inputRequired",result:await U(o)}:{kind:"prependText",text:await w(o)}}async function B(e,t,r,n,a){const i=t.filter(o=>k(o,a));if(i.length===0)return{kind:"prependText",text:y(t)};const s=await M(e,i,r,n);return{kind:"prependText",text:await $(`${r}:${i[0].api}`,()=>w(s))}}function N(e){return{sessionId:e.sessionId,authInfo:e.http?.authInfo,requestId:e.mcpReq.id,_meta:e.mcpReq._meta}}function ne(e){return{user:e.user,config:e.config,outdir:e.outdir,baseUrl:e.baseUrl,params:e.params,query:e.query,cookies:e.cookies,apiDescriptionsMap:e.apiDescriptionsMap,graphqlDescriptions:e.graphqlDescriptions,products:e.products,accessToken:e.accessToken,metadata:e.metadata,upstreamAuthorization:e.upstreamAuthorization,mcpMode:e.mcpMode,elicitationEnabled:e.elicitationEnabled,gatewayFetchBudgetPerExec:e.gatewayFetchBudgetPerExec,clientIp:e.clientIp,upstreamSecrets:e.upstreamSecrets,searchIgnoredRoutes:e.searchIgnoredRoutes}}export{te as connectMcpServer,ee as createMcpServer,re as createToolDispatch,ne as extractSerializableContext};
|
|
@@ -28,6 +28,7 @@ export type McpDocsStaticDataPropsConfig = {
|
|
|
28
28
|
mcpMode: McpMode;
|
|
29
29
|
elicitationEnabled: boolean;
|
|
30
30
|
gatewayFetchBudgetPerExec: number;
|
|
31
|
+
searchIgnoredRoutes?: string[];
|
|
31
32
|
};
|
|
32
33
|
export type McpDocsStaticData = PageStaticData & {
|
|
33
34
|
props: {
|
|
@@ -98,6 +99,7 @@ export type McpToolContext = Omit<ApiFunctionsContext, 'telemetry' | 'getKv' | k
|
|
|
98
99
|
gatewayFetchBudgetPerExec?: number;
|
|
99
100
|
clientIp?: string;
|
|
100
101
|
upstreamSecrets?: Record<string, StoredSecret>;
|
|
102
|
+
searchIgnoredRoutes?: string[];
|
|
101
103
|
};
|
|
102
104
|
export type McpToolHandler<TArgs extends ToolArgs = ToolArgs> = (args: TArgs, context: McpToolContext, extra: McpToolExtra) => Promise<McpToolWorkerResponse>;
|
|
103
105
|
export type McpToolIsAvailable = (context: McpToolContext) => boolean | Promise<boolean>;
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import type { OpenAPIDefinition } from '@redocly/api-docs';
|
|
2
2
|
import type { XMcpConfig, XMcpSection } from '../types.js';
|
|
3
|
+
/** Whether the path or operation is hidden for `section`. */
|
|
4
|
+
export declare function isEndpointHidden(endpoint: {
|
|
5
|
+
'x-mcp'?: XMcpConfig;
|
|
6
|
+
} | undefined, section: XMcpSection): boolean;
|
|
3
7
|
/**
|
|
4
8
|
* Returns false when the endpoint is hidden for `section`; otherwise strips x-mcp from the
|
|
5
9
|
* output and returns true.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
function
|
|
1
|
+
function n(e,t){return!!e?.["x-mcp"]?.[t]?.hide}function i(e,t){return n(e,t)?!1:(e&&delete e["x-mcp"],!0)}function o(e,t){if(!e)return!1;const r=e["x-mcp"];return!r||typeof r!="object"?!1:t?r[t]?.hide===!0:r.docs?.hide===!0}function c(e){if(!e)return!1;const t=e["x-mcp"];return!!(t&&typeof t=="object"&&t.gateway)}export{i as checkEndpointAndDeleteXMcp,c as hasGatewayConfig,o as isDefinitionHidden,n as isEndpointHidden};
|
|
@@ -55,6 +55,17 @@ export declare function buildGraphqlDescriptions(definitions: McpGraphqlSpec[]):
|
|
|
55
55
|
export declare function filterIgnoredApiDescriptions<T extends {
|
|
56
56
|
relativePath: string;
|
|
57
57
|
}>(apiDescriptions: T[], ignoredPaths: string[]): T[];
|
|
58
|
+
/**
|
|
59
|
+
* Registered page routes whose source file `mcp.docs.ignore` matches, as exact route slugs
|
|
60
|
+
* for the `search` tool to drop. The catalog tools filter definitions by path; `search` reads
|
|
61
|
+
* the site-wide semantic index, which only knows page URLs — so the affected routes are looked
|
|
62
|
+
* up in the route table at static-data time rather than derived from file paths (a derived
|
|
63
|
+
* slug bypasses the content-slugs transforms and cannot see operation pages).
|
|
64
|
+
*/
|
|
65
|
+
export declare function collectIgnoredRoutes(routes: {
|
|
66
|
+
fsPath?: string;
|
|
67
|
+
slug: string;
|
|
68
|
+
}[], ignoredPaths: string[]): string[];
|
|
58
69
|
/**
|
|
59
70
|
* Checks if the MCP route (/mcp) appears in redirect configuration.
|
|
60
71
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import
|
|
1
|
+
import u,{join as l}from"node:path";import s from"picomatch";import{PUBLIC_API_DEFINITIONS_FOLDER as m,L10N_DIR_NAME as p,I18N_DIR_NAME as c}from"../../constants/common.js";import{RESERVED_ROUTES as h}from"../../plugins/get-reserved-routes.js";import{removeL10nPrefix as D}from"../../fs/utils/remove-l10n-prefix.js";import{removeTrailingSlash as g}from"../../../utils/url/remove-trailing-slash.js";import{slash as A}from"../../../utils/path/slash.js";import{canDownloadApiDefinition as d}from"../../utils/rbac.js";function T(e){return e.filter(t=>t.type==="openapi").map(t=>({relativePath:t.relativePath,definition:t.document}))}function W(e){return e.filter(t=>t.type==="graphql").map(t=>({relativePath:t.relativePath,definition:t.document,options:t.options}))}function f(e){if(typeof e!="object"||e===null)return e;if(Array.isArray(e))return e.map(f);const t={};for(const i in e)if(Object.hasOwn(e,i)){if(i.toString().startsWith("x-parsed-"))continue;t[i]=f(e[i])}return t}function b(e){return e.reduce((t,i)=>(i.relativePath.startsWith(p)||i.relativePath.startsWith(c)||!i.definition||typeof i.definition!="object"||!("paths"in i.definition)||i.definition?.paths&&Object.keys(i.definition.paths).length>0&&t.push({...i,definition:f(i.definition)}),t),[])}function M(e,t,i,r){const n={};for(const[o,a]of Object.entries(e))d(l(m,a.relativePath),i,r,t)&&(n[o]=a);return n}function N(e,t,i,r){return e.filter(n=>d(l(m,n.relativePath),i,r,t))}function S(e){return e.filter(({relativePath:t})=>!t.startsWith(p)&&!t.startsWith(c)).map(({relativePath:t,options:i})=>({name:i.info?.title||u.basename(t,u.extname(t)),description:i.info?.description,relativePath:t}))}function v(e,t){const i=s(t||[]);return e.filter(({relativePath:r})=>!i(r))}function k(e,t){if(!t?.length)return[];const i=s(t),r=e.filter(({fsPath:n})=>{if(!n)return!1;const o=A(n);return i(o)||i(D(o))}).map(({slug:n})=>g(n));return[...new Set(r)].sort()}function q(e={}){for(const[t,i]of Object.entries(e))if(t===h.mcp||(typeof i=="string"?i:i.to)===h.mcp)return!0;return!1}function w(e,t,i){return e.startsWith(p)||e.startsWith(c)||!t?.paths||Object.keys(t.paths).length===0?!1:!s(i?.docs?.ignore||[])(e)}export{S as buildGraphqlDescriptions,W as bundledGraphqlDocumentsToMcpOpenApi,T as bundledOpenApiDocumentsToMcpOpenApi,k as collectIgnoredRoutes,M as filterApiDescriptionsByRbac,N as filterGraphqlDescriptionsByRbac,v as filterIgnoredApiDescriptions,b as getCleanedUpApiDescriptions,w as isApiIncludedInDocsMcp,q as isMcpInRedirects};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{telemetry as
|
|
1
|
+
import{telemetry as h}from"../../../telemetry/index.js";import{mcpToolHandlers as y}from"../../../../client/mcp-tool-handlers-entry.js";import{McpServerType as c}from"../constants.js";import{EXECUTE_TOOL_NAME as T}from"../codemode/constants.js";import{logMcpToolCallAudit as M,reportMcpToolCalled as C,reportMcpToolError as u}from"./mcp-tool-telemetry.js";function E(e){return e.content.map(o=>o.type==="text"?o.text:"")}async function j(e){h.initialize();const{toolName:o,args:a,context:l,extra:r}=e,n=l?.mcpMode??"tools",s=performance.now();try{const t=y[o];if(!t)throw new Error(`Unknown MCP tool: ${o}`);const{default:x}=await t(),i=x[o];if(!i)throw new Error(`MCP tool module does not export a handler for "${o}". Expected \`export default { '${o}': handler }\`.`);const f=await(typeof i=="function"?i:i.execute)(a,l,r);if(!v(f))throw new Error(`MCP tool "${o}" returned an invalid result.`);const m=Math.round(performance.now()-s),p=f.isError?o===T?"sandbox_error":"tool_error":void 0,d=E(f),w=d.join("");return M({tool:o,mode:n,serverType:c.Docs,args:a,result:w,errorClass:p}),p?u({tool:o,message:d.join(" "),mode:n,serverType:c.Docs,durationMs:m,errorClass:p}):C({tool:o,mode:n,serverType:c.Docs,durationMs:m,outputLength:w.length}),f}catch(t){throw M({tool:o,mode:n,serverType:c.Docs,args:a,errorClass:"server_error"}),u({tool:o,message:t instanceof Error?t.message:String(t),mode:n,serverType:c.Docs,durationMs:Math.round(performance.now()-s),stack:t instanceof Error&&t.stack||"",errorClass:"server_error"}),t}}function v(e){return!e||typeof e!="object"?!1:Array.isArray(e.content)}async function P(e){h.initialize();const{toolName:o,context:a}=e,l=performance.now();try{const r=y[o];if(!r)return!1;const{default:n}=await r(),s=n[o];return s?typeof s=="object"&&typeof s.isAvailable=="function"?await s.isAvailable(a):!0:!1}catch(r){throw u({tool:o,message:"Failed to check if MCP tool is available: "+(r instanceof Error?r.message:String(r)),mode:a?.mcpMode??"tools",serverType:c.Docs,durationMs:Math.round(performance.now()-l),stack:r instanceof Error&&r.stack||"",errorClass:"server_error"}),r}}export{j as executeMcpTool,P as isMcpToolAvailable};
|
|
@@ -15,6 +15,17 @@ export type McpErrorClass = 'tool_error' | 'sandbox_error' | 'server_error';
|
|
|
15
15
|
export declare function reportMcpToolCalled({ tool, mode, serverType, durationMs, outputLength, }: McpToolEvent & {
|
|
16
16
|
outputLength: number;
|
|
17
17
|
}): void;
|
|
18
|
+
/**
|
|
19
|
+
* Arguments and result identity for one MCP tool call. `tool` and `mode` repeat the
|
|
20
|
+
* `mcpServer.toolCalled` telemetry event so a Grafana row joins onto this line; `args_sha256`
|
|
21
|
+
* identifies the invocation. The result body itself is never recorded — a tool can return
|
|
22
|
+
* credentials no pattern will recognise — so only its digest lands here.
|
|
23
|
+
*/
|
|
24
|
+
export declare function logMcpToolCallAudit({ tool, mode, serverType, args, result, errorClass, }: Omit<McpToolEvent, 'durationMs'> & {
|
|
25
|
+
args: unknown;
|
|
26
|
+
result?: string;
|
|
27
|
+
errorClass?: McpErrorClass;
|
|
28
|
+
}): void;
|
|
18
29
|
export declare function reportMcpToolError({ tool, mode, serverType, durationMs, message, stack, errorClass, }: McpToolEvent & {
|
|
19
30
|
message: string;
|
|
20
31
|
stack?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{telemetry as
|
|
1
|
+
import{telemetry as u}from"../../../telemetry/index.js";import{serverAttributes as l}from"../utils/telemetry-attributes.js";import{EXECUTE_TOOL_NAME as c}from"../codemode/constants.js";import{auditInput as d,auditOutputDigest as p,auditSha256 as f,logAuditRecord as g}from"../audit/audit-log.js";function E({tool:r,mode:e,serverType:o,durationMs:s,outputLength:t}){u.sendMcpToolCalledMessage([{...l(o),tool:r,mode:e,output_length:t,duration_ms:s}])}function T({tool:r,mode:e,serverType:o,args:s,result:t,errorClass:n}){if(r===c)return;const i=m(s),a=t===void 0?void 0:p(t);g("Record MCP tool call",{tool:r,mode:e,server_type:o,error_class:n,args_sha256:f(i),args:d(i),result_sha256:a?.sha256,result_bytes:a?.bytes})}function m(r){try{return JSON.stringify(r)??String(r)}catch{return"\xAB[unserializable]\xBB"}}function A({tool:r,mode:e,serverType:o,durationMs:s,message:t,stack:n="",errorClass:i}){u.sendMcpErrorMessage([{...l(o),tool:r,message:t,stack:n,error_class:i,mode:e,duration_ms:s}])}export{T as logMcpToolCallAudit,E as reportMcpToolCalled,A as reportMcpToolError};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import*as t from"react";import{useParams as p}from"react-router
|
|
1
|
+
import*as t from"react";import{useParams as p}from"react-router";import{useMemo as u}from"react";import{ApiPage as s}from"./views";import{useData as c}from"./useData";function I(r){const{apiSlug:e}=p(),{apis:o,scorecardInfo:n,teamLabel:i,catalogConfig:l}=c(r),a=u(()=>e?o.find(m=>m.api.link===`/${decodeURIComponent(e)}`):void 0,[o,e]);return a?t.createElement(s,{catalogSlug:l.slug,slug:`/${decodeURIComponent(e||"")}`,api:a,teamLabel:i,rulesPerLevel:n.rulesPerLevel}):t.createElement("div",null,"API not found")}export{I as ApiDetailPage};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{useParams as n}from"react-router
|
|
1
|
+
import{useParams as n}from"react-router";import{useMemo as f}from"react";import*as l from"react";import{useData as d}from"./useData";import{RuleView as c}from"./views";function R(o){const{problemsByRule:a,hasTeam:r,hasPublishedAt:u,teamLabel:m,catalogConfig:s}=d(o),{ruleId:e}=n(),t=f(()=>e?a.find(i=>i.ruleId===e):void 0,[a,e]);return!e||!t?l.createElement("div",null,"Rule not found"):l.createElement(c,{catalogSlug:s.slug,slug:e,data:t,hasTeam:r,hasPublishedAt:u,teamLabel:m})}export{R as RuleDetailPage};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{Routes as a,Route as r}from"react-router
|
|
1
|
+
import{Routes as a,Route as r}from"react-router";import*as e from"react";import"react-date-picker/dist/DatePicker.css";import"react-calendar/dist/Calendar.css";import{ApiDetailPage as o}from"./ApiDetailsPage";import{RuleDetailPage as m}from"./RuleDetailsPage";import{ScorecardDashboard as p}from"./ScorecardDashboard";function l(t){return e.createElement(a,null,e.createElement(r,{path:"/",element:e.createElement(p,{pageProps:t.pageProps})}),e.createElement(r,{path:"/apis/:apiSlug",element:e.createElement(o,{pageProps:t.pageProps})}),e.createElement(r,{path:"/rules/:ruleId",element:e.createElement(m,{pageProps:t.pageProps})}),";")}export{l as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import*as e from"react";import{useCallback as H,useMemo as b,useState as G,useEffect as _}from"react";import{useLocation as T}from"react-router
|
|
1
|
+
import*as e from"react";import{useCallback as H,useMemo as b,useState as G,useEffect as _}from"react";import{useLocation as T}from"react-router";import{Flex as U}from"@redocly/portal-legacy-ui";import{Button as x}from"@redocly/theme/components/Button/Button";import{AddIcon as I}from"@redocly/theme/icons/AddIcon/AddIcon";import{SubtractIcon as D}from"@redocly/theme/icons/SubtractIcon/SubtractIcon";import{ArrowLeftIcon as K}from"@redocly/theme/icons/ArrowLeftIcon/ArrowLeftIcon";import{getScorecardColorVariable as z,withoutPathPrefix as O}from"@redocly/theme/core/utils";import{Link as P}from"../../../../client/app/Link";import N from"../../../../client/app/CircularProgress";import{isDefined as R}from"../../../../utils/guards/is-defined.js";import{removeLeadingSlash as Z}from"../../../../utils/url/remove-leading-slash.js";import{StatusByLevelWidget as J}from"./StatusByLevelWidget";import{OTHER_TEAMS_LABEL as Q,NON_CONFORMANT as X}from"./utils";import{LevelIndicator as Y}from"./LevelIndicator";import{AppPageWrapper as V,CardValue as v,CardsWrapper as j,CatalogDescription as ee,ModeSwitcherTab as te,ModeSwitcherTabs as re,CardRow as B,ProblemsByStatusCardBody as W,ScoreCardStatusCardBody as F,TableWrap as ne,LevelComplianceCardTitle as le,ContentWithDotWrap as C,ScorecardCard as S,ScorecardCardTitle as w}from"./index.styles";import{ApiLevel as M,InstanceStatus as k,LevelStatus as $,RuleStatus as q}from"./components";import{Grid as A}from"./Grid/Grid";import{useDetailedScorecard as ae}from"./useDetailedScorecard";import{Gauge as se,GaugeValue as ce}from"./Gauge";function Te(p){const u=T(),{data:d,levelNames:i,hasPublishedAt:n,hasTeam:s,teamLabel:l}=p,f=H((a,c,E)=>{const g=a.getValue(E)?new Date(a.getValue(E)).getTime():0,t=c.getValue(E)?new Date(c.getValue(E)).getTime():0;return g>t?1:-1},[]),m=b(()=>[{id:"title",header:"API",accessorKey:"api.title",size:200,cell:({getValue:a,row:c})=>e.createElement(P,{to:O(u.pathname)+"/apis/"+encodeURIComponent(Z(c.original.api.link))},a())},n?{header:"Published at",accessorKey:"api.publishedAt",sortingFn:f,cell:({getValue:a})=>{const c=a();return c?new Date(c).toLocaleDateString():"-"}}:void 0,s?{header:l,accessorKey:"api.team"}:void 0,{id:"level",header:"Level",accessorKey:"scorecard.scorecardLevel",cell:({getValue:a,row:c})=>e.createElement(M,{level:a(),colorVariable:z(c.original?.scorecard.scorecardLevelIdx,i.length+1)})},...i.map(a=>({id:a,header:`${a}`,accessorKey:"scorecard.levels",cell:({getValue:c,row:E})=>{const g=c(),t=E.original.api.link;return g?.[a]?e.createElement(Y,{key:t,uniqueErrors:g[a].uniqueErrors,uniqueWarnings:g[a].uniqueWarnings,id:t}):null}}))].filter(R),[f,i,u.pathname,n,s,l]);return e.createElement(A,{columns:m,data:d,sortBy:[{id:"title",desc:!1}]})}function Ie(p){const u=T(),{data:d}=p,i=b(()=>[{header:"Rules",accessorKey:"ruleId",cell:({getValue:n})=>e.createElement(P,{to:O(u.pathname)+"/rules/"+encodeURIComponent(n())},n())},{id:"status",header:"Status",accessorKey:"status",size:200,cell:({row:n})=>e.createElement(q,{errors:n.original.errorApisCount,warnings:n.original.warningApisCount})},{header:"Problem APIs",size:200,accessorKey:"apis",cell:({getValue:n})=>n().length,sortDescFirst:!0},{header:"Problem count",size:200,accessorKey:"count",sortDescFirst:!0}],[u.pathname]);return e.createElement(A,{columns:i,data:d,sortBy:[{id:"status",desc:!0}]})}function De(p){const{data:u,levelNames:d,filters:i,setActiveTab:n,teamLabel:s,teamProperty:l}=p,f=b(()=>[{id:"team",header:`API ${s}`,accessorKey:"team",size:200,cell:({getValue:m})=>e.createElement("a",{href:"#",onClick:a=>{a.preventDefault(),n("apis"),i.find(c=>c.property===l)?.selectOption(m())}},m())},...[X,...d].map(m=>({id:m,header:`${m}`,accessorFn:a=>a.levels[m]?.apis}))],[i,d,n,s,l]);return e.createElement(A,{columns:f,data:u,sortBy:[{id:"team",desc:!1}],groupHeaderTitle:"APIs by level"})}function oe(p){const{data:u,title:d}=p,i=b(()=>[{id:"expand",maxSize:40,size:40,header:()=>null,enableSorting:!1,cell:({row:n})=>n.getCanExpand()?e.createElement(x,{onClick:n.getToggleExpandedHandler(),variant:"text",size:"medium",icon:n.getIsExpanded()?e.createElement(D,null):e.createElement(I,null)}):null},{header:"Rules",accessorKey:"ruleId",cell:({getValue:n,row:s})=>s.getCanExpand()?e.createElement("span",{onClick:s.getToggleExpandedHandler()},n()):null},{header:"Status",accessorKey:"status",size:200,cell:({getValue:n})=>{const s=n();return e.createElement(q,{errors:s?.errorsCount,warnings:s?.warningsCount})},enableSorting:!1},{header:"Problem count",accessorKey:"problemsCount",size:200,sortDescFirst:!0}],[]);return e.createElement(A,{columns:i,data:u,sortBy:[{id:"ruleId",desc:!1}],empty:e.createElement(e.Fragment,null,"\u2705 This API is compliant with ",e.createElement("strong",null,d)," level rules"),subRowKey:"problems"})}function Ke(p){const{catalogSlug:u,slug:d,data:i,hasTeam:n,hasPublishedAt:s,teamLabel:l}=p,{apis:f,apisCount:m,warningApisCount:a,errorApisCount:c,levels:E,count:g}=i,t=f.length===0,h=t?void 0:{id:"expand",maxSize:40,size:40,header:()=>null,enableSorting:!1,cell:({row:r})=>r.getCanExpand()?e.createElement(x,{onClick:r.getToggleExpandedHandler(),variant:"text",size:"medium",icon:r.getIsExpanded()?e.createElement(D,null):e.createElement(I,null)}):null},L=b(()=>[h,{header:"API",accessorKey:"title"},s?{header:"Published at",accessorKey:"publishedAt",cell:({getValue:r})=>{const o=r();return o?new Date(o).toLocaleDateString():"-"}}:void 0,n?{header:l,accessorKey:"team",cell:({getValue:r})=>r()||Q}:void 0,{header:"Problem count",size:200,accessorKey:"count",cell:({getValue:r})=>r()||0,sortDescFirst:!0}].filter(R),[n,s,l,t]),y=b(()=>Object.entries(i.teams).sort((r,o)=>o[1]-r[1]),[i.teams]);return e.createElement(V,null,e.createElement(x,{icon:e.createElement(K,null),iconPosition:"left",variant:"ghost",size:"large",to:`${u}scorecard`},"Back to dashboard"),e.createElement("h1",null,"Rule ",d),e.createElement(j,null,e.createElement(S,null,e.createElement(w,null,"Rule status"),e.createElement(F,null,e.createElement("div",null,e.createElement(v,null,m),e.createElement("br",null),"APIs"),e.createElement("div",null,e.createElement(C,null,e.createElement(v,{style:{textAlign:"right"}},m-a-c),e.createElement(k,{severity:"Pass"})),e.createElement(C,null,e.createElement(v,{style:{textAlign:"right"}},a),e.createElement(k,{severity:"Warn"})),e.createElement(C,null,e.createElement(v,{style:{textAlign:"right"}},c),e.createElement(k,{severity:"Error"}))))),e.createElement(S,null,e.createElement(w,null,"Problems by level"),e.createElement(W,null,Object.entries(E).map(([r,o])=>e.createElement(B,{key:r},e.createElement("span",null,r),e.createElement(se,{chunks:[{share:o.errors/g*100,colorVariable:"--scorecard-color-error"},{share:o.warnings/g*100,colorVariable:"--scorecard-color-warning"}]}),e.createElement(ce,null,o.errors+o.warnings))))),e.createElement(S,null,e.createElement(w,null,`Problems by ${l}`),e.createElement(W,null,y.slice(0,4).map(([r,o])=>e.createElement(B,{key:r},e.createElement("span",{style:{flex:1,textAlign:"left"}},r),e.createElement(v,null,o)))))),e.createElement(A,{columns:L,data:f,sortBy:[{id:"title",desc:!1}],subRowKey:"problems",slug:d}))}function ze(p){const{slug:u,api:d,teamLabel:i,catalogSlug:n}=p,{api:s}=d||{},{scorecard:l,isLoading:f}=ae(`/${u}`),m=l?.levels||{},[a,c]=G(Object.keys(m)[0]),E=b(()=>s?.publishedAt instanceof Date?s?.publishedAt.toLocaleDateString():s?.publishedAt,[s]);_(()=>{if(l){const t=l.levels||{};c(Object.keys(t)[0])}},[l]);const g=b(()=>{if(!l?.levels)return{};const t={};for(const h of Object.keys(l.levels)){const L=l.levels[h].problems.reduce((y,r)=>(y[r.ruleId]||(y[r.ruleId]=[]),y[r.ruleId].push(r),y),{});t[h]=Object.entries(L).map(([y,r])=>({ruleId:y,problems:[...r.filter(o=>o.severity==="error"),...r.filter(o=>o.severity==="warn")],problemsCount:r.length,status:{errorsCount:r.filter(o=>o.severity==="error").length,warningsCount:r.filter(o=>o.severity==="warn").length}}))}return t},[l?.levels]);return f?e.createElement(U,{justifyContent:"center",mt:"2em"},e.createElement(N,null)):l?e.createElement(V,null,e.createElement(x,{icon:e.createElement(K,null),iconPosition:"left",variant:"ghost",size:"large",to:`${n}scorecard`},"Back to dashboard"),e.createElement("h1",null,s?.title||u),e.createElement(ee,null,E&&e.createElement(e.Fragment,null,"Published at: ",new Date().toLocaleString(void 0,{timeZoneName:"short"}),e.createElement("br",null)),e.createElement(P,{to:u,external:!0},"Documentation")),e.createElement(j,null,e.createElement(S,null,e.createElement(le,null,e.createElement("span",null,"Scorecard level"),e.createElement(M,{level:l.scorecardLevel,colorVariable:z(l.scorecardLevelIdx,Object.keys(m).length)})),e.createElement(F,null,e.createElement("div",null,"Compliance by level"),e.createElement("div",null,Object.entries(l.levels).map(([t,h])=>e.createElement(C,{key:t},e.createElement(v,{style:{width:"100px",textAlign:"right"}},t),e.createElement($,{errors:h.errors,warnings:h.warnings})))))),e.createElement(J,{title:"Rules compliance",levels:Object.entries(l.levels).map(([t,h])=>({errors:h.uniqueErrors,warnings:h.uniqueWarnings,total:p.rulesPerLevel[t].length,name:t}))}),e.createElement(S,null,e.createElement(w,null,i),e.createElement(v,{style:{fontWeight:"normal"}},s?.team))),e.createElement(re,{style:{justifyContent:"flex-start"},"data-component-name":"Scorecard/ModeSwitcherTabs"},Object.keys(l.levels).map(t=>e.createElement(te,{"data-component-name":"Scorecard/ModeSwitcherTab",key:t,isActive:a===t,onClick:()=>c(t)},e.createElement(C,null,e.createElement("span",null,t)," ",e.createElement($,{errors:l.levels[t].errors,warnings:l.levels[t].warnings}))))),Object.keys(m).map(t=>e.createElement(ne,{key:t,isActive:a===t},e.createElement(oe,{title:t,data:g[t]})))):e.createElement("div",null,"Scorecard not found")}export{Te as ApiListView,ze as ApiPage,oe as ApiView,Ke as RuleView,Ie as RulesView,De as TeamsView};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{appendFile as
|
|
1
|
+
import{appendFile as D}from"node:fs/promises";import{existsSync as P}from"node:fs";import E from"node:path";import{Client as v}from"typesense";import{SEARCH_GROUP_FACET_FIELD as A,SEARCH_PRODUCT_FIELD as L,SEARCH_RBAC_FIELD as T,SEARCH_VERSION_FIELD as h}from"../../../../../constants/common.js";import{BASE_SEARCH_DOCUMENT as j,DISABLE_DEEP_LINK_IF_FIELDS_EXIST as k,HIGHLIGHTED_TEXT_MAX_LENGTH as R,SEARCH_DATA_EXPORT_FOLDER as C,SEARCH_DOCUMENT_METADATA_KEY as w,SEARCH_GROUP_LIMIT as O,SEARCH_MAX_FACET_VALUES as y,SEARCH_MAX_INMEMORY_DOCUMENTS_COUNT as q}from"../../../../constants/plugins/search.js";import{telemetryTraceStep as N}from"../../../../telemetry/helpers/trace-step.js";import{envConfig as _}from"../../../../config/env-config.js";import{logger as F}from"../../../../tools/notifiers/logger.js";import{ensureDir as b}from"../../../../utils/index.js";class J{#e=null;#a="";#t=[{name:"title",type:"string",facet:!1,optional:!0},{name:"text",type:"string",facet:!1,optional:!0},{name:"path",type:"string[]",facet:!1,optional:!0},{name:"isAdditionalOperation",type:"bool",facet:!1,optional:!0,queryable:!1},{name:"deprecated",type:"bool",facet:!1,optional:!0,queryable:!1},{name:"parameters",type:"object[]",facet:!1,optional:!0},{name:L,type:"string",facet:!0,optional:!0},{name:h,type:"object",facet:!0,optional:!0},{name:T,type:"string[]",facet:!0},{name:"metadata_curated",type:"bool",facet:!1,optional:!0,queryable:!1},{name:"metadata_keywords_excludes",type:"string[]",facet:!1,optional:!0,queryable:!1},{name:"metadata_keywords_includes",type:"string[]",facet:!1,optional:!0,queryable:!1}];#s=new Map;#r={ORGANIZATION_ID:_.ORGANIZATION_ID??"",PROJECT_ID:_.PROJECT_ID??"",TYPESENSE_API_URL:_.TYPESENSE_API_URL??"",TYPESENSE_API_KEY:_.TYPESENSE_API_KEY??""};constructor(){if(!_.isBuildMode){for(const[e,t]of Object.entries(this.#r))if(!t)throw new Error(`Cannot initialize search index. ${e} is not set`);this.#a=`${this.#r.ORGANIZATION_ID}_${this.#r.PROJECT_ID}_`,this.#e=new v({nodes:[{url:this.#r.TYPESENSE_API_URL}],apiKey:this.#r.TYPESENSE_API_KEY,connectionTimeoutSeconds:5})}}async initIndexSchema(e){this.#_(e)}async addDocuments(e,t){e.push(j);const{locale:s,outDir:o}=t,r=e.map(n=>{const a={...n},c=n[w];return c&&(c.curated&&(a.metadata_curated=c.curated),c.excludes&&(a.metadata_keywords_excludes=c.excludes),c.includes&&(a.metadata_keywords_includes=c.includes)),a}),i=this.#s.get(s)??[];this.#s.set(s,i.concat(r)),i.length+e.length>=q&&await this.exportDocuments(o)}async search(e,t){return await N("com.redocly.search.performed",async s=>{s?.setAttribute("id","searchQueryId"),s?.setAttribute("object","searchQuery"),s?.setAttribute("uri","urn:redocly:realm:api:searchQuery:searchQueryId");const{query:o,locale:r,filter:i,loadMore:n}=e,a=this.#u(r),c={collection:a,q:o||"*",query_by:this.#f(),max_facet_values:y};if(s?.setAttribute("collectionName",a),s?.setAttribute("locale",r),this.#e)if(n){const{groupKey:l,offset:u}=n,f={offset:u,filter_by:this.#o(t,i),facet_by:"*",per_page:O};return s?.setAttribute("isLoadMore",!0),s?.setAttribute("filter",f.filter_by),this.#m(await this.#e.collections(a).documents().search({...c,...f}),l)}else{const l=this.#o(t,i);s?.setAttribute("filter",l);const u=await this.#e.multiSearch.perform({searches:this.#E(t,i)},c),f=this.#i(u,this.#t.filter(m=>m.facet).map(m=>m.name));f&&F.warn("Search facet requests failed: %s",f);const p=this.#p(u),d=(p[A]??[]).map(m=>m.value);s?.setAttribute("groups",d.join(",")),d.length===y&&F.warn("Search category facet list reached the limit of %s; results for some categories may be missing",y);const I=[...new Set(this.#h(i))].slice(0,y),g=I.length?I:d;if(!g.length)return{facets:p,documents:{},groupCounts:{}};const $=await this.#e.multiSearch.perform({searches:g.map(m=>({filter_by:`${A}:=${this.#n(m)} && ${l}`,per_page:O}))},c),S=this.#i($,g);return S&&F.warn("Search category requests failed: %s",S),this.#d($,g,p,i)}else return{facets:{},documents:{}}})}#m(e,t){const s={facets:{},documents:{[t]:[]},groupCounts:typeof e.found=="number"?{[t]:e.found}:{}};if(e.hits&&e.hits.length)for(const o of e.hits)s.documents[t].push({document:this.#c(o),highlight:this.#l(o)});return s}#p(e){const t={};if("results"in e){for(const s of e.results)if(s.facet_counts&&s.facet_counts.length)for(const o of s.facet_counts)t[o.field_name]=o.counts.map(r=>({value:r.value,count:r.count}))}return t}#i(e,t){return"results"in e?e.results.map((s,o)=>({result:s,label:t[o]})).filter(({result:s})=>"error"in s).map(({result:s,label:o})=>`${o}: ${s.error}`).join("; "):""}#d(e,t,s,o){const r={},i={facets:s,documents:{},groupCounts:r};for(const n of this.#h(o))i.documents[n]=[];return"results"in e&&e.results.forEach((n,a)=>{const c=t[a];typeof n.found=="number"&&(r[c]=n.found);const l=n.hits??[];l.length&&(i.documents[c]=l.map(u=>({document:this.#c(u),highlight:this.#l(u)})))}),i}#c(e){return this.#y(e)}#l(e){const t={},s=[];for(const[o,r]of Object.entries(e.highlight??{}))if(Array.isArray(r)){if(o==="path"){const i=r,n=[];for(const a of i)n.push(a.snippet);t.path=n}else if(o==="parameters"){const i=r;for(const n of i){let a=!1;for(const[c,l]of Object.entries(n))if(c!=="deepLink")if(Array.isArray(l))for(const u of l)u.matched_tokens?.length&&(a=!0);else l.matched_tokens?.length&&(a=!0);if(a){const c={name:n.name?.snippet||"",description:n.description?.snippet||"",place:n.place?.snippet||"",path:n.path?.map(l=>l?.snippet)||[]};t.parameters=[c];break}}}}else t[o]=r.snippet,s.push(o);for(const[o,r]of Object.entries(e.document))!s.includes(o)&&typeof r=="string"&&(t[o]=r.length>R?`${r.substring(0,R)}...`:r);return t.parameters||(t.parameters=[]),t}#y(e){let t;const s=Object.keys(e.highlight??{});for(const r of k)if(s.some(i=>i===r))return e.document;const o=e.highlight?.parameters;if(o){for(const r of o)for(const[i,n]of Object.entries(r))if(i!=="deepLink"){if(Array.isArray(n)){for(const a of n)if(a.matched_tokens?.length){t=r.deepLink?.snippet??t;break}}else if(n.matched_tokens?.length){t=r.deepLink?.snippet??t;break}}}if(t){const r=t.split("#")[1];return{...e.document,url:`${e.document.url}#${r}`}}return e.document}async exportDocuments(e){const t='{"documents":[',s=b(E.join(e,C));for(const[o,r]of this.#s){if(r.length===0)continue;const i=b(E.join(s,`${o}.json`)),n=!P(i),a=JSON.stringify(r).substring(1).slice(0,-1),c=n?t+a:","+a;await D(i,c,{encoding:"utf8"}),this.#s.set(o,[])}}async exportIndexes(e){const t=b(E.join(e,C));for(const s of this.#s.keys()){const o=b(E.join(t,`${s}.json`)),r=`],"schemaFields":${JSON.stringify(this.#t)}}`;await D(o,r,{encoding:"utf8"})}}async import(e){}async countFacets(e,t){return await N("com.redocly.search.facets",async s=>{s?.setAttribute("id","searchFacetsId"),s?.setAttribute("object","searchFacets"),s?.setAttribute("uri","urn:redocly:realm:api:searchFacets:searchFacetsId");const{locale:o,query:r,facetQuery:i,filter:n,field:a}=e,c=this.#u(o),l={q:r||"*",query_by:this.#f(),facet_by:"*",facet_query:this.#g(i,a),filter_by:this.#o(t,n,a),max_facet_values:y};if(s?.setAttribute("collectionName",c),s?.setAttribute("query",l.q),s?.setAttribute("facetQuery",l.facet_query),s?.setAttribute("filter",l.filter_by),this.#e){const u={},f=await this.#e.collections(c).documents().search(l);if(f.facet_counts&&f.facet_counts.length)for(const p of f.facet_counts)u[p.field_name]=p.counts.map(d=>({value:d.value,count:d.count,isCounterVisible:!!r||(n?.length||0)>0}));return u}else return{}})}#u(e){return`${this.#a}${e}`}#_(e){for(const[t,{queryable:s}]of e)this.#t.find(o=>o.name===t)||this.#t.push({queryable:s,name:t,type:"string",facet:!0,optional:!0})}#f(){return this.#t.filter(e=>e.facet?e.queryable:e.queryable!==!1).map(e=>e.name).join(",")}#n(e){return`\`${e.replaceAll("`","")}\``}#o(e,t,s){const o=`${T}:[${e.teams.map(i=>`'${i}'`).join(", ")}]`;let r=`${h}.isDefault:true`;if(t&&t.length){const i=t.filter(a=>a.field!==s&&a.field!==h).map(a=>{const c=a.values.map(l=>this.#n(l));return c.length?`${a.field}:=[${c.join(", ")}]`:""}).join(" && "),n=t.find(a=>a.field===h);if(n&&n.values.length&&n.values.length===2){const a=n.values[0],c=n.values[1],l=`(${h}.folderId:! ${a} && ${h}.isDefault:true)`,u=`(${h}.folderId: ${a} && ${h}.version:=${this.#n(c)})`;r=`(${l} || ${u})`}return i?`${o} && ${i} && ${r}`:`${o} && ${r}`}else return`${o} && ${r}`}#g(e,t){return e&&t?`${t}:${e}`:""}#h(e){const t=[];if(e&&e.length)for(const s of e)s.field===A&&t.push(...s.values);return t}#E(e,t){const s=[],o=this.#t.filter(r=>r.facet);for(const r of o){const i={facet_by:r.name,filter_by:this.#o(e,t,r.name)};s.push(i)}return s}cleanupFacetValues(e){const t=e.getSearchFacets();t.forEach(s=>{s.values=[]}),e.setSearchFacets(t)}}export{J as Typesense};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{pathToFileURL as z}from"url";import{HelmetProvider as G}from"@dr.pogodin/react-helmet";import{renderToString as l}from"react-dom/server";import{StaticRouterProvider as J,createStaticHandler as K,createStaticRouter as Q}from"react-router
|
|
1
|
+
import{pathToFileURL as z}from"url";import{HelmetProvider as G}from"@dr.pogodin/react-helmet";import{renderToString as l}from"react-dom/server";import{StaticRouterProvider as J,createStaticHandler as K,createStaticRouter as Q}from"react-router";import r from"react";import{readFile as V}from"fs/promises";import{join as W}from"path";import{withPathPrefix as m,getLocaleFromPathname as X,withoutPathPrefix as Y,removeTrailingSlash as Z}from"@redocly/theme/core/utils";import{RUNTIME_RESOURCES_DIR as T}from"../constants/common.js";import{slash as tt}from"../../utils/path/slash.js";import{reporter as et}from"../tools/notifiers/reporter.js";import{envConfig as p}from"../config/env-config.js";import{slug as rt}from"../../utils/slugger.js";import{shouldForwardProp as ot}from"../../utils/should-forward-prop.js";import{htmlTemplate as st}from"./template.js";import{detectColorSchemaScript as nt,generatePreloadPageData as at,generatePreloadSharedData as it}from"./utils.js";import"./hijack-console.js";import{getSitemapLinkTag as ct}from"./get-sitemap-link-tag.js";let g="";async function lt(t){return p.isRuntimeMode?await import("../../client/server-entry.js"):await import(z(`${tt(t)}/server-entry.js`)+"?"+new Date)}async function Bt(t){if(!p.isRuntimeMode){const e=et.getCompilationProblems();if(e.length>0){const{renderCompilationError:n}=await import("./render-compilation-error.js");return n(e)}}const{Loader:u,App:R,routes:w,ServerStyleSheet:E,StyleSheetManager:P,ErrorDetails:C,initL10n:D}=await lt(t.serverOutDir),{page:h,store:{globalData:S,hasSitemap:y},sharedData:v,ssrHref:b}=t,d=S?.l10n,i=X(Y(h.slug),d?.defaultLocale,d?.locales),f=t.page.request?.url||"http://localhost/";await u.prepare({...h,slug:Z(new URL(f).pathname)},v,S,i),await D(i);const c=new E,{query:M,dataRoutes:x}=K([{Component:R,path:m("*"),children:w}]),s=await M(new Request(f));if(s instanceof Response)throw s;const B=Q(x,s);try{globalThis.SSR_HOSTNAME=b,globalThis.SSR_USER_AGENT=t.userAgent,globalThis.SSR_OMIT_SUSPENSE=t.omitSuspense;const e={},n=l(r.createElement(G,{context:e},r.createElement(P,{sheet:c.instance,shouldForwardProp:ot},r.createElement(J,{router:B,context:s})))),L=y?ct():"",a=e.helmet,j=a?.title.toString()||"",k=t.store.globalData?.logo?.favicon,o=t.store.config,_=`<link rel="preload" as="fetch" crossorigin="anonymous" href="${m("/app-data.json")}" />`,F=at(t.page.slug),H=it(t.page.sharedDataIds),U=nt(o),A=t.page.product?.name?`product-${rt(t.page.product.name)}`:"",$=t.store.ssr.headTags.join(""),I=t.store.ssr.postBodyTags.join(""),N=t.store.ssr.preBodyTags.join(""),O=`<link rel="stylesheet" href="${m(T)}/browser-entry.css" />`;!p.isDevelopMode&&!g&&(g=`<style>${await V(W(t.outdir,T,"browser-entry.css"),"utf-8")}</style>`);const q={bodyHtml:n,linkTags:o.linkTags+c.getStyleTags()+(a?.link.toString()||""),title:j,favicon:k,headScriptTags:L+U+o.headScriptTags+$+(a?.script.toString()||"")+(a?.meta.toString()||""),preload:[_,F,...H],postBodyScriptTags:o.postBodyScriptTags+I,preBodyScriptTags:o.preBodyScriptTags||""+N,lang:i,productClass:A,runtimeCss:g||O};return{html:st(q),statusCode:200}}catch(e){return t.telemetry.sendSsrErrorCaughtMessage([{id:"ssr",object:"error",uri:"urn:redocly:realm:cli:error:ssr",message:e.message}]),{html:l(r.createElement(C,{error:e})),statusCode:500,error:e}}finally{c.seal(),u.clear()}}function Lt(t){return l(r.createElement(r.Fragment,null,...t))}export{Bt as render,Lt as renderComponents};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import*as
|
|
2
|
-
`},
|
|
3
|
-
`},
|
|
1
|
+
import*as E from"node:path";import{envConfig as R}from"../../config/env-config.js";import{maskEmail as T}from"./helpers/privacy/mask-email.js";import{maskSubject as C}from"./helpers/privacy/mask-subject.js";import{removePii as w}from"./helpers/privacy/remove-pii.js";import{removePiiFromUrl as $}from"./helpers/privacy/remove-pii-from-url.js";import{red as x,green as A,bold as F,blue as l,gray as i,yellow as b,cyan as v}from"./helpers/colors.js";function P(e,r){return r?e:w(e)}var n;(function(e){e.INFO="INFO",e.WARN="WARN",e.ERROR="ERROR",e.SUCCESS="SUCCESS",e.VERBOSE="VERBOSE",e.HTTP="HTTP"})(n||(n={}));const I={[n.VERBOSE]:0,[n.HTTP]:1,[n.INFO]:2,[n.SUCCESS]:2,[n.WARN]:3,[n.ERROR]:4};function L(e,r){return I[e]>=I[r]}function G(e){if(!e)return;const r=e.toUpperCase();if(r in n)return r}const H={[n.INFO]:l,[n.SUCCESS]:A,[n.WARN]:b,[n.ERROR]:x,[n.HTTP]:v,[n.VERBOSE]:i},N={"%ap":e=>l(E.resolve(e)),"%rp":e=>l(E.relative(process.cwd(),e)),"%s":e=>e?.toString(),"%c":e=>l(e)},M={format(e){return R.REDOCLY_LOG_FORMAT==="JSON"?y(e):U(e)},interpolate(e,...r){const u=Object.keys(N).map(a=>`(${a})`).join("|"),o=new RegExp(u,"g");let s,m=e;for(;(s=o.exec(e))!==null;){s.index===o.lastIndex&&o.lastIndex++;const a=r.shift();if(a===void 0)break;const t=s[0];m=m.replace(t,N[t](a))}return m}};var Y=M;const U=e=>{const{level:r,message:u,duration:o,context:s,preSanitized:m}=e,a=R.isRuntimeMode,t=[H[r](F(`[${r.toLowerCase()}]`))];if(a&&t.push(i(`time="${j()}"`)),s){const{email:c,ipAddress:f,subject:d,method:S,pathname:p,statusCode:h,teams:g,apiFunction:O}=s;O&&t.push(l(`fn="${O}"`)),h&&t.push(D(h)),e.level===n.HTTP&&(S&&t.push(i(`method="${S}"`)),p&&t.push(i(`path="${$(p)}"`))),f&&t.push(i(`ip="${f}"`)),c&&t.push(i(`email="${T(c)}"`)),d&&t.push(i(`sub="${C(d)}"`)),g?.length&&t.push(i(`teams="${g.join(", ")}"`))}if(u){const c=a?`msg="${String(P(u,m)).replaceAll?.('"','\\"')}"`:String(u);t.push(c)}return e.level===n.HTTP&&s?.userAgent&&t.push(i(`agent="${s.userAgent}"`)),o&&t.push(V(o)),t.join(" ")+`
|
|
2
|
+
`},y=({context:e,message:r,preSanitized:u,...o})=>{const{method:s,pathname:m,statusCode:a,userAgent:t,subject:c,email:f,teams:d,apiFunction:S}=e||{},p={...o,email:f&&T(f),subject:c&&C(c),teams:d,apiFunction:S,...o.level===n.HTTP?{method:s,pathname:String($(m)),statusCode:a,userAgent:t}:{message:String(P(String(r??""),u))}};return R.isRuntimeMode&&(p.time=j()),JSON.stringify(p,["time","level","scope","message","duration","method","pathname","statusCode","userAgent","subject","ipAddress","email","apiFunction"])+`
|
|
3
|
+
`},D=e=>(e%500<100?x:e%400<100?b:A)(`status="${e}"`),j=()=>{let e=new Date().getTimezoneOffset()*6e4;return new Date(Date.now()-e).toISOString().slice(0,-1)},V=e=>i(`dur="${Math.round(e)}ms"`);export{n as LogLevel,Y as default,G as parseLogLevel,L as shouldLog};
|
|
@@ -22,6 +22,7 @@ export declare class Logger {
|
|
|
22
22
|
constructor({ context, allowInteractive, minLogLevel }?: LoggerOptions);
|
|
23
23
|
shouldLog(level: LogLevel): boolean;
|
|
24
24
|
info(message: string, ...args: unknown[]): void;
|
|
25
|
+
infoPreSanitized(message: string): void;
|
|
25
26
|
infoTime(timingId: symbol | string, message: string, ...args: unknown[]): {
|
|
26
27
|
message: string;
|
|
27
28
|
timeMs: number;
|