@redocly/redoc-reef 0.137.0 → 0.138.0-next.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. package/CHANGELOG.md +57 -2
  2. package/dist/bin.js +1 -1
  3. package/dist/cli/eject/resolveEjectParams.js +1 -1
  4. package/dist/cli/eject/themeOperations.js +1 -1
  5. package/dist/cli/generate/generate-tag.js +1 -1
  6. package/dist/cli/generate/generate.js +1 -1
  7. package/dist/client/TestProvider.js +1 -1
  8. package/dist/client/api-request-handlers-entry.d.ts +1 -1
  9. package/dist/client/app/hooks/catalog/useCatalog.d.ts +1 -2
  10. package/dist/client/app/hooks/index.d.ts +0 -1
  11. package/dist/client/app/hooks/index.js +1 -1
  12. package/dist/client/app/l10n/hooks/useL10n.js +1 -1
  13. package/dist/client/app/l10n/index.js +1 -1
  14. package/dist/client/app/search/sse-parser.d.ts +5 -2
  15. package/dist/client/app/search/sse-parser.js +2 -2
  16. package/dist/client/constants/ai-search.d.ts +8 -0
  17. package/dist/client/constants/ai-search.js +1 -1
  18. package/dist/client/mcp-tool-handlers-entry.d.ts +1 -1
  19. package/dist/client/middleware-entry.d.ts +1 -1
  20. package/dist/client/providers/theme/ThemeDataProvider.js +1 -1
  21. package/dist/client/server-props-entry.d.ts +1 -1
  22. package/dist/constants/l10n/langs/ar.js +1 -1
  23. package/dist/constants/l10n/langs/de.js +1 -1
  24. package/dist/constants/l10n/langs/en.js +1 -1
  25. package/dist/constants/l10n/langs/es.js +1 -1
  26. package/dist/constants/l10n/langs/fr.js +1 -1
  27. package/dist/constants/l10n/langs/hi.js +1 -1
  28. package/dist/constants/l10n/langs/it.js +1 -1
  29. package/dist/constants/l10n/langs/ja.js +1 -1
  30. package/dist/constants/l10n/langs/ko.js +1 -1
  31. package/dist/constants/l10n/langs/pl.js +1 -1
  32. package/dist/constants/l10n/langs/pt-BR.js +1 -1
  33. package/dist/constants/l10n/langs/pt.js +1 -1
  34. package/dist/constants/l10n/langs/ru.js +1 -1
  35. package/dist/constants/l10n/langs/uk.js +1 -1
  36. package/dist/constants/l10n/langs/zh.js +1 -1
  37. package/dist/markdoc/helpers/guards/is-example-node.d.ts +2 -1
  38. package/dist/markdoc/helpers/guards/is-example-node.js +1 -1
  39. package/dist/markdoc/nodes/fence/index.js +1 -1
  40. package/dist/server/constants/entitlements.d.ts +1 -2
  41. package/dist/server/esbuild/plugins/styled-components-ssr.js +1 -1
  42. package/dist/server/esbuild/plugins/themes-resolver.js +2 -2
  43. package/dist/server/fs/cache.js +1 -1
  44. package/dist/server/fs/fs.js +1 -1
  45. package/dist/server/fs/utils/remove-l10n-prefix.js +1 -1
  46. package/dist/server/persistence/file-hashes/repositories/file-hashes-repository.d.ts +1 -2
  47. package/dist/server/persistence/file-hashes/services/file-hashes-service.d.ts +1 -2
  48. package/dist/server/plugins/analytics/rudderstack/browser-hooks.js +1 -1
  49. package/dist/server/plugins/analytics/segment/browser-hooks.js +1 -1
  50. package/dist/server/plugins/analytics/segment/build-script.js +3 -3
  51. package/dist/server/plugins/api-docs/loader.d.ts +2 -3
  52. package/dist/server/plugins/api-docs/options.d.ts +1 -1
  53. package/dist/server/plugins/api-docs/search/get-ai-search-documents.d.ts +1 -1
  54. package/dist/server/plugins/api-docs/utils/decorators.js +1 -1
  55. package/dist/server/plugins/api-functions/index.js +1 -1
  56. package/dist/server/plugins/catalog-entities/database/repositories/entities/entities-write-repository.js +1 -1
  57. package/dist/server/plugins/catalog-entities/extensions/extractors/api-description/arazzo-entities-extractor.js +1 -1
  58. package/dist/server/plugins/catalog-entities/types/extractors.d.ts +1 -2
  59. package/dist/server/plugins/catalog-entities/utils/openapi-component-content-extractor.d.ts +1 -2
  60. package/dist/server/plugins/catalog-entities/utils/openapi-schema-resolver.d.ts +1 -2
  61. package/dist/server/plugins/config-parser/format-error.js +4 -4
  62. package/dist/server/plugins/l10n/index.js +1 -1
  63. package/dist/server/plugins/lifecycle.js +2 -2
  64. package/dist/server/plugins/markdown/attribute-resolvers/code-walkthrough/file-chunk-parser.js +2 -2
  65. package/dist/server/plugins/markdown/attribute-resolvers/resolve-link.js +1 -1
  66. package/dist/server/plugins/markdown/attribute-resolvers/resolve-svg-content.js +1 -1
  67. package/dist/server/plugins/markdown/compiler.js +1 -1
  68. package/dist/server/plugins/markdown/errors.js +1 -1
  69. package/dist/server/plugins/markdown/markdoc/reparse-example-fences.d.ts +7 -0
  70. package/dist/server/plugins/markdown/markdoc/reparse-example-fences.js +1 -0
  71. package/dist/server/plugins/markdown/markdoc/resolve-raw-partials.js +1 -1
  72. package/dist/server/plugins/markdown/runtime-transform.js +1 -1
  73. package/dist/server/plugins/markdown/search/to-markdown.js +20 -20
  74. package/dist/server/plugins/mcp/codemode/code-execution-telemetry.d.ts +7 -2
  75. package/dist/server/plugins/mcp/codemode/code-execution-telemetry.js +1 -1
  76. package/dist/server/plugins/mcp/codemode/invoke-tool.js +1 -1
  77. package/dist/server/plugins/mcp/codemode/sandbox/unknown-tool-hint.d.ts +5 -1
  78. package/dist/server/plugins/mcp/codemode/sandbox/unknown-tool-hint.js +2 -2
  79. package/dist/server/plugins/mcp/codemode/tools/execute.js +1 -1
  80. package/dist/server/plugins/mcp/codemode/tools/tool-errors.d.ts +4 -0
  81. package/dist/server/plugins/mcp/codemode/tools/tool-errors.js +1 -1
  82. package/dist/server/plugins/mcp/constants.d.ts +1 -0
  83. package/dist/server/plugins/mcp/constants.js +1 -1
  84. package/dist/server/plugins/mcp/docs-mcp/tool-schemas.d.ts +1 -0
  85. package/dist/server/plugins/mcp/docs-mcp/tool-schemas.js +1 -1
  86. package/dist/server/plugins/mcp/docs-mcp/tools/core/submit-feedback.d.ts +7 -0
  87. package/dist/server/plugins/mcp/docs-mcp/tools/core/submit-feedback.js +3 -0
  88. package/dist/server/plugins/mcp/docs-mcp/tools/core/types.d.ts +6 -0
  89. package/dist/server/plugins/mcp/docs-mcp/tools/index.d.ts +1 -0
  90. package/dist/server/plugins/mcp/docs-mcp/tools/index.js +1 -1
  91. package/dist/server/plugins/mcp/docs-mcp/tools/openapi/get-endpoint-info.js +1 -1
  92. package/dist/server/plugins/mcp/docs-mcp/tools/openapi/get-endpoints.js +1 -1
  93. package/dist/server/plugins/mcp/docs-mcp/tools/openapi/get-full-api-description.js +1 -1
  94. package/dist/server/plugins/mcp/docs-mcp/tools/openapi/get-security-schemes.js +1 -1
  95. package/dist/server/plugins/mcp/docs-mcp/tools/openapi/list-apis.js +1 -1
  96. package/dist/server/plugins/mcp/docs-mcp/tools/openapi/load-api-description.d.ts +16 -4
  97. package/dist/server/plugins/mcp/docs-mcp/tools/openapi/load-api-description.js +1 -1
  98. package/dist/server/plugins/mcp/docs-mcp/utils/api-name-matching.d.ts +6 -1
  99. package/dist/server/plugins/mcp/docs-mcp/utils/api-name-matching.js +1 -1
  100. package/dist/server/plugins/mcp/docs-mcp/utils/api-titles.d.ts +8 -0
  101. package/dist/server/plugins/mcp/docs-mcp/utils/api-titles.js +1 -1
  102. package/dist/server/plugins/mcp/handlers/docs-mcp-handler.js +1 -1
  103. package/dist/server/plugins/mcp/index.js +1 -1
  104. package/dist/server/plugins/nav-utils.js +1 -1
  105. package/dist/server/plugins/search/llmstxt/is-included-in-llms-txt.d.ts +1 -2
  106. package/dist/server/providers/database/pagination/after-and-before.js +1 -1
  107. package/dist/server/providers/database/pagination/utils/decode-cursor.js +1 -1
  108. package/dist/server/providers/database/pagination/utils/is-base-64.js +1 -1
  109. package/dist/server/sandbox/constants/host-functions.d.ts +3 -0
  110. package/dist/server/sandbox/constants/host-functions.js +1 -1
  111. package/dist/server/sandbox/constants/sandbox.d.ts +10 -0
  112. package/dist/server/sandbox/constants/sandbox.js +1 -1
  113. package/dist/server/sandbox/sandbox.js +3 -3
  114. package/dist/server/sandbox/types.d.ts +3 -0
  115. package/dist/server/sandbox/utils/read-result.d.ts +8 -0
  116. package/dist/server/sandbox/utils/read-result.js +1 -0
  117. package/dist/server/sandbox/utils/setup-host-functions.js +3 -3
  118. package/dist/server/ssr/index.js +1 -1
  119. package/dist/server/store.d.ts +1 -1
  120. package/dist/server/store.js +1 -1
  121. package/dist/server/tools/notifiers/helpers/privacy/remove-pii-from-url.js +1 -1
  122. package/dist/server/tools/notifiers/helpers/privacy/remove-pii.js +1 -1
  123. package/dist/server/types/plugins/common.d.ts +1 -2
  124. package/dist/server/utils/rbac.js +1 -1
  125. package/dist/server/web-server/middleware/apiKeyMiddleware.js +1 -1
  126. package/dist/server/web-server/middleware/catalogAuthMiddleware.js +1 -1
  127. package/dist/server/web-server/routes/catalog/helpers/create-entity-update-schema.d.ts +1 -1
  128. package/dist/server/web-server/routes/catalog/helpers/create-entity-update-schema.js +1 -1
  129. package/dist/server/web-server/routes/feedback.d.ts +3 -1
  130. package/dist/server/web-server/routes/feedback.js +1 -1
  131. package/dist/server/web-server/routes/mcp-routes/mcp-oauth.js +1 -1
  132. package/dist/server/web-server/routes/otel/otel.js +1 -1
  133. package/dist/server/web-server/utils/legacy-openapi-redirects.js +1 -1
  134. package/dist/types/global-data.d.ts +1 -2
  135. package/dist/utils/slugger.js +1 -1
  136. package/dist/utils/url/sanitize-redirect-pathname.js +1 -1
  137. package/package.json +6 -6
  138. package/dist/client/app/hooks/useAnchorPositioning.d.ts +0 -6
  139. package/dist/client/app/hooks/useAnchorPositioning.js +0 -1
@@ -1,13 +1,18 @@
1
+ import { telemetry } from '../../../telemetry/index.js';
1
2
  import type { CodeAudit } from './code-audit.js';
3
+ type CodeExecutedData = Parameters<typeof telemetry.sendMcpCodeExecutedMessage>[0][number];
4
+ export type McpCodeFailureReason = NonNullable<CodeExecutedData['failure_reason']>;
2
5
  type CodeExecutedEvent = {
3
6
  audit: CodeAudit;
4
7
  fetchCount: number;
5
- outcome: 'ok' | 'error';
8
+ outcome: CodeExecutedData['outcome'];
6
9
  durationMs: number;
10
+ failureReason?: McpCodeFailureReason;
11
+ failedTool?: string;
7
12
  client?: string;
8
13
  clientVersion?: string;
9
14
  };
10
15
  /** Audit record for one sandbox run. Carries the code fingerprint, never the code. */
11
- export declare function reportCodeExecuted({ audit, fetchCount, outcome, durationMs, client, clientVersion, }: CodeExecutedEvent): void;
16
+ export declare function reportCodeExecuted({ audit, fetchCount, outcome, durationMs, failureReason, failedTool, client, clientVersion, }: CodeExecutedEvent): void;
12
17
  export {};
13
18
  //# sourceMappingURL=code-execution-telemetry.d.ts.map
@@ -1 +1 @@
1
- import{telemetry as f}from"../../../telemetry/index.js";import{logger as g}from"../../../tools/notifiers/logger.js";import{McpServerType as l}from"../constants.js";import{serverAttributes as n}from"../utils/telemetry-attributes.js";function $({audit:e,fetchCount:o,outcome:r,durationMs:t,client:c,clientVersion:s}){try{f.sendMcpCodeExecutedMessage([{...n(l.Docs),code_sha256:e.sha256,code_length:e.length,fetch_count:o,outcome:r,flags:e.flags,duration_ms:t,client:c,client_version:s}])}catch{}g.info(`Gateway MCP code executed [${e.sha256.slice(0,12)}] outcome=${r} codeLength=${e.length} fetchCount=${o}`+(e.flags?` flags=${e.flags}`:"")+` durationMs=${t}`)}export{$ as reportCodeExecuted};
1
+ import{telemetry as l}from"../../../telemetry/index.js";import{logger as n}from"../../../tools/notifiers/logger.js";import{McpServerType as m}from"../constants.js";import{serverAttributes as h}from"../utils/telemetry-attributes.js";function d({audit:e,fetchCount:t,outcome:c,durationMs:s,failureReason:o,failedTool:r,client:f,clientVersion:g}){try{l.sendMcpCodeExecutedMessage([{...h(m.Docs),code_sha256:e.sha256,code_length:e.length,fetch_count:t,outcome:c,flags:e.flags,duration_ms:s,failure_reason:o,failed_tool:r,client:f,client_version:g}])}catch{}n.info(`Gateway MCP code executed [${e.sha256.slice(0,12)}] outcome=${c} codeLength=${e.length} fetchCount=${t}`+(e.flags?` flags=${e.flags}`:"")+` durationMs=${s}`+(o?` failureReason=${o}`:"")+(r?` failedTool=${r}`:""))}export{d as reportCodeExecuted};
@@ -1 +1 @@
1
- import{executeMcpTool as c}from"../workers/execute-mcp-tool.js";async function a(t,r,o,u){const e=await c({toolName:t,args:r,context:o,extra:u});if(e.isError)throw new Error(n(e));return e.structuredContent!==void 0?e.structuredContent:i(n(e))}function n(t){return t.content.filter(r=>r.type==="text").map(r=>r.text).join("")}function i(t){try{return JSON.parse(t)}catch{return t}}export{a as invokeTool};
1
+ import{executeMcpTool as i}from"../workers/execute-mcp-tool.js";import{ToolResultError as c}from"./tools/tool-errors.js";async function p(t,r,o,u){const e=await i({toolName:t,args:r,context:o,extra:u});if(e.isError)throw new c(n(e));return e.structuredContent!==void 0?e.structuredContent:s(n(e))}function n(t){return t.content.filter(r=>r.type==="text").map(r=>r.text).join("")}function s(t){try{return JSON.parse(t)}catch{return t}}export{p as invokeTool};
@@ -1,8 +1,12 @@
1
1
  import type { GuestPosition } from '../../../../sandbox/types.js';
2
+ export type GuestErrorDescription = {
3
+ message: string;
4
+ unknownTool?: string;
5
+ };
2
6
  /**
3
7
  * Turns a guest error into the message the model reads. A call on a tool the sandbox does not
4
8
  * hold names that tool and lists the available ones; every other error keeps its message and
5
9
  * gains the line it was thrown on.
6
10
  */
7
- export declare function describeGuestError(code: string, message: string, position: GuestPosition | undefined, availableTools: string[]): string;
11
+ export declare function describeGuestError(code: string, message: string, position: GuestPosition | undefined, availableTools: string[]): GuestErrorDescription;
8
12
  //# sourceMappingURL=unknown-tool-hint.d.ts.map
@@ -1,2 +1,2 @@
1
- import{TOOLS_BRIDGE_GLOBAL_NAME as c}from"../constants.js";const i="not a function",d=new RegExp(`(?:^|[^\\w$.])${c}\\s*(?:(?:\\?\\.|\\.)\\s*([A-Za-z_$][\\w$]*)|(?:\\?\\.)?\\s*\\[\\s*(['"])([^'"]*)\\2\\s*\\])\\s*(?:\\?\\.)?\\s*$`);function $(o,t,n,e){const u=n&&E(o,n);if(!n||u===void 0)return t;const f=t===i?l(o.slice(0,u),e):void 0;return f===void 0?`${t} (line ${n.line})`:`Unknown tool "${f}". Available tools: ${e.join(", ")}`}function l(o,t){const n=d.exec(o),e=n?.[1]??n?.[3];return e!==void 0&&!t.includes(e)?e:void 0}function E(o,{line:t,column:n}){const e=o.split(`
2
- `);if(t>e.length)return;const f=e.slice(0,t-1).reduce((r,s)=>r+s.length+1,0)+n-1;return f<=o.length?f:void 0}export{$ as describeGuestError};
1
+ import{TOOLS_BRIDGE_GLOBAL_NAME as c}from"../constants.js";const i="not a function",d=new RegExp(`(?:^|[^\\w$.])${c}\\s*(?:(?:\\?\\.|\\.)\\s*([A-Za-z_$][\\w$]*)|(?:\\?\\.)?\\s*\\[\\s*(['"])([^'"]*)\\2\\s*\\])\\s*(?:\\?\\.)?\\s*$`);function $(o,t,n,e){const f=n&&E(o,n);if(!n||f===void 0)return{message:t};const s=t===i?l(o.slice(0,f),e):void 0;return s===void 0?{message:`${t} (line ${n.line})`}:{message:`Unknown tool "${s}". Available tools: ${e.join(", ")}`,unknownTool:s}}function l(o,t){const n=d.exec(o),e=n?.[1]??n?.[3];return e!==void 0&&!t.includes(e)?e:void 0}function E(o,{line:t,column:n}){const e=o.split(`
2
+ `);if(t>e.length)return;const s=e.slice(0,t-1).reduce((u,r)=>u+r.length+1,0)+n-1;return s<=o.length?s:void 0}export{$ as describeGuestError};
@@ -1 +1 @@
1
- import{runInSandbox as b}from"../../../../sandbox/sandbox.js";import{returnLastExpression as w}from"../../../../sandbox/utils/return-last-expression.js";import{isMcpToolAvailable as C}from"../../workers/execute-mcp-tool.js";import{importMcpToolHandlers as O}from"../../workers/import-mcp-tool-handlers.js";import{isFetchCapable as T}from"../../gateway-mcp/callable-apis.js";import{buildExecuteHostFetch as y}from"../../gateway-mcp/fetch-capability.js";import{withAuthRequiredMeta as x}from"../../gateway-mcp/upstream-auth.js";import{CODE_MODE_TOOL_NAMES as M,EXECUTE_TOOL_NAME as S}from"../constants.js";import{sanitizeToolName as v}from"../build-tool-type-declarations.js";import{invokeTool as A}from"../invoke-tool.js";import{createSandboxSetup as _}from"../sandbox/create-sandbox-setup.js";import{createToolInputValidator as k}from"../sandbox/tool-input-validator.js";import{describeGuestError as F}from"../sandbox/unknown-tool-hint.js";import{auditCode as N}from"../code-audit.js";import{reportCodeExecuted as j}from"../code-execution-telemetry.js";import{logCodeExecutionAudit as D}from"../code-execution-audit.js";const H=async(o,r,u)=>{const i=new Set,n=await P(r,u,i),s=[],e=T(r)?await y(r,p=>s.push(p)):void 0;let m=0;const f=e?p=>(m+=1,e(p)):void 0,a=N(o.code);D({audit:a,code:o.code,description:o.description,sessionHandle:o.sessionHandle,toolNames:Object.keys(n),fetchBudget:r.gatewayFetchBudgetPerExec,fetchCapable:e!==void 0});const l=Date.now(),d=w(o.code),{result:c,error:t,errorPosition:h}=await b(d,{setupContext:_(n,f),authoredCode:o.code});j({audit:a,fetchCount:m,outcome:t===void 0?"ok":"error",durationMs:Date.now()-l,client:r.client,clientVersion:r.clientVersion});const E=t===void 0?void 0:F(d,t,h,Object.keys(n));return x({content:[{type:"text",text:JSON.stringify({result:c,error:E})}],isError:t!==void 0,...t!==void 0&&i.has(t)?{errorClass:"tool_error"}:{}},s)};async function P(o,r,u){const i=Object.keys(await O()).filter(e=>!M.has(e)),n=await Promise.all(i.map(e=>C({toolName:e,context:o}).catch(()=>!1))),s={};return i.forEach((e,m)=>{if(!n[m])return;const f=v(e),a=o.sandboxToolSchemas?.[e],l=a?k(f,a):void 0;s[f]=d=>{const c=l?.(d);return c?(u.add(c),Promise.reject(new Error(c))):A(e,d,o,r).catch(t=>{throw t instanceof Error&&u.add(t.message),t})}}),s}var Z={[S]:H};export{Z as default};
1
+ import{runInSandbox as C}from"../../../../sandbox/sandbox.js";import{SANDBOX_FAILURE as E}from"../../../../sandbox/constants/sandbox.js";import{returnLastExpression as y}from"../../../../sandbox/utils/return-last-expression.js";import{isMcpToolAvailable as g}from"../../workers/execute-mcp-tool.js";import{importMcpToolHandlers as A}from"../../workers/import-mcp-tool-handlers.js";import{isFetchCapable as M}from"../../gateway-mcp/callable-apis.js";import{buildExecuteHostFetch as S}from"../../gateway-mcp/fetch-capability.js";import{withAuthRequiredMeta as k}from"../../gateway-mcp/upstream-auth.js";import{CODE_MODE_TOOL_NAMES as v,EXECUTE_TOOL_NAME as x}from"../constants.js";import{sanitizeToolName as F}from"../build-tool-type-declarations.js";import{invokeTool as H}from"../invoke-tool.js";import{createSandboxSetup as R}from"../sandbox/create-sandbox-setup.js";import{createToolInputValidator as D}from"../sandbox/tool-input-validator.js";import{describeGuestError as j}from"../sandbox/unknown-tool-hint.js";import{auditCode as B}from"../code-audit.js";import{reportCodeExecuted as I}from"../code-execution-telemetry.js";import{logCodeExecutionAudit as L}from"../code-execution-audit.js";import{ToolResultError as N}from"./tool-errors.js";const P=async(e,t,n)=>{const i=new Map,s=await U(t,n,i),a=[],o=M(t)?await S(t,h=>a.push(h)):void 0;let f=0;const m=o?h=>(f+=1,o(h).catch(_=>{throw i.set(O(_),{reason:"runtime_error"}),_})):void 0,c=B(e.code);L({audit:c,code:e.code,description:e.description,sessionHandle:e.sessionHandle,toolNames:Object.keys(s),fetchBudget:t.gatewayFetchBudgetPerExec,fetchCapable:o!==void 0});const l=Date.now(),d=y(e.code),{result:u,error:r,failure:b,errorPosition:T}=await C(d,{setupContext:R(s,m),authoredCode:e.code}),w=r===void 0?void 0:j(d,r,T,Object.keys(s)),p=r!==void 0&&b===E.HostError?i.get(r):void 0;return I({audit:c,fetchCount:f,outcome:r===void 0?"ok":"error",durationMs:Date.now()-l,failureReason:V(b,p,w?.unknownTool),failedTool:p?.tool,client:t.client,clientVersion:t.clientVersion}),k({content:[{type:"text",text:JSON.stringify({result:u,error:w?.message})}],isError:r!==void 0,...p?.tool!==void 0?{errorClass:"tool_error"}:{}},a)};function V(e,t,n){return e===E.HostError?t?.reason??"runtime_error":e===E.RuntimeError?n===void 0?e:"unknown_tool":e}async function U(e,t,n){const i=Object.keys(await A()).filter(o=>!v.has(o)),s=await Promise.all(i.map(o=>g({toolName:o,context:e}).catch(()=>!1))),a={};return i.forEach((o,f)=>{if(!s[f])return;const m=F(o),c=e.sandboxToolSchemas?.[o],l=c?D(m,c):void 0;a[m]=d=>{const u=l?.(d);return u?(n.set(u,{tool:o,reason:"inner_tool_error"}),Promise.reject(new Error(u))):H(o,d,e,t).catch(r=>{throw n.set(O(r),{tool:o,reason:r instanceof N?"inner_tool_error":"server_error"}),r})}}),a}function O(e){return e instanceof Error?e.message:String(e)}var ae={[x]:P};export{ae as default};
@@ -1,3 +1,7 @@
1
+ /** The tool answered with `isError`, as opposed to failing before it could answer. */
2
+ export declare class ToolResultError extends Error {
3
+ constructor(message: string);
4
+ }
1
5
  export declare class UnknownToolError extends Error {
2
6
  constructor(message: string);
3
7
  }
@@ -1 +1 @@
1
- class n extends Error{constructor(r){super(r),this.name="UnknownToolError"}}export{n as UnknownToolError};
1
+ class s extends Error{constructor(r){super(r),this.name="ToolResultError"}}class e extends Error{constructor(r){super(r),this.name="UnknownToolError"}}export{s as ToolResultError,e as UnknownToolError};
@@ -15,6 +15,7 @@ export declare const MAX_DOCUMENTS_PER_CATEGORY = 3;
15
15
  export declare const DEFAULT_DOCS_MCP_SERVER_NAME = "Docs MCP server";
16
16
  export declare const SUPPORTED_MCP_SCOPES: readonly ['openid', 'profile', 'email', 'offline_access'];
17
17
  export declare const CREATE_ANONYMOUS_SESSION_TOOL_NAME = "createAnonymousSession";
18
+ export declare const SUBMIT_FEEDBACK_TOOL_NAME = "submit-feedback";
18
19
  export declare const MANAGE_API_CREDENTIALS_TOOL_NAME = "manageApiCredentials";
19
20
  export declare const CUSTOM_MCP_TOOLS_META_DIR = "custom-mcp-tools-meta";
20
21
  //# sourceMappingURL=constants.d.ts.map
@@ -1 +1 @@
1
- import{LATEST_PROTOCOL_VERSION as o}from"@modelcontextprotocol/server";const r={Docs:"docs"},t={InternalError:-32603,ServerError:-32e3,InvalidRequest:-32600,MethodNotFound:-32601,InvalidParams:-32602},E=o,_=3e4,s=15e3,O=3,n="Docs MCP server",S=["openid","profile","email","offline_access"],c="createAnonymousSession",T="manageApiCredentials",M="custom-mcp-tools-meta";export{c as CREATE_ANONYMOUS_SESSION_TOOL_NAME,M as CUSTOM_MCP_TOOLS_META_DIR,_ as DEFAULT_CONNECTION_TIMEOUT_MS,n as DEFAULT_DOCS_MCP_SERVER_NAME,T as MANAGE_API_CREDENTIALS_TOOL_NAME,O as MAX_DOCUMENTS_PER_CATEGORY,E as MCP_PROTOCOL_VERSION,t as McpErrorCodes,r as McpServerType,s as SSE_KEEPALIVE_INTERVAL_MS,S as SUPPORTED_MCP_SCOPES};
1
+ import{LATEST_PROTOCOL_VERSION as o}from"@modelcontextprotocol/server";const t={Docs:"docs"},E={InternalError:-32603,ServerError:-32e3,InvalidRequest:-32600,MethodNotFound:-32601,InvalidParams:-32602},_=o,r=3e4,s=15e3,O=3,n="Docs MCP server",S=["openid","profile","email","offline_access"],c="createAnonymousSession",T="submit-feedback",M="manageApiCredentials",A="custom-mcp-tools-meta";export{c as CREATE_ANONYMOUS_SESSION_TOOL_NAME,A as CUSTOM_MCP_TOOLS_META_DIR,r as DEFAULT_CONNECTION_TIMEOUT_MS,n as DEFAULT_DOCS_MCP_SERVER_NAME,M as MANAGE_API_CREDENTIALS_TOOL_NAME,O as MAX_DOCUMENTS_PER_CATEGORY,_ as MCP_PROTOCOL_VERSION,E as McpErrorCodes,t as McpServerType,s as SSE_KEEPALIVE_INTERVAL_MS,T as SUBMIT_FEEDBACK_TOOL_NAME,S as SUPPORTED_MCP_SCOPES};
@@ -7,6 +7,7 @@ export declare function getDefaultToolSchemas(config: {
7
7
  hasGraphqlApis?: boolean;
8
8
  elicitationEnabled?: boolean;
9
9
  hasCallableApis?: boolean;
10
+ feedbackHidden?: boolean;
10
11
  }): McpToolSchema[];
11
12
  export declare const ALL_DEFAULT_TOOL_NAMES: ReadonlySet<string>;
12
13
  //# sourceMappingURL=tool-schemas.d.ts.map
@@ -1 +1 @@
1
- import{SEMANTIC_SEARCH_API_URL as m}from"../../../constants/common.js";import{shouldHandleMcpAuth as h}from"../../../utils/rbac/should-handle-mcp-auth.js";import{CREATE_ANONYMOUS_SESSION_TOOL_NAME as y}from"../constants.js";import{GRAPHQL_TYPE_KINDS as o,GRAPHQL_LIST_SCOPES as f}from"./tools/graphql/constants.js";import{OPERATION_METHODS as p}from"./tools/openapi/constants.js";const i={type:"string",nullable:!0},n={limit:{type:"number"},total:{type:"number"},page:{type:"number"},totalPages:{type:"number"}},r={codemodeType:"OpenApiServer[]"},s={codemodeType:"OpenApiSecurityRequirement[]"},l={codemodeType:"Record<string, OpenApiSecurityScheme>"},g={codemodeType:"OpenApiDocument"},b={codemodeType:"OpenApiOperation & { path: string; method: string }"},v={type:"object",additionalProperties:!1,required:[],properties:{filter:{type:"string",description:"Matches part of an API name, or of a description when no name matches",minLength:1,nullable:!0},page:{type:"number",description:"Page number",minimum:1,default:1,nullable:!0},limit:{type:"number",description:"Number of APIs per page. Default is 300",minimum:1,default:300,nullable:!0}}},a={type:"object",required:[],additionalProperties:!1,properties:{name:{type:"string",description:"API name, or a unique part of it. Omit when `filePath` is given.",minLength:1,nullable:!0},apiName:{type:"string",description:"Alias of `name`",nullable:!0},api:{type:"string",description:"Alias of `name`",nullable:!0},version:{type:"string",description:"API version",nullable:!0},filePath:{type:"string",description:"API definition file path, as returned by `listApis`",nullable:!0}}},S={type:"object",required:["path","method"],additionalProperties:!1,properties:{name:{type:"string",description:"API name, or a unique part of it. Omit when `filePath` is given.",minLength:1,nullable:!0},apiName:{type:"string",description:"Alias of `name`",nullable:!0},api:{type:"string",description:"Alias of `name`",nullable:!0},path:{type:"string",description:"Endpoint path (e.g. /api/v1/users)",minLength:1},method:{type:"string",description:"HTTP method (GET, POST, PUT, DELETE, etc.)",enum:[...p.map(e=>e.toUpperCase()),...p],minLength:1},version:{type:"string",description:"API version (required when multiple APIs share the same name but differ by version)",nullable:!0},filePath:{type:"string",description:"API definition file path, as returned by `listApis`",nullable:!0}}},A={type:"object",required:[],additionalProperties:!1,properties:{}},H={type:"object",required:[],additionalProperties:!1,properties:{}};function P(e){const t=[{name:"list-apis",title:"List APIs",description:"Lists the APIs documented in this project",schema:v,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",properties:{items:{type:"array",items:{type:"object",properties:{name:{type:"string"},description:i,version:i,servers:r,filePath:{type:"string",description:"API definition file path"},ambiguousTitle:{type:"boolean",description:"true = another API shares this title; pass `filePath`, or `version` when the copies differ by version"},...e.hasCallableApis?{callable:{type:"boolean",description:"true = the documented hosts of this API are reachable via `fetch`; false = documentation only"}}:{}}}},...n}}},{name:"get-endpoints",title:"Get endpoints",description:"Get all endpoints for a specific API",schema:a,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",properties:{api:{type:"string"},version:{type:"string"},servers:r,endpoints:{type:"array",items:{type:"object",properties:{path:{type:"string"},method:{type:"string"},summary:i,description:i,security:s}}}}}},{name:"get-endpoint-info",title:"Get endpoint info",description:"Get comprehensive information about specific endpoint including parameters, security, and examples",schema:S,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",properties:{api:{type:"string"},version:{type:"string"},servers:r,endpoint:b,globalSecurity:s,securitySchemes:l}}},{name:"get-security-schemes",title:"Get security schemes",description:"Get the security schemes for a specific API",schema:a,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",properties:{name:i,version:i,securitySchemes:l,security:s}}},{name:"get-full-api-description",title:"Get full API description",description:"Get the complete OpenAPI description",schema:a,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",properties:{api:{type:"string"},version:{type:"string"},definition:g}}},...m?[c(e.products,e.locales)]:[]];return h(e.requiresLogin,e.rbac)&&t.push({name:"whoami",title:"Who am I",description:"Get information about the currently authenticated user",schema:A,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",properties:{email:{type:"string"},name:{type:"string"},subject:{type:"string"},clientId:{type:"string"},scope:{type:"string"},issuedAt:{type:"string"},expiresAt:{type:"string"}}}}),e.hasGraphqlApis&&t.push(...G()),e.elicitationEnabled&&e.hasCallableApis&&t.push({name:y,title:"Create anonymous session",description:"Create an anonymous session handle for storing upstream API credentials. Pass the returned sessionHandle to execute when an API needs credentials and the caller is not signed in. Treat it as a secret and reuse it across calls.",schema:H,annotations:{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!1,openWorldHint:!1},outputSchema:{type:"object",required:["sessionHandle"],properties:{sessionHandle:{type:"string"}}}}),t}const L={type:"object",required:[],additionalProperties:!1,properties:{filter:{type:"string",description:"GraphQL schema name (or part of it)",minLength:1,nullable:!0},page:{type:"number",description:"Page number",minimum:1,default:1,nullable:!0},limit:{type:"number",description:"Number of results per page. Default is 300",minimum:1,default:300,nullable:!0}}},O={type:"object",required:["name"],additionalProperties:!1,properties:{name:{type:"string",description:"GraphQL schema name",minLength:1},kind:{type:"string",description:'Optional: return only a single category of schema members. With scope "fields", restricts to the fields of that parent category ("objects", "interfaces", or "inputs" only).',enum:[...o,null],nullable:!0},scope:{type:"string",description:'Optional: what each list item is. "members" (default) lists top-level types and operations. "fields" flattens every field of every object/interface/input type into "ParentType.fieldName" entries with their descriptions \u2014 combine with `filter` to search nested fields anywhere in the schema.',enum:[...f,null],nullable:!0},filter:{type:"string",description:'Optional: only members whose name or description contains this substring, case-insensitive (e.g. "custom tags")',minLength:1,nullable:!0},referencesType:{type:"string",description:'Optional: only members that reference this type directly or transitively (via return, field, argument, union-member or input-field types). Finds cross-cutting members that never name it \u2014 e.g. referencesType "Book" surfaces a search query returning a union that includes Book.',minLength:1,nullable:!0},page:{type:"number",description:"Page number",minimum:1,default:1,nullable:!0},limit:{type:"number",description:"Number of results per page. Default is 300",minimum:1,default:300,nullable:!0}}},T={type:"object",required:["name"],additionalProperties:!1,properties:{name:{type:"string",description:"GraphQL schema name",minLength:1},type:{type:"string",description:"Name of the type, operation, or directive",minLength:1,nullable:!0},typeName:{type:"string",description:"Alias of `type`",nullable:!0},includeReferencedTypes:{type:"boolean",description:"Also include the SDL of every type referenced transitively. Gives the whole subgraph at once, but can be large for highly-connected types.",default:!1,nullable:!0}}},q={type:"object",required:["name"],additionalProperties:!1,properties:{name:{type:"string",description:"GraphQL schema name",minLength:1}}};function G(){return[{name:"list-graphql-apis",title:"List GraphQL APIs",description:"Lists available GraphQL schemas with their context and purpose",schema:L,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",properties:{items:{type:"array",items:{type:"object",properties:{name:{type:"string"},description:i}}},...n}}},{name:"get-graphql-type-list",title:"Get GraphQL type list",description:'List all operations and types in a GraphQL schema as a flat, paginated list. Each item is tagged with its kind (query, object, enum, \u2026) and carries a one-line description; operations also include their return type and argument signature \u2014 use it to decide which members to fetch in detail. Narrow the result with `kind` (one category), `filter` (case-insensitive substring of the member name or description, e.g. "book"), or `referencesType` (only members that use a given type, directly or transitively) to explore a domain cheaply instead of pulling the full schema. To search nested fields \u2014 not just type names \u2014 set scope "fields": it flattens every field of every object/interface/input type into "ParentType.fieldName" entries with their descriptions, so `filter` finds things like an input field whose docstring mentions your keyword.',schema:O,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",properties:{name:{type:"string"},items:{type:"array",items:{type:"object",properties:{kind:{type:"string",enum:o},name:{type:"string"},description:i,type:{type:"string"},args:{type:"string"},directives:{type:"string"}}}},...n}}},{name:"get-graphql-type",title:"Get GraphQL type",description:'Get the SDL for a single GraphQL type, operation (query/mutation/subscription field), or directive. Without includeReferencedTypes, the SDL is followed by a one-level manifest of every directly referenced type\'s field names (e.g. "input ActionOperationInput { addTags, removeTags }"), so you can see what nested types contain before fetching them. Set includeReferencedTypes to instead pull in the full SDL of every type it references transitively \u2014 the whole structural subgraph in one call, ideal for complete exploration of an entity (e.g. Book and all the types it touches). That traversal only follows what the target depends on; to go the other direction and find the members that use a type, call get-graphql-type-list with `referencesType`.',schema:T,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"string"}},{name:"get-graphql-schema",title:"Get GraphQL schema",description:"Get the complete GraphQL schema as SDL \u2014 the whole type graph in one call. Returns everything, so it can be very large and token-expensive for big schemas; prefer get-graphql-type-list (filter/paginate) plus targeted get-graphql-type calls, and reach for this only for small schemas or when you truly need the full SDL.",schema:q,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"string"}}]}function c(e,t){const u=e&&e.length>0,d=t&&t.length>0;return{name:"search",title:"Search documentation",description:"Search across the documentation to fetch relevant content for a given query",schema:{type:"object",required:["query"],additionalProperties:!1,properties:{query:{type:"string",description:"Search query. Should be a single word or that phrase that is presented in a documentation.",minLength:1},...u?{product:{type:"string",description:"Optional product name to filter search results by specific product.",enum:[...e,null],nullable:!0}}:{},...d?{locale:{type:"string",description:"Optional locale code to filter search results by documentation language (e.g. 'en', 'ja'). Use the locale matching the language of the user's request. Defaults to the project's default locale.",enum:[...t,null],nullable:!0}}:{}}},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!1,openWorldHint:!1},outputSchema:{type:"string"}}}const D=new Set([...P({requiresLogin:!0,hasGraphqlApis:!0,elicitationEnabled:!0,hasCallableApis:!0}).map(e=>e.name),c().name]);export{D as ALL_DEFAULT_TOOL_NAMES,P as getDefaultToolSchemas};
1
+ import{SEMANTIC_SEARCH_API_URL as y}from"../../../constants/common.js";import{shouldHandleMcpAuth as f}from"../../../utils/rbac/should-handle-mcp-auth.js";import{CREATE_ANONYMOUS_SESSION_TOOL_NAME as g,SUBMIT_FEEDBACK_TOOL_NAME as b}from"../constants.js";import{GRAPHQL_TYPE_KINDS as l,GRAPHQL_LIST_SCOPES as v}from"./tools/graphql/constants.js";import{OPERATION_METHODS as c}from"./tools/openapi/constants.js";const i={type:"string",nullable:!0},s={limit:{type:"number"},total:{type:"number"},page:{type:"number"},totalPages:{type:"number"}},a={codemodeType:"OpenApiServer[]"},o={codemodeType:"OpenApiSecurityRequirement[]"},u={codemodeType:"Record<string, OpenApiSecurityScheme>"},P={codemodeType:"OpenApiDocument"},A={codemodeType:"OpenApiOperation & { path: string; method: string }"},n={filePath:{type:"string",description:"API definition file path"},otherMatches:{type:"array",description:"Other API definitions the lookup also matched. Present only when several matched; pass `filePath` to pick another one",items:{type:"object",required:["filePath"],properties:{version:{type:"string"},filePath:{type:"string"}}}}},r="When several definitions match the name, the highest version or the shortest file path is used and the rest are listed in `otherMatches`; tell the user which version or file the answer is based on.",S={type:"object",additionalProperties:!1,required:[],properties:{filter:{type:"string",description:"Matches part of an API name, or of a description when no name matches",minLength:1,nullable:!0},page:{type:"number",description:"Page number",minimum:1,default:1,nullable:!0},limit:{type:"number",description:"Number of APIs per page. Default is 300",minimum:1,default:300,nullable:!0}}},p={type:"object",required:[],additionalProperties:!1,properties:{name:{type:"string",description:"API name, or a unique part of it. Omit when `filePath` is given.",minLength:1,nullable:!0},apiName:{type:"string",description:"Alias of `name`",nullable:!0},api:{type:"string",description:"Alias of `name`",nullable:!0},version:{type:"string",description:"API version. When omitted and several versions exist, the highest one is used",nullable:!0},filePath:{type:"string",description:"API definition file path, as returned by `listApis`",nullable:!0}}},H={type:"object",required:["path","method"],additionalProperties:!1,properties:{name:{type:"string",description:"API name, or a unique part of it. Omit when `filePath` is given.",minLength:1,nullable:!0},apiName:{type:"string",description:"Alias of `name`",nullable:!0},api:{type:"string",description:"Alias of `name`",nullable:!0},path:{type:"string",description:"Endpoint path (e.g. /api/v1/users)",minLength:1},method:{type:"string",description:"HTTP method (GET, POST, PUT, DELETE, etc.)",enum:[...c.map(e=>e.toUpperCase()),...c],minLength:1},version:{type:"string",description:"API version. When omitted and several versions exist, the highest one is used",nullable:!0},filePath:{type:"string",description:"API definition file path, as returned by `listApis`",nullable:!0}}},L={type:"object",required:[],additionalProperties:!1,properties:{}},q={type:"object",required:[],additionalProperties:!1,properties:{}},O={type:"object",required:["path","summary"],additionalProperties:!1,properties:{path:{type:"string",description:"Path or URL of the documentation page the feedback is about (e.g. /guides/auth)",minLength:1,maxLength:1e3},summary:{type:"string",description:"One sentence that names what is wrong with the page",minLength:1,maxLength:500},details:{type:"string",description:"Expected versus actual behavior, missing steps, or the snippet that failed",maxLength:4e3,nullable:!0},targetFeature:{type:"string",description:"The API or feature the page documents",maxLength:500,nullable:!0}}};function T(e){const t=[{name:"list-apis",title:"List APIs",description:"Lists the APIs documented in this project",schema:S,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",properties:{items:{type:"array",items:{type:"object",properties:{name:{type:"string"},description:i,version:i,servers:a,filePath:{type:"string",description:"API definition file path"},ambiguousTitle:{type:"boolean",description:"true = another API shares this title; a lookup picks the highest version, or the shortest file path at the same version, and lists the rest in `otherMatches`. Pass `filePath` to pick another one"},...e.hasCallableApis?{callable:{type:"boolean",description:"true = the documented hosts of this API are reachable via `fetch`; false = documentation only"}}:{}}}},...s}}},{name:"get-endpoints",title:"Get endpoints",description:`Get all endpoints for a specific API. ${r}`,schema:p,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",required:["filePath"],properties:{api:{type:"string"},version:{type:"string"},...n,servers:a,endpoints:{type:"array",items:{type:"object",properties:{path:{type:"string"},method:{type:"string"},summary:i,description:i,security:o}}}}}},{name:"get-endpoint-info",title:"Get endpoint info",description:`Get comprehensive information about specific endpoint including parameters, security, and examples. ${r}`,schema:H,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",required:["filePath"],properties:{api:{type:"string"},version:{type:"string"},...n,servers:a,endpoint:A,globalSecurity:o,securitySchemes:u}}},{name:"get-security-schemes",title:"Get security schemes",description:`Get the security schemes for a specific API. ${r}`,schema:p,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",required:["filePath"],properties:{name:i,version:i,...n,securitySchemes:u,security:o}}},{name:"get-full-api-description",title:"Get full API description",description:`Get the complete OpenAPI description. ${r}`,schema:p,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",required:["filePath"],properties:{api:{type:"string"},version:{type:"string"},...n,definition:P}}},...y?[d(e.products,e.locales)]:[]];return f(e.requiresLogin,e.rbac)&&t.push({name:"whoami",title:"Who am I",description:"Get information about the currently authenticated user",schema:L,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",properties:{email:{type:"string"},name:{type:"string"},subject:{type:"string"},clientId:{type:"string"},scope:{type:"string"},issuedAt:{type:"string"},expiresAt:{type:"string"}}}}),e.feedbackHidden||t.push({name:b,title:"Submit feedback",description:"Report a documentation page that is wrong or incomplete",schema:O,annotations:{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!1,openWorldHint:!1},outputSchema:{type:"object",required:["status","page","message"],properties:{status:{type:"string"},page:{type:"string"},message:{type:"string"}}}}),e.hasGraphqlApis&&t.push(...E()),e.elicitationEnabled&&e.hasCallableApis&&t.push({name:g,title:"Create anonymous session",description:"Create an anonymous session handle for storing upstream API credentials. Pass the returned sessionHandle to execute when an API needs credentials and the caller is not signed in. Treat it as a secret and reuse it across calls.",schema:q,annotations:{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!1,openWorldHint:!1},outputSchema:{type:"object",required:["sessionHandle"],properties:{sessionHandle:{type:"string"}}}}),t}const G={type:"object",required:[],additionalProperties:!1,properties:{filter:{type:"string",description:"GraphQL schema name (or part of it)",minLength:1,nullable:!0},page:{type:"number",description:"Page number",minimum:1,default:1,nullable:!0},limit:{type:"number",description:"Number of results per page. Default is 300",minimum:1,default:300,nullable:!0}}},w={type:"object",required:["name"],additionalProperties:!1,properties:{name:{type:"string",description:"GraphQL schema name",minLength:1},kind:{type:"string",description:'Optional: return only a single category of schema members. With scope "fields", restricts to the fields of that parent category ("objects", "interfaces", or "inputs" only).',enum:[...l,null],nullable:!0},scope:{type:"string",description:'Optional: what each list item is. "members" (default) lists top-level types and operations. "fields" flattens every field of every object/interface/input type into "ParentType.fieldName" entries with their descriptions \u2014 combine with `filter` to search nested fields anywhere in the schema.',enum:[...v,null],nullable:!0},filter:{type:"string",description:'Optional: only members whose name or description contains this substring, case-insensitive (e.g. "custom tags")',minLength:1,nullable:!0},referencesType:{type:"string",description:'Optional: only members that reference this type directly or transitively (via return, field, argument, union-member or input-field types). Finds cross-cutting members that never name it \u2014 e.g. referencesType "Book" surfaces a search query returning a union that includes Book.',minLength:1,nullable:!0},page:{type:"number",description:"Page number",minimum:1,default:1,nullable:!0},limit:{type:"number",description:"Number of results per page. Default is 300",minimum:1,default:300,nullable:!0}}},I={type:"object",required:["name"],additionalProperties:!1,properties:{name:{type:"string",description:"GraphQL schema name",minLength:1},type:{type:"string",description:"Name of the type, operation, or directive",minLength:1,nullable:!0},typeName:{type:"string",description:"Alias of `type`",nullable:!0},includeReferencedTypes:{type:"boolean",description:"Also include the SDL of every type referenced transitively. Gives the whole subgraph at once, but can be large for highly-connected types.",default:!1,nullable:!0}}},j={type:"object",required:["name"],additionalProperties:!1,properties:{name:{type:"string",description:"GraphQL schema name",minLength:1}}};function E(){return[{name:"list-graphql-apis",title:"List GraphQL APIs",description:"Lists available GraphQL schemas with their context and purpose",schema:G,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",properties:{items:{type:"array",items:{type:"object",properties:{name:{type:"string"},description:i}}},...s}}},{name:"get-graphql-type-list",title:"Get GraphQL type list",description:'List all operations and types in a GraphQL schema as a flat, paginated list. Each item is tagged with its kind (query, object, enum, \u2026) and carries a one-line description; operations also include their return type and argument signature \u2014 use it to decide which members to fetch in detail. Narrow the result with `kind` (one category), `filter` (case-insensitive substring of the member name or description, e.g. "book"), or `referencesType` (only members that use a given type, directly or transitively) to explore a domain cheaply instead of pulling the full schema. To search nested fields \u2014 not just type names \u2014 set scope "fields": it flattens every field of every object/interface/input type into "ParentType.fieldName" entries with their descriptions, so `filter` finds things like an input field whose docstring mentions your keyword.',schema:w,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",properties:{name:{type:"string"},items:{type:"array",items:{type:"object",properties:{kind:{type:"string",enum:l},name:{type:"string"},description:i,type:{type:"string"},args:{type:"string"},directives:{type:"string"}}}},...s}}},{name:"get-graphql-type",title:"Get GraphQL type",description:'Get the SDL for a single GraphQL type, operation (query/mutation/subscription field), or directive. Without includeReferencedTypes, the SDL is followed by a one-level manifest of every directly referenced type\'s field names (e.g. "input ActionOperationInput { addTags, removeTags }"), so you can see what nested types contain before fetching them. Set includeReferencedTypes to instead pull in the full SDL of every type it references transitively \u2014 the whole structural subgraph in one call, ideal for complete exploration of an entity (e.g. Book and all the types it touches). That traversal only follows what the target depends on; to go the other direction and find the members that use a type, call get-graphql-type-list with `referencesType`.',schema:I,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"string"}},{name:"get-graphql-schema",title:"Get GraphQL schema",description:"Get the complete GraphQL schema as SDL \u2014 the whole type graph in one call. Returns everything, so it can be very large and token-expensive for big schemas; prefer get-graphql-type-list (filter/paginate) plus targeted get-graphql-type calls, and reach for this only for small schemas or when you truly need the full SDL.",schema:j,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"string"}}]}function d(e,t){const h=e&&e.length>0,m=t&&t.length>0;return{name:"search",title:"Search documentation",description:"Search across the documentation to fetch relevant content for a given query",schema:{type:"object",required:["query"],additionalProperties:!1,properties:{query:{type:"string",description:"Search query. Should be a single word or that phrase that is presented in a documentation.",minLength:1},...h?{product:{type:"string",description:"Optional product name to filter search results by specific product.",enum:[...e,null],nullable:!0}}:{},...m?{locale:{type:"string",description:"Optional locale code to filter search results by documentation language (e.g. 'en', 'ja'). Use the locale matching the language of the user's request. Defaults to the project's default locale.",enum:[...t,null],nullable:!0}}:{}}},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!1,openWorldHint:!1},outputSchema:{type:"string"}}}const x=new Set([...T({requiresLogin:!0,hasGraphqlApis:!0,elicitationEnabled:!0,hasCallableApis:!0}).map(e=>e.name),d().name]);export{x as ALL_DEFAULT_TOOL_NAMES,T as getDefaultToolSchemas};
@@ -0,0 +1,7 @@
1
+ import type { McpToolHandler } from '../../../types.js';
2
+ import type { SubmitFeedbackArgs } from './types.js';
3
+ declare const _default: {
4
+ "submit-feedback": McpToolHandler<SubmitFeedbackArgs>;
5
+ };
6
+ export default _default;
7
+ //# sourceMappingURL=submit-feedback.d.ts.map
@@ -0,0 +1,3 @@
1
+ import{getPathPrefix as p,withPathPrefix as h,withoutPathPrefix as l}from"@redocly/theme/core/utils";import{ServerRoutes as g}from"../../../../../../constants/api.js";import{normalizeRouteSlug as b}from"../../../../../../utils/path/normalize-route-slug.js";import{SUBMIT_FEEDBACK_TOOL_NAME as y}from"../../../constants.js";const k="mcp",P="mcp-client";function r(t,e=!1){return{content:[{type:"text",text:JSON.stringify(t)}],isError:e}}function i(t){const e=t?.trim();return e||void 0}function U(t){const e=p();return!!e&&(t===e||t.startsWith(`${e}/`))?l(t):t}function F(t,e){try{const{pathname:n}=new URL(t,e),a=new URL(e);return a.pathname=U(b(n)),a.toString()}catch{return}}function T(t){const e=t.client??P;return t.clientVersion?`${e}/${t.clientVersion}`:e}async function A(t){const n=(await t.json().catch(()=>{}))?.errors;return Array.isArray(n)?n.filter(a=>typeof a=="string"):[]}const E=async(t,e)=>{const n=i(t.path),a=i(t.summary);if(!n||!a)return r({error:"Invalid arguments",message:"`path` and `summary` are required."},!0);const c=e.baseUrl;if(!c)return r({error:"Unavailable",message:"The feedback endpoint of this site is not configured."},!0);const s=F(n,c);if(!s)return r({error:"Invalid arguments",message:"`path` must be a page path or URL of this site."},!0);const u=i(t.details),d=T(e),f=e.accessToken?.replace(/^Bearer /,""),m=`${e.internalBaseUrl||c}${h(g.FEEDBACK)}`;let o;try{o=await fetch(m,{method:"POST",headers:{"Content-Type":"application/json","User-Agent":d,...f?{Cookie:`authorization=${f}`}:{},...e.clientIp?{"X-Real-IP":e.clientIp}:{}},body:JSON.stringify({component:"comment",path:s,comment:u?`${a}
2
+
3
+ ${u}`:a,agent:d,targetFeature:i(t.targetFeature),origin:k})})}catch{return r({error:"Failed to submit feedback",message:"The feedback endpoint could not be reached."},!0)}return o.status===403?r({error:"Forbidden",message:"You have no access to this page, so feedback for it is not accepted."},!0):o.status===404?r({error:"Not found",message:`No page exists at ${s}.`},!0):o.status===400?r({error:"Invalid feedback",errors:await A(o)},!0):o.ok?r({status:"received",page:s,message:"Thanks for your feedback. The documentation team sees it on the Feedback page."}):r({error:"Failed to submit feedback",message:`The feedback endpoint answered ${o.status}.`},!0)};var N={[y]:E};export{N as default};
@@ -4,4 +4,10 @@ export type SearchArgs = {
4
4
  locale?: string | null;
5
5
  };
6
6
  export type WhoamiArgs = Record<string, never>;
7
+ export type SubmitFeedbackArgs = {
8
+ path: string;
9
+ summary: string;
10
+ details?: string;
11
+ targetFeature?: string;
12
+ };
7
13
  //# sourceMappingURL=types.d.ts.map
@@ -10,6 +10,7 @@ declare const _default: {
10
10
  'get-full-api-description': import("../../types.js").McpToolHandler<import("./openapi/types.js").ApiNameVersionArgs>;
11
11
  search: import("../../types.js").McpToolHandler<import("./core/types.js").SearchArgs>;
12
12
  whoami: import("../../types.js").McpToolHandler<import("./core/types.js").WhoamiArgs>;
13
+ "submit-feedback": import("../../types.js").McpToolHandler<import("./core/types.js").SubmitFeedbackArgs>;
13
14
  'list-graphql-apis': import("../../types.js").McpToolHandler<import("./graphql/types.js").ListGraphqlApisArgs>;
14
15
  'get-graphql-type-list': import("../../types.js").McpToolHandler<import("./graphql/types.js").GetGraphqlTypeListArgs>;
15
16
  'get-graphql-type': import("../../types.js").McpToolHandler<import("./graphql/types.js").GetGraphqlTypeArgs>;
@@ -1 +1 @@
1
- import o from"./openapi/list-apis.js";import r from"./openapi/get-endpoints.js";import t from"./openapi/get-endpoint-info.js";import m from"./openapi/get-security-schemes.js";import i from"./openapi/get-full-api-description.js";import p from"./core/search.js";import e from"./core/whoami.js";import f from"./core/create-anonymous-session.js";import s from"./graphql/list-graphql-apis.js";import a from"./graphql/get-graphql-type-list.js";import l from"./graphql/get-graphql-type.js";import n from"./graphql/get-graphql-schema.js";var w={...o,...r,...t,...m,...i,...p,...e,...f,...s,...a,...l,...n};export{w as default};
1
+ import o from"./openapi/list-apis.js";import r from"./openapi/get-endpoints.js";import m from"./openapi/get-endpoint-info.js";import t from"./openapi/get-security-schemes.js";import i from"./openapi/get-full-api-description.js";import p from"./core/search.js";import e from"./core/whoami.js";import f from"./core/create-anonymous-session.js";import s from"./core/submit-feedback.js";import a from"./graphql/list-graphql-apis.js";import l from"./graphql/get-graphql-type-list.js";import n from"./graphql/get-graphql-type.js";import h from"./graphql/get-graphql-schema.js";var k={...o,...r,...m,...t,...i,...p,...e,...f,...s,...a,...l,...n,...h};export{k as default};
@@ -1 +1 @@
1
- import{resolveParameters as l,resolveRequestBody as f,resolveResponses as y}from"../../utils/resolve-refs.js";import{isMcpEndpoint as x}from"./utils.js";import{describeMethodMiss as v,describePathMiss as E,visibleMethodsAt as M}from"./endpoint-suggestions.js";import{loadApiDescription as g}from"./load-api-description.js";import{checkEndpointAndDeleteXMcp as P}from"../../../utils/xmcp-utils.js";const b=async(p,a)=>{const{path:r,method:o}=p;if(!r||!o)return{content:[{type:"text",text:'Both "path" and "method" are required (e.g. path: "/tickets", method: "GET").'}],isError:!0};let e;try{e=await g(p,a)}catch(u){return{content:[{type:"text",text:u.message}],isError:!0}}const s=r.startsWith("/")?r:`/${r}`,{title:n=""}=e.info||{},i=e.paths?.[s],c=o.toLowerCase();if(!i||M(e,s).length===0)return{content:[{type:"text",text:E(e,n,s,a.mcpMode)}],isError:!0};const t=i[c];if(!x(t)||!P(t,"docs"))return{content:[{type:"text",text:v(e,n,s,o)}],isError:!0};const d=i?.parameters||[],m=t.parameters||[],h={...t,parameters:l({pathParams:d,opParams:m,definition:e}),requestBody:f(t.requestBody,e),responses:y(t.responses,e)};return{content:[{type:"text",text:JSON.stringify({api:n,version:e.info?.version||"",servers:e.servers||[],endpoint:{path:r,method:o.toUpperCase(),...h},globalSecurity:e.security||[],securitySchemes:e.components?.securitySchemes||{}},null,2)}]}};var C={"get-endpoint-info":b};export{C as default};
1
+ import{resolveParameters as v,resolveRequestBody as E,resolveResponses as M}from"../../utils/resolve-refs.js";import{isMcpEndpoint as P}from"./utils.js";import{describeMethodMiss as g,describePathMiss as b,visibleMethodsAt as q}from"./endpoint-suggestions.js";import{loadApiDescription as B}from"./load-api-description.js";import{checkEndpointAndDeleteXMcp as S}from"../../../utils/xmcp-utils.js";const k=async(c,d)=>{const{path:r,method:o}=c;if(!r||!o)return{content:[{type:"text",text:'Both "path" and "method" are required (e.g. path: "/tickets", method: "GET").'}],isError:!0};let h;try{h=await B(c,d)}catch(p){return{content:[{type:"text",text:p.message}],isError:!0}}const{description:t,filePath:l,otherMatches:n}=h,m=n?` Other definitions share this title: ${n.map(p=>`"${p.filePath}"`).join(", ")}. Pass "filePath" to check them.`:"",s=r.startsWith("/")?r:`/${r}`,{title:i=""}=t.info||{},a=t.paths?.[s],f=o.toLowerCase();if(!a||q(t,s).length===0)return{content:[{type:"text",text:b(t,i,s,d.mcpMode)+m}],isError:!0};const e=a[f];if(!P(e)||!S(e,"docs"))return{content:[{type:"text",text:g(t,i,s,o)+m}],isError:!0};const u=a?.parameters||[],y=e.parameters||[],x={...e,parameters:v({pathParams:u,opParams:y,definition:t}),requestBody:E(e.requestBody,t),responses:M(e.responses,t)};return{content:[{type:"text",text:JSON.stringify({api:i,version:t.info?.version||"",filePath:l,otherMatches:n,servers:t.servers||[],endpoint:{path:r,method:o.toUpperCase(),...x},globalSecurity:t.security||[],securitySchemes:t.components?.securitySchemes||{}},null,2)}]}};var D={"get-endpoint-info":k};export{D as default};
@@ -1 +1 @@
1
- import{loadApiDescription as i}from"./load-api-description.js";import{getEndpointsFromPaths as s}from"./utils.js";const p=async(e,r)=>{let t;try{t=await i(e,r)}catch(o){return{content:[{type:"text",text:o.message}],isError:!0}}const n=s(t);return{content:[{type:"text",text:JSON.stringify({api:t.info?.title||"",version:t.info?.version||"",servers:t.servers||[],endpoints:n},null,2)}]}};var d={"get-endpoints":p};export{d as default};
1
+ import{loadApiDescription as a}from"./load-api-description.js";import{getEndpointsFromPaths as c}from"./utils.js";const d=async(r,n)=>{let e;try{e=await a(r,n)}catch(p){return{content:[{type:"text",text:p.message}],isError:!0}}const{description:t,filePath:o,otherMatches:i}=e,s=c(t);return{content:[{type:"text",text:JSON.stringify({api:t.info?.title||"",version:t.info?.version||"",filePath:o,otherMatches:i,servers:t.servers||[],endpoints:s},null,2)}]}};var m={"get-endpoints":d};export{m as default};
@@ -1 +1 @@
1
- import{loadApiDescription as n}from"./load-api-description.js";const o=async(e,i)=>{let t;try{t=await n(e,i)}catch(r){return{content:[{type:"text",text:r.message}],isError:!0}}return{content:[{type:"text",text:JSON.stringify({api:t.info?.title||"",version:t.info?.version||"",definition:t},null,2)}]}};var s={"get-full-api-description":o};export{s as default};
1
+ import{loadApiDescription as a}from"./load-api-description.js";const c=async(i,r)=>{let e;try{e=await a(i,r)}catch(s){return{content:[{type:"text",text:s.message}],isError:!0}}const{description:t,filePath:n,otherMatches:o}=e;return{content:[{type:"text",text:JSON.stringify({api:t.info?.title||"",version:t.info?.version||"",filePath:n,otherMatches:o,definition:t},null,2)}]}};var p={"get-full-api-description":c};export{p as default};
@@ -1 +1 @@
1
- import{loadApiDescription as s}from"./load-api-description.js";const c=async(t,r)=>{let e;try{e=await s(t,r)}catch(i){return{content:[{type:"text",text:i.message}],isError:!0}}return{content:[{type:"text",text:JSON.stringify({name:e.info?.title,version:e.info?.version,securitySchemes:e.components?.securitySchemes||{},security:e.security||[]},null,2)}]}};var o={"get-security-schemes":c};export{o as default};
1
+ import{loadApiDescription as o}from"./load-api-description.js";const a=async(r,s)=>{let t;try{t=await o(r,s)}catch(n){return{content:[{type:"text",text:n.message}],isError:!0}}const{description:e,filePath:i,otherMatches:c}=t;return{content:[{type:"text",text:JSON.stringify({name:e.info?.title,version:e.info?.version,filePath:i,otherMatches:c,securitySchemes:e.components?.securitySchemes||{},security:e.security||[]},null,2)}]}};var y={"get-security-schemes":a};export{y as default};
@@ -1 +1 @@
1
- import{isFetchCapable as d}from"../../../gateway-mcp/callable-apis.js";import{filterApiDescriptionsByName as h}from"../../utils/api-name-matching.js";import{apiTitleKey as y,countApiTitles as x}from"../../utils/api-titles.js";const A=async(c,i)=>{const{filter:s,page:l=1,limit:e=300}=c,p=d(i),n=Object.values(i.apiDescriptionsMap),r=x(n);let t=n;s&&(t=h(t,s));const a=(l-1)*e,m=a+e,u=Math.ceil(t.length/e),f=t.length;return t=t.slice(a,m),{content:[{type:"text",text:JSON.stringify({items:t.map(({relativePath:g,fetchEligible:b,...o})=>({filePath:g,...o,...(r.get(y(o.name))??0)>1?{ambiguousTitle:!0}:{},...p?{callable:b===!0}:{}})),limit:e,total:f,page:l,totalPages:u})}]}};var I={"list-apis":A};export{I as default};
1
+ import{isFetchCapable as h}from"../../../gateway-mcp/callable-apis.js";import{filterApiDescriptionsByName as b}from"../../utils/api-name-matching.js";import{apiTitleKey as y,countApiTitles as T,orderSharedTitles as x}from"../../utils/api-titles.js";const A=async(r,i)=>{const{filter:s,page:l=1,limit:e=300}=r,c=h(i),a=x(Object.values(i.apiDescriptionsMap)),p=T(a);let t=a;s&&(t=b(t,s));const n=(l-1)*e,m=n+e,u=Math.ceil(t.length/e),f=t.length;return t=t.slice(n,m),{content:[{type:"text",text:JSON.stringify({items:t.map(({relativePath:d,fetchEligible:g,...o})=>({filePath:d,...o,...(p.get(y(o.name))??0)>1?{ambiguousTitle:!0}:{},...c?{callable:g===!0}:{}})),limit:e,total:f,page:l,totalPages:u})}]}};var M={"list-apis":A};export{M as default};
@@ -1,10 +1,22 @@
1
1
  import type { OpenAPIDefinition } from '@redocly/api-docs';
2
2
  import type { McpToolContext } from '../../../types.js';
3
- export declare function loadApiDescription(args: {
3
+ type ApiDescriptionRef = {
4
+ version?: string;
5
+ filePath: string;
6
+ };
7
+ type LoadedApiDescription = {
8
+ description: OpenAPIDefinition;
9
+ filePath: string;
10
+ otherMatches?: ApiDescriptionRef[];
11
+ };
12
+ type ApiLookup = {
4
13
  name?: string;
5
- apiName?: string;
6
- api?: string;
7
14
  version?: string;
8
15
  filePath?: string;
9
- }, context: McpToolContext): Promise<OpenAPIDefinition>;
16
+ };
17
+ export declare function loadApiDescription(args: ApiLookup & {
18
+ apiName?: string;
19
+ api?: string;
20
+ }, context: McpToolContext): Promise<LoadedApiDescription>;
21
+ export {};
10
22
  //# sourceMappingURL=load-api-description.d.ts.map
@@ -1 +1 @@
1
- import{describeAvailableApis as l,findApiDescriptionByNameAndVersion as h}from"../../utils/api-name-matching.js";import{getApiDescriptionFromFs as u}from"./utils.js";async function P(o,i){const{version:p,filePath:e}=o,r=o.name??o.apiName??o.api;if(!e&&!r)throw new Error("Pass `name` (the API title, or a unique part of it) or `filePath` from list-apis.");const t=Object.values(i.apiDescriptionsMap),n=e?t.find(a=>a.relativePath===e):t.find(a=>a.relativePath===r)??h(i.apiDescriptionsMap,r??"",p);if(!n){if(e)throw new Error(`No API found with filePath "${e}". File paths are returned by the list-apis tool.`);const a=l(i.apiDescriptionsMap,r??"");throw new Error(a?`No API found matching "${r}". Available APIs: ${a}.`:`No API found matching "${r}".`)}const c=!!i?.config?.access?.requiresLogin,f=i?.config?.access?.rbac||{},s=await u({relativePath:n.relativePath||"",outdir:i.outdir||"",user:i.user,rbac:f,requiresLogin:c});if(!s)throw new Error(`No API found matching "${e||r}".`);return s}export{P as loadApiDescription};
1
+ import{describeAvailableApis as u,findApiDescriptionByNameAndVersion as d}from"../../utils/api-name-matching.js";import{getApiDescriptionFromFs as m}from"./utils.js";function P({name:i,version:t,filePath:c},o){const e=Object.values(o);if(c)return e.filter(s=>s.relativePath===c);const r=e.find(s=>s.relativePath===i);if(r)return[r];const a=d(o,i??"",t);return a?[a.description,...a.otherMatches??[]]:[]}function A({version:i,relativePath:t}){return{...i?{version:i}:{},filePath:t}}async function w(i,t){const{version:c,filePath:o}=i,e=i.name??i.apiName??i.api;if(!o&&!e)throw new Error("Pass `name` (the API title, or a unique part of it) or `filePath` from list-apis.");const r=P({name:e,version:c,filePath:o},t.apiDescriptionsMap);if(r.length===0){if(o)throw new Error(`No API found with filePath "${o}". File paths are returned by the list-apis tool.`);const n=u(t.apiDescriptionsMap,e??"");throw new Error(n?`No API found matching "${e}". Available APIs: ${n}.`:`No API found matching "${e}".`)}const a=!!t?.config?.access?.requiresLogin,s=t?.config?.access?.rbac||{};for(const n of r){const f=await m({relativePath:n.relativePath,outdir:t.outdir||"",user:t.user,rbac:s,requiresLogin:a});if(!f)continue;const h=r.filter(p=>p!==n);return{description:f,filePath:n.relativePath,otherMatches:h.length>0?h.map(A):void 0}}const l=r.map(({relativePath:n})=>`"${n}"`).join(", ");throw new Error(r.length>1?`No API found matching "${e}". None of the matching definitions could be loaded: ${l}.`:`No API found matching "${o||e}".`)}export{w as loadApiDescription};
@@ -1,8 +1,13 @@
1
1
  import type { ApiDescriptionInfo } from '../../types.js';
2
2
  export declare const MAX_LISTED_CANDIDATES = 15;
3
+ export type ApiDescriptionMatch = {
4
+ description: ApiDescriptionInfo;
5
+ /** The other definitions the lookup matched, absent when it matched exactly one. */
6
+ otherMatches?: ApiDescriptionInfo[];
7
+ };
3
8
  export declare function formatCandidates(items: string[]): string;
4
9
  /** Every API name in the catalog, closest to `name` first. Used to make a miss recoverable. */
5
10
  export declare function describeAvailableApis(apiDescriptionsMap: Record<string, ApiDescriptionInfo>, name: string): string;
6
- export declare function findApiDescriptionByNameAndVersion(apiDescriptionsMap: Record<string, ApiDescriptionInfo>, name: string, version?: string): ApiDescriptionInfo | undefined;
11
+ export declare function findApiDescriptionByNameAndVersion(apiDescriptionsMap: Record<string, ApiDescriptionInfo>, name: string, version?: string): ApiDescriptionMatch | undefined;
7
12
  export declare function filterApiDescriptionsByName(apiDescriptions: ApiDescriptionInfo[], filter: string): ApiDescriptionInfo[];
8
13
  //# sourceMappingURL=api-name-matching.d.ts.map
@@ -1 +1 @@
1
- const $=15,p=new Set(["api","apis","rest","restful","openapi","graphql","spec","specification","service","services"]);function w(s){return s.toLowerCase().split(/[^a-z0-9_]+/).filter(Boolean)}function f(s){return new Set(w(s).filter(t=>!p.has(t)))}function d(s,t){return s.size===t.size&&[...s].every(n=>t.has(n))}function h(s){const t=s.slice(0,15),n=s.length-t.length;return n>0?`${t.join(", ")} (+${n} more)`:t.join(", ")}function v(s,t){const n=f(t);return[...new Set(s.map(e=>e.name))].map(e=>({name:e,score:[...f(e)].filter(r=>n.has(r)).length})).sort((e,r)=>r.score-e.score||e.name.localeCompare(r.name)).map(({name:e})=>e)}function g(s,t){const n=Object.values(s);return n.length===0?"":h(v(n,t).map(e=>`"${e}"`))}function T(s,t){const n=t.trim().toLowerCase();if(!n)return{matches:[],isExactTitle:!1};const e=s.map(a=>({api:a,title:a.name.trim().toLowerCase()})),r=a=>a.map(({api:o})=>o),i=e.filter(({title:a})=>a===n);if(i.length>0)return{matches:r(i),isExactTitle:!0};const l=e.filter(({title:a})=>a.includes(n));if(l.length>0)return{matches:r(l),isExactTitle:!1};const m=f(n);if(m.size===0)return{matches:[],isExactTitle:!1};const u=e.filter(({title:a})=>{const o=f(a);return o.size>0&&d(o,m)});return{matches:r(u),isExactTitle:!1}}function A(s,t,n){if(!t)return;const{matches:e,isExactTitle:r}=T(Object.values(s),t);if(e.length===0)return;if(!r){const o=[...new Set(e.map(({name:c})=>c))];if(o.length>1)throw new Error(`"${t}" matches ${o.length} APIs: ${h(o.map(c=>`"${c}"`))}. Pass one of those names exactly, or the "filePath" parameter from list-apis.`)}const i=n?e.filter(o=>o.version===n):e;if(i.length===0){const o=[...new Set(e.map(({version:c})=>c||"(no version)"))];throw new Error(`"${e[0].name||t}" has no version "${n}". Available versions: ${h(o)}.`)}if(i.length===1)return i[0];const l=i[0].name||t;if(new Set(i.map(({version:o})=>o||"")).size>1){const o=i.map(({version:c})=>c||"(no version)").join(", ");throw new Error(`Multiple versions of "${l}" found: ${o}. Specify a version to disambiguate.`)}const u=i.map(({relativePath:o})=>`"${o||"(unknown path)"}"`).join(", "),a=i[0].version?` at version "${i[0].version}"`:"";throw new Error(`Multiple APIs are titled "${l}"${a}. Pass the "filePath" parameter to select one of: ${u}.`)}function E(s,t){const n=t.trim().toLowerCase();if(!n)return s;const e=s.filter(({name:r})=>r.toLowerCase().includes(n));return e.length>0?e:s.filter(({description:r})=>!!r?.toLowerCase().includes(n))}export{$ as MAX_LISTED_CANDIDATES,g as describeAvailableApis,E as filterApiDescriptionsByName,A as findApiDescriptionByNameAndVersion,h as formatCandidates};
1
+ import{apiTitleKey as u,compareApiDescriptions as h}from"./api-titles.js";const T=15,d=new Set(["api","apis","rest","restful","openapi","graphql","spec","specification","service","services"]);function g(r){return r.toLowerCase().split(/[^a-z0-9_]+/).filter(Boolean)}function f(r){return new Set(g(r).filter(n=>!d.has(n)))}function w(r,n){return r.size===n.size&&[...r].every(e=>n.has(e))}function m(r){const n=r.slice(0,T),e=r.length-n.length;return e>0?`${n.join(", ")} (+${e} more)`:n.join(", ")}function x(r,n){const e=f(n);return[...new Set(r.map(t=>t.name))].map(t=>({name:t,score:[...f(t)].filter(s=>e.has(s)).length})).sort((t,s)=>s.score-t.score||t.name.localeCompare(s.name)).map(({name:t})=>t)}function E(r,n){const e=Object.values(r);return e.length===0?"":m(x(e,n).map(t=>`"${t}"`))}function A(r,n){const e=u(n);if(!e)return{matches:[],isExactTitle:!1};const t=r.map(o=>({api:o,title:u(o.name)})),s=o=>o.map(({api:l})=>l),c=t.filter(({title:o})=>o===e);if(c.length>0)return{matches:s(c),isExactTitle:!0};const i=t.filter(({title:o})=>o.includes(e));if(i.length>0)return{matches:s(i),isExactTitle:!1};const a=f(e);if(a.size===0)return{matches:[],isExactTitle:!1};const p=t.filter(({title:o})=>{const l=f(o);return l.size>0&&w(l,a)});return{matches:s(p),isExactTitle:!1}}function k(r){const[n,...e]=[...r].sort(h);return e.length===0?{description:n}:{description:n,otherMatches:e}}function S(r,n,e){if(!n)return;const{matches:t,isExactTitle:s}=A(Object.values(r),n);if(t.length===0)return;if(!s){const i=[...new Set(t.map(({name:a})=>a))];if(i.length>1)throw new Error(`"${n}" matches ${i.length} APIs: ${m(i.map(a=>`"${a}"`))}. Pass one of those names exactly, or the "filePath" parameter from list-apis.`)}const c=e?t.filter(i=>i.version===e):t;if(c.length===0){const i=[...new Set(t.map(({version:a})=>a||"(no version)"))];throw new Error(`"${t[0].name||n}" has no version "${e}". Available versions: ${m(i)}.`)}return k(c)}function $(r,n){const e=n.trim().toLowerCase();if(!e)return r;const t=r.filter(({name:s})=>s.toLowerCase().includes(e));return t.length>0?t:r.filter(({description:s})=>!!s?.toLowerCase().includes(e))}export{T as MAX_LISTED_CANDIDATES,E as describeAvailableApis,$ as filterApiDescriptionsByName,S as findApiDescriptionByNameAndVersion,m as formatCandidates};
@@ -3,4 +3,12 @@ import type { ApiDescriptionInfo } from '../../types.js';
3
3
  export declare function apiTitleKey(name: string): string;
4
4
  /** How many APIs carry each title, keyed by `apiTitleKey`, so a shared title is detectable. */
5
5
  export declare function countApiTitles(apis: ApiDescriptionInfo[]): Map<string, number>;
6
+ /** The highest version, then the shortest path, so the same catalog always yields the same pick. */
7
+ export declare function compareApiDescriptions(a: ApiDescriptionInfo, b: ApiDescriptionInfo): number;
8
+ /**
9
+ * Orders the APIs that share a title the way a name lookup picks, so code that takes the first
10
+ * matching item gets the same definition. Each title keeps the positions it already occupied,
11
+ * so no other API moves.
12
+ */
13
+ export declare function orderSharedTitles(apis: ApiDescriptionInfo[]): ApiDescriptionInfo[];
6
14
  //# sourceMappingURL=api-titles.d.ts.map
@@ -1 +1 @@
1
- function r(t){return t.trim().toLowerCase()}function c(t){const e=new Map;for(const{name:o}of t){const n=r(o);e.set(n,(e.get(n)??0)+1)}return e}export{r as apiTitleKey,c as countApiTitles};
1
+ import c from"semver";import{compareVersions as p}from"../../../../../utils/version/compare-versions.js";function a(e){return e.trim().toLowerCase()}function h(e){const t=new Map;for(const{name:n}of e){const o=a(n);t.set(o,(t.get(o)??0)+1)}return t}function l(e,t){return c.valid(e)&&c.valid(t)?c.rcompare(e,t):p(t,e)}function f(e,t){return l(e.version||"",t.version||"")||e.relativePath.length-t.relativePath.length||e.relativePath.localeCompare(t.relativePath)}function v(e){const t=new Map;e.forEach((o,i)=>{const r=a(o.name),s=t.get(r);s?s.push(i):t.set(r,[i])});const n=[...e];for(const o of t.values()){if(o.length===1)continue;const i=o.map(r=>e[r]).sort(f);o.forEach((r,s)=>{n[r]=i[s]})}return n}export{a as apiTitleKey,f as compareApiDescriptions,h as countApiTitles,v as orderSharedTitles};
@@ -1 +1 @@
1
- import{logger as u}from"../../../tools/notifiers/logger.js";import{getFeedbackClientIp as N}from"../../../web-server/utils/feedback-ip.js";import{getForwardedOrigin as g,getInternalOrigin as F}from"../../../web-server/utils/get-request-origin.js";import{GATEWAY_FETCH_LIMIT_DEFAULTS as v}from"../../../../constants/common.js";import{isObject as k}from"../../../../utils/guards/is-object.js";import{getAccessibleSkills as B}from"../../../utils/skills/get-accessible-skills.js";import{getSkillUrl as L}from"../../../utils/skills/get-skill-url.js";import{createMcpHandler as H}from"@modelcontextprotocol/server";import{createDocsMcpServer as V}from"../servers/docs-server.js";import{filterApiDescriptionsByRbac as $,filterGraphqlDescriptionsByRbac as j}from"../utils.js";import{McpClientInputError as G,createMethodNotAllowedError as J,withErrorHandling as K}from"./errors.js";import{constructForbiddenResponse as Y,constructInvalidTokenResponse as z,constructUnauthorizedResponse as W,handleMcpAuth as X}from"../auth/auth-handlers.js";import{shouldHandleMcpAuth as Q}from"../../../utils/rbac/should-handle-mcp-auth.js";import{canAnonymousAccessMcpFeature as Z}from"../../../utils/rbac/can-anonymous-access-mcp-feature.js";import{extractTokenFromAuthHeader as q}from"../utils/jwt.js";import{resolveMcpClient as x}from"../utils/mcp-client.js";import{DEFAULT_DOCS_MCP_SERVER_NAME as ee,SSE_KEEPALIVE_INTERVAL_MS as re}from"../constants.js";import{withPathPrefix as oe}from"@redocly/theme/core/utils";import{PUBLIC_MCP_ROUTE as se}from"@redocly/theme/core/constants/mcp";import{canAccessFeature as ne}from"../../../utils/rbac.js";import{ANONYMOUS_AUTH_DETAILS as ie}from"../../../constants/rbac.js";import{DEFAULT_ANONYMOUS_VISITOR_TEAM as te,RbacFeatures as ce}from"../../../../constants/common.js";const h="X-Redocly-AI-Metadata";function ae(r){if(r)try{const e=JSON.parse(r);if(k(e))return e;u.warn(`Ignoring ${h} header: not a JSON object.`)}catch{u.warn(`Ignoring ${h} header: invalid JSON.`)}}const pe=async(r,e,t)=>{const n=!!e?.config?.access?.requiresLogin,i=e?.config?.access?.rbac||{},A=t?.props?.config?.mcpMode??"tools",T=t?.props?.config?.gatewayFetchBudgetPerExec??v.budgetPerExec,S=t?.props?.config?.searchIgnoredRoutes??[],s=t,b=!!s?.props?.config?.isPublicEndpoint;let p;const E=r.headers.get("Authorization");if(b)e.user={...ie,email:"",idpAccessToken:void 0,idpId:void 0};else if(Q(n,i)){const{isAuthenticated:d,isTokenValid:l,currentUser:a,accessToken:m}=await X(r,e);if(!d){const c=g(r),f=e.config.mcp?.docs?.publicEndpoint&&Z(i,n)?`${c}${oe(se)}`:void 0;return l===!1?z(c):W(c,f)}a&&(e.user=a),p=m}else E&&(p=q(E||"")??void 0);const I={isAuthenticated:!!e.user?.isAuthenticated,teams:e.user?.teams||[te],claims:e.user?.claims??{}};return ne(ce.MCP,I,i,n)?await K(async()=>{const d=t?.props?.config?.elicitationEnabled??!1;if(r.method==="GET")return new Response(JSON.stringify({error:"Method Not Allowed",message:`In order to use this MCP server, you need to register it in your MCP client (VS Code, Cursor, Claude Code, etc.) using this URL: ${r.url}`}),{status:405,headers:{"Content-Type":"application/json"}});if(r.method!=="POST")return J();const l=s?.props?.config?.apiDescriptionsMap||{},a=s?.props?.config?.graphqlDescriptions||[],m=s?.props?.config?.mcpDocsServerName||ee,{config:{mcp:c={}}}=e,f=$(l,e.user,i,n),y=j(a,e.user,i,n),U=e.config.products?Object.values(e.config.products).map(o=>o?.name):[],w=c.docs?.name||m,C=ae(r.headers.get(h)),R=s?.props?.tools||[],_=s?.props?.skillsBaseUrl||g(r),D=B(s?.props?.skills||[],e.user,i,n).map(o=>({slug:o.slug,name:o.name,description:o.description,content:o.content,uri:L(_,o.slug)})),M=await de(r),O={name:w,tools:R,skills:D,context:{...e,accessToken:p,outdir:e.outdir||"",baseUrl:e.baseUrl||g(r),internalBaseUrl:F(r),apiDescriptionsMap:f,graphqlDescriptions:y,products:U,metadata:C,mcpMode:A,elicitationEnabled:d,gatewayFetchBudgetPerExec:T,searchIgnoredRoutes:S,clientIp:N(r),...x(r)}},P=await V({...O,getKv:e.getKv});return await H(async()=>P,{keepAliveMs:re,onerror:o=>u.warn(`MCP handler: ${o.message}`)}).fetch(r,M!==void 0?{parsedBody:M}:void 0)},A):Y()};async function de(r){try{return await r.json()}catch(e){throw new G(e instanceof Error?e.message:String(e),{cause:e})}}var Fe=pe;export{Fe as default};
1
+ import{logger as f}from"../../../tools/notifiers/logger.js";import{getFeedbackClientIp as N}from"../../../web-server/utils/feedback-ip.js";import{getForwardedOrigin as g,getInternalOrigin as F}from"../../../web-server/utils/get-request-origin.js";import{GATEWAY_FETCH_LIMIT_DEFAULTS as v,DEFAULT_ANONYMOUS_VISITOR_TEAM as k,RbacFeatures as B}from"../../../../constants/common.js";import{isObject as L}from"../../../../utils/guards/is-object.js";import{getAccessibleSkills as H}from"../../../utils/skills/get-accessible-skills.js";import{getSkillUrl as V}from"../../../utils/skills/get-skill-url.js";import{createMcpHandler as $}from"@modelcontextprotocol/server";import{createDocsMcpServer as j}from"../servers/docs-server.js";import{filterApiDescriptionsByRbac as G,filterGraphqlDescriptionsByRbac as J}from"../utils.js";import{McpClientInputError as K,createMethodNotAllowedError as Y,withErrorHandling as z}from"./errors.js";import{constructForbiddenResponse as W,constructInvalidTokenResponse as X,constructUnauthorizedResponse as Q,handleMcpAuth as Z}from"../auth/auth-handlers.js";import{shouldHandleMcpAuth as q}from"../../../utils/rbac/should-handle-mcp-auth.js";import{canAnonymousAccessMcpFeature as x}from"../../../utils/rbac/can-anonymous-access-mcp-feature.js";import{extractTokenFromAuthHeader as ee}from"../utils/jwt.js";import{resolveMcpClient as re}from"../utils/mcp-client.js";import{DEFAULT_DOCS_MCP_SERVER_NAME as oe,SSE_KEEPALIVE_INTERVAL_MS as se}from"../constants.js";import{withPathPrefix as ne}from"@redocly/theme/core/utils";import{PUBLIC_MCP_ROUTE as ie}from"@redocly/theme/core/constants/mcp";import{canAccessFeature as te}from"../../../utils/rbac.js";import{ANONYMOUS_AUTH_DETAILS as ce}from"../../../constants/rbac.js";const h="X-Redocly-AI-Metadata";function ae(r){if(r)try{const e=JSON.parse(r);if(L(e))return e;f.warn(`Ignoring ${h} header: not a JSON object.`)}catch{f.warn(`Ignoring ${h} header: invalid JSON.`)}}const pe=async(r,e,t)=>{const n=!!e?.config?.access?.requiresLogin,i=e?.config?.access?.rbac||{},A=t?.props?.config?.mcpMode??"tools",T=t?.props?.config?.gatewayFetchBudgetPerExec??v.budgetPerExec,S=t?.props?.config?.searchIgnoredRoutes??[],s=t,b=!!s?.props?.config?.isPublicEndpoint;let p;const E=r.headers.get("Authorization");if(b)e.user={...ce,email:"",idpAccessToken:void 0,idpId:void 0};else if(q(n,i)){const{isAuthenticated:d,isTokenValid:l,currentUser:a,accessToken:m}=await Z(r,e);if(!d){const c=g(r),u=e.config.mcp?.docs?.publicEndpoint&&x(i,n)?`${c}${ne(ie)}`:void 0;return l===!1?X(c):Q(c,u)}a&&(e.user=a),p=m}else E&&(p=ee(E||"")??void 0);const I={isAuthenticated:!!e.user?.isAuthenticated,teams:e.user?.teams||[k],claims:e.user?.claims??{}};return te(B.MCP,I,i,n)?await z(async()=>{const d=t?.props?.config?.elicitationEnabled??!1;if(r.method==="GET")return new Response(JSON.stringify({error:"Method Not Allowed",message:`In order to use this MCP server, you need to register it in your MCP client (VS Code, Cursor, Claude Code, etc.) using this URL: ${r.url}`}),{status:405,headers:{"Content-Type":"application/json"}});if(r.method!=="POST")return Y();const l=s?.props?.config?.apiDescriptionsMap||{},a=s?.props?.config?.graphqlDescriptions||[],m=s?.props?.config?.mcpDocsServerName||oe,{config:{mcp:c={}}}=e,u=G(l,e.user,i,n),y=J(a,e.user,i,n),U=e.config.products?Object.values(e.config.products).map(o=>o?.name):[],w=c.docs?.name||m,C=ae(r.headers.get(h)),R=s?.props?.tools||[],_=s?.props?.skillsBaseUrl||g(r),D=H(s?.props?.skills||[],e.user,i,n).map(o=>({slug:o.slug,name:o.name,description:o.description,content:o.content,uri:V(_,o.slug)})),M=await de(r),O={name:w,tools:R,skills:D,context:{...e,accessToken:p,outdir:e.outdir||"",baseUrl:e.baseUrl||g(r),internalBaseUrl:F(r),apiDescriptionsMap:u,graphqlDescriptions:y,products:U,metadata:C,mcpMode:A,elicitationEnabled:d,gatewayFetchBudgetPerExec:T,searchIgnoredRoutes:S,clientIp:N(r),...re(r)}},P=await j({...O,getKv:e.getKv});return await $(async()=>P,{keepAliveMs:se,onerror:o=>f.warn(`MCP handler: ${o.message}`)}).fetch(r,M!==void 0?{parsedBody:M}:void 0)},A):W()};async function de(r){try{return await r.json()}catch(e){throw new K(e instanceof Error?e.message:String(e),{cause:e})}}var Ne=pe;export{Ne as default};
@@ -1 +1 @@
1
- import{fileURLToPath as F}from"node:url";import{dirname as $,join as M}from"node:path";import{MCP_ROUTE as k,PUBLIC_MCP_ROUTE as D}from"@redocly/theme/core/constants/mcp";import{logger as c}from"../../tools/notifiers/logger.js";import{reporter as B}from"../../tools/notifiers/reporter.js";import{isDefined as x}from"../../../utils/guards/is-defined.js";import{canAnonymousAccessMcpFeature as P}from"../../utils/rbac/can-anonymous-access-mcp-feature.js";import{shouldHandleMcpAuth as R}from"../../utils/rbac/should-handle-mcp-auth.js";import{MCP_CREDENTIALS_HANDLER_ID as _,MCP_CREDENTIALS_ROUTE as V,MCP_DOCS_SERVER_HANDLER_ID as T,MCP_NOT_ALLOWED_TEMPLATE_ID as J}from"../../constants/mcp.js";import{bundledOpenApiDocumentsToMcpOpenApi as W,bundledGraphqlDocumentsToMcpOpenApi as X,buildGraphqlDescriptions as z,collectIgnoredRoutes as K,filterIgnoredApiDescriptions as S,getCleanedUpApiDescriptions as Q,isMcpInRedirects as Y}from"./utils.js";import{getMcpMode as O,isMcpElicitationEnabled as Z,isMcpGatewayEnabled as ee}from"./utils/mode.js";import{findGatedToolNames as te}from"./utils/find-gated-tool-names.js";import{getDefaultToolSchemas as oe}from"./docs-mcp/tool-schemas.js";import{EXECUTE_TOOL_SCHEMA as ie}from"./codemode/tools/execute-schema.js";import{isGatewayCapabilityEnabled as re,isGatewayEligible as se}from"./gateway-mcp/eligibility.js";import{resolveGatewayFetchLimits as ne}from"./gateway-mcp/rate-limit/limits.js";import{resetCustomMcpTools as ae,scanCustomMcpTools as ce}from"./custom-tools/scan-custom-tools.js";import{telemetryTraceStep as pe}from"../../../cli/telemetry/helpers/trace-step.js";import{DEFAULT_DOCS_MCP_SERVER_NAME as w}from"./constants.js";const b=$(F(import.meta.url));async function le(){let o;const p={registeredToolNames:[]};let l=0,d=!1;return{id:"mcp",async processContent(e,n){await pe("com.redocly.build.plugin.mcp",async s=>{const i=await n.getConfig(),{mcp:r,redirects:g}=i;if(s?.setAttribute("config",JSON.stringify(r||{})),s?.setAttribute("mcpMode",O()),s?.setAttribute("mcpGateway",String(ee())),r?.hide||r?.docs?.hide){ae(e,p);return}Y(g)&&await B.panicOnBuildContentError('The reserved route "/mcp" cannot be used in redirect configuration. Please remove any redirects involving "/mcp" from your redocly.yaml config.'),e.createTemplate(J,"@redocly/theme/layouts/McpNotAllowed");const u=!!i?.access?.requiresLogin,a=i?.access?.rbac||{},E=O(),h=Z(),{budgetPerExec:f}=ne();if(!o){c.info("Configuring MCP servers...");const C=W(await e.loadApiDocuments(n)),L=X(await e.loadApiDocuments(n)),v=r?.docs?.ignore||[],q=Q(S(C,v)),I=re(r),A=new Map;for(const t of q){const j=t.definition.info?.title||"",U=t.definition.info?.version||"";A.set(t.relativePath,{name:j,description:typeof t.definition.info?.description=="string"?t.definition.info.description:"",version:U,servers:t.definition.servers||[],relativePath:t.relativePath,...I&&se(t.definition.info,t.relativePath,a)?{fetchEligible:!0}:{}})}const y=z(S(L,v)),G=Object.values(i.products||{}).map(t=>t?.name).filter(x),N=i.l10n?.locales?.map(t=>t.code)??n.fs.localeFolders,H=oe({products:G,locales:N,requiresLogin:u,rbac:a,hasGraphqlApis:y.length>0,elicitationEnabled:h,hasCallableApis:A.values().some(t=>t.fetchEligible)});e.addMcpTools(M(b,"./docs-mcp/tools/index.js"),H),E==="code"&&e.addMcpTools(M(b,"./codemode/tools/execute.js"),[ie]),o={apiDescriptionsMap:Object.fromEntries(A),graphqlDescriptions:y}}const m=await ce(e,n,p);s?.setAttribute("customToolsCount",String(m)),m!==l&&(l=m,m>0&&c.info(`Registered ${m} custom MCP tool${m===1?"":"s"} from @mcp folders`)),await me({actions:e,handlerPath:M(b,"./handlers/docs-mcp-handler.js"),apiDescriptionsMap:o.apiDescriptionsMap,graphqlDescriptions:o.graphqlDescriptions,mcpConfig:r,mcpMode:E,elicitationEnabled:h,gatewayFetchBudgetPerExec:f,requiresLogin:u,rbacConfig:a}),d||(c.info("Registered Docs MCP Server endpoint at /mcp"),d=!0)})},async afterRoutesCreated(e,n){const s=await n.getConfig(),{mcp:i}=s,r=!i?.hide&&!i?.docs?.hide;e.markGatedMcpTools(await te(e.getMcpTools())),e.setGlobalData({mcpData:{docs:{enabled:r,name:i?.docs?.name||w,publicEndpoint:r&&de(i,s)}}})}}}var Le=le;function de(o,p){const l=!!p.access?.requiresLogin,d=p.access?.rbac||{};return!!o?.docs?.publicEndpoint&&R(l,d)&&P(d,l)}async function me({actions:o,handlerPath:p,apiDescriptionsMap:l,graphqlDescriptions:d,mcpConfig:e,mcpMode:n,elicitationEnabled:s,gatewayFetchBudgetPerExec:i,requiresLogin:r,rbacConfig:g}){o.createRequestHandler(T,p);const u=a=>async(E,h)=>{const f=K(h.getAllRoutes(),e?.docs?.ignore||[]);return f.length>0&&c.verbose(`mcp.docs.ignore: hiding ${f.length} page routes from MCP search`),{props:{config:{apiDescriptionsMap:l,graphqlDescriptions:d,mcpDocsServerName:e?.docs?.name||w,mcpMode:n,elicitationEnabled:s,gatewayFetchBudgetPerExec:i,searchIgnoredRoutes:f,...a?{isPublicEndpoint:a}:{}},serverOutDir:o.serverOutDir,tools:o.getMcpTools().map(({importPath:m,...C})=>C)}}};if(o.addApiRoute({slug:k,requestHandlerId:T,httpMethod:"all",getStaticData:u(!1)}),e?.docs?.publicEndpoint&&(R(r,g)?P(g,r)?(o.addApiRoute({slug:D,requestHandlerId:T,httpMethod:"all",getStaticData:u(!0)}),c.verbose(`Registered public Docs MCP Server endpoint at ${D}`)):c.info(`mcp.docs.publicEndpoint is enabled, but anonymous users are denied the MCP feature (rbac.features.mcp or requiresLogin) - skipping ${D}.`):c.info(`mcp.docs.publicEndpoint is enabled, but the project has no protected content - /mcp already serves anonymous users, skipping ${D}.`)),s){const a=M(b,"./handlers/mcp-credentials-handler.js");o.createRequestHandler(_,a),o.addApiRoute({slug:V,requestHandlerId:_,httpMethod:"all",getStaticData:async()=>({props:{}})}),c.verbose("Registered MCP credentials endpoint at /mcp/credentials")}}export{Le as default,le as mcpServerPlugin};
1
+ import{fileURLToPath as F}from"node:url";import{dirname as $,join as b}from"node:path";import{MCP_ROUTE as k,PUBLIC_MCP_ROUTE as M}from"@redocly/theme/core/constants/mcp";import{logger as c}from"../../tools/notifiers/logger.js";import{reporter as B}from"../../tools/notifiers/reporter.js";import{isDefined as x}from"../../../utils/guards/is-defined.js";import{canAnonymousAccessMcpFeature as P}from"../../utils/rbac/can-anonymous-access-mcp-feature.js";import{shouldHandleMcpAuth as R}from"../../utils/rbac/should-handle-mcp-auth.js";import{MCP_CREDENTIALS_HANDLER_ID as _,MCP_CREDENTIALS_ROUTE as V,MCP_DOCS_SERVER_HANDLER_ID as T,MCP_NOT_ALLOWED_TEMPLATE_ID as J}from"../../constants/mcp.js";import{bundledOpenApiDocumentsToMcpOpenApi as W,bundledGraphqlDocumentsToMcpOpenApi as X,buildGraphqlDescriptions as z,collectIgnoredRoutes as K,filterIgnoredApiDescriptions as S,getCleanedUpApiDescriptions as Q,isMcpInRedirects as Y}from"./utils.js";import{getMcpMode as O,isMcpElicitationEnabled as Z,isMcpGatewayEnabled as ee}from"./utils/mode.js";import{findGatedToolNames as te}from"./utils/find-gated-tool-names.js";import{getDefaultToolSchemas as oe}from"./docs-mcp/tool-schemas.js";import{EXECUTE_TOOL_SCHEMA as ie}from"./codemode/tools/execute-schema.js";import{isGatewayCapabilityEnabled as re,isGatewayEligible as se}from"./gateway-mcp/eligibility.js";import{resolveGatewayFetchLimits as ne}from"./gateway-mcp/rate-limit/limits.js";import{resetCustomMcpTools as ae,scanCustomMcpTools as ce}from"./custom-tools/scan-custom-tools.js";import{telemetryTraceStep as pe}from"../../../cli/telemetry/helpers/trace-step.js";import{DEFAULT_DOCS_MCP_SERVER_NAME as w}from"./constants.js";const D=$(F(import.meta.url));async function de(){let o;const p={registeredToolNames:[]};let d=0,l=!1;return{id:"mcp",async processContent(e,n){await pe("com.redocly.build.plugin.mcp",async s=>{const i=await n.getConfig(),{mcp:r,redirects:g}=i;if(s?.setAttribute("config",JSON.stringify(r||{})),s?.setAttribute("mcpMode",O()),s?.setAttribute("mcpGateway",String(ee())),r?.hide||r?.docs?.hide){ae(e,p);return}Y(g)&&await B.panicOnBuildContentError('The reserved route "/mcp" cannot be used in redirect configuration. Please remove any redirects involving "/mcp" from your redocly.yaml config.'),e.createTemplate(J,"@redocly/theme/layouts/McpNotAllowed");const u=!!i?.access?.requiresLogin,a=i?.access?.rbac||{},E=O(),h=Z(),{budgetPerExec:f}=ne();if(!o){c.info("Configuring MCP servers...");const C=W(await e.loadApiDocuments(n)),L=X(await e.loadApiDocuments(n)),v=r?.docs?.ignore||[],q=Q(S(C,v)),I=re(r),A=new Map;for(const t of q){const j=t.definition.info?.title||"",U=t.definition.info?.version||"";A.set(t.relativePath,{name:j,description:typeof t.definition.info?.description=="string"?t.definition.info.description:"",version:U,servers:t.definition.servers||[],relativePath:t.relativePath,...I&&se(t.definition.info,t.relativePath,a)?{fetchEligible:!0}:{}})}const y=z(S(L,v)),G=Object.values(i.products||{}).map(t=>t?.name).filter(x),N=i.l10n?.locales?.map(t=>t.code)??n.fs.localeFolders,H=oe({products:G,locales:N,requiresLogin:u,rbac:a,hasGraphqlApis:y.length>0,elicitationEnabled:h,hasCallableApis:A.values().some(t=>t.fetchEligible),feedbackHidden:i.feedback?.hide===!0});e.addMcpTools(b(D,"./docs-mcp/tools/index.js"),H),E==="code"&&e.addMcpTools(b(D,"./codemode/tools/execute.js"),[ie]),o={apiDescriptionsMap:Object.fromEntries(A),graphqlDescriptions:y}}const m=await ce(e,n,p);s?.setAttribute("customToolsCount",String(m)),m!==d&&(d=m,m>0&&c.info(`Registered ${m} custom MCP tool${m===1?"":"s"} from @mcp folders`)),await me({actions:e,handlerPath:b(D,"./handlers/docs-mcp-handler.js"),apiDescriptionsMap:o.apiDescriptionsMap,graphqlDescriptions:o.graphqlDescriptions,mcpConfig:r,mcpMode:E,elicitationEnabled:h,gatewayFetchBudgetPerExec:f,requiresLogin:u,rbacConfig:a}),l||(c.info("Registered Docs MCP Server endpoint at /mcp"),l=!0)})},async afterRoutesCreated(e,n){const s=await n.getConfig(),{mcp:i}=s,r=!i?.hide&&!i?.docs?.hide;e.markGatedMcpTools(await te(e.getMcpTools())),e.setGlobalData({mcpData:{docs:{enabled:r,name:i?.docs?.name||w,publicEndpoint:r&&le(i,s)}}})}}}var Le=de;function le(o,p){const d=!!p.access?.requiresLogin,l=p.access?.rbac||{};return!!o?.docs?.publicEndpoint&&R(d,l)&&P(l,d)}async function me({actions:o,handlerPath:p,apiDescriptionsMap:d,graphqlDescriptions:l,mcpConfig:e,mcpMode:n,elicitationEnabled:s,gatewayFetchBudgetPerExec:i,requiresLogin:r,rbacConfig:g}){o.createRequestHandler(T,p);const u=a=>async(E,h)=>{const f=K(h.getAllRoutes(),e?.docs?.ignore||[]);return f.length>0&&c.verbose(`mcp.docs.ignore: hiding ${f.length} page routes from MCP search`),{props:{config:{apiDescriptionsMap:d,graphqlDescriptions:l,mcpDocsServerName:e?.docs?.name||w,mcpMode:n,elicitationEnabled:s,gatewayFetchBudgetPerExec:i,searchIgnoredRoutes:f,...a?{isPublicEndpoint:a}:{}},serverOutDir:o.serverOutDir,tools:o.getMcpTools().map(({importPath:m,...C})=>C)}}};if(o.addApiRoute({slug:k,requestHandlerId:T,httpMethod:"all",getStaticData:u(!1)}),e?.docs?.publicEndpoint&&(R(r,g)?P(g,r)?(o.addApiRoute({slug:M,requestHandlerId:T,httpMethod:"all",getStaticData:u(!0)}),c.verbose(`Registered public Docs MCP Server endpoint at ${M}`)):c.info(`mcp.docs.publicEndpoint is enabled, but anonymous users are denied the MCP feature (rbac.features.mcp or requiresLogin) - skipping ${M}.`):c.info(`mcp.docs.publicEndpoint is enabled, but the project has no protected content - /mcp already serves anonymous users, skipping ${M}.`)),s){const a=b(D,"./handlers/mcp-credentials-handler.js");o.createRequestHandler(_,a),o.addApiRoute({slug:V,requestHandlerId:_,httpMethod:"all",getStaticData:async()=>({props:{}})}),c.verbose("Registered MCP credentials endpoint at /mcp/credentials")}}export{Le as default,de as mcpServerPlugin};
@@ -1 +1 @@
1
- import*as v from"path";import{REDOCLY_ROUTE_RBAC as b,REDOCLY_TEAMS_RBAC as p}from"@redocly/config";import{VERSION_SEPARATOR as M}from"../constants/common.js";import{DEFAULT_LOCALE_PLACEHOLDER as _}from"../../constants/common.js";import{removeTrailingSlash as j}from"../../utils/url/remove-trailing-slash.js";import{isPrimitive as W}from"../../utils/guards/is-primitive.js";import{slash as w}from"../../utils/path/slash.js";import{isAbsoluteUrl as z}from"../../utils/url/is-absolute-url.js";import{normalizeRouteSlug as U}from"../../utils/path/normalize-route-slug.js";import{parsePathVersions as R}from"../../utils/path/parse-path-versions.js";import{logger as A}from"../tools/notifiers/logger.js";import{reporter as S}from"../tools/notifiers/reporter.js";import{shaDirPathShort as C}from"../utils/crypto/sha-dir-path-short.js";import{copyStaticFile as H,FileNotFoundError as E}from"../utils/fs.js";import{isIconPath as J,resolveAssetPath as Y}from"../utils/index.js";import{resolveSrcSet as G}from"../utils/resolve-src-set.js";import{isL10nPath as B}from"../fs/utils/is-l10n-path.js";import{getLocaleFromRelativePath as q}from"../fs/utils/get-locale-from-relative-path.js";async function D(e,s,n,t,a){if(!e)return;const f={...a,ignoreCustomSidebar:!0};if(W(e)){if(typeof e=="string"){const r=F(n.contentDir,s,a,e,t.fs);if(t.fs.exists(r)){if(n.getRouteByFsPath(r))return K({page:e},s,n,t,f);{const g=t.fs.getFileInfo(r);return g?H(n.contentDir,g.realRelativePath,n.outdir):void 0}}}return e}return Array.isArray(e)?I(N(e),s,n,t,f):Object.fromEntries(await Promise.all(Object.entries(e).map(async([r,l])=>[r,await D(l,s,n,t,a)])))}function N(e){return e.map(s=>({...s,items:s.items?N(s.items):void 0}))}async function I(e,s,n,t,a){if(Array.isArray(e))return(await Promise.all(e.map(f=>K(f,s,n,t,a)))).flatMap(f=>f)}async function P(e,s,n,t){let a,f;if(typeof e.icon=="object"){if("srcSet"in e.icon)try{a=await G(e.icon.srcSet,n.fs,{fromFileRelativePath:t.navFile,contentDir:s.contentDir,outdir:s.outdir})}catch(d){d instanceof E?await S.panicOnBuildContentError(`Cannot resolve "item.icon.srcSet" from ${t.navFile}: ${d.message}`):await S.panicOnBuild(`Cannot resolve "item.icon.srcSet" from ${t.navFile}: ${d.message}`)}}else if(typeof e.icon=="string")if(z(e.icon)||J(e.icon))try{f=await Y(e.icon,n.fs,{fromFileRelativePath:t.navFile,contentDir:s.contentDir,outdir:s.outdir})}catch(d){d instanceof E?await S.panicOnBuildContentError(`Cannot resolve "item.icon" from ${t.navFile}: file ${f} does not exist`):await S.panicOnBuild(`Cannot resolve "item.icon" from ${t.navFile}: ${d.message}`)}else f=e.icon;return{icon:f,srcSet:a}}function Q(e){return s=>{if(s.type==="link"||s.type==="group"){const n=s.metadata;return n?Object.entries(e).every(([t,a])=>Array.isArray(a)?a.some(f=>n[t]===f):n[t]===a):!1}return!0}}async function K(e,s,n,t,a){if(e?.directory&&e.items?.length)return{type:"error",label:`Can't have both "directory" and "items" in the nav item: ${JSON.stringify(e)}`};e?.directory&&e?.group&&(e={...e,directory:void 0,items:[{directory:e.directory}]});const f=e?.directory?F(n.contentDir,s,a,e.directory,t.fs):void 0;if(f!==void 0){const i=f===""?"":f+"/",{locale:u,ignoredRoutes:o}=a;let h=n.getAllRoutesForLocale(u).filter(c=>!o?.has(c.baseSlug||"")&&c.fsPath.startsWith(i)&&!c.excludeFromSidebar).sort((c,y)=>c.fsPath===y.fsPath?0:c.baseSlug.localeCompare(y.baseSlug,void 0,{numeric:!0}));const m=e.includeByMetadata?Q(e.includeByMetadata):Boolean;if(!h.length)return[];const $=(await Promise.all(h.map(async c=>{const y=c.versions?.find(x=>x.active),L=y&&{version:y.version,isDefault:y.default,versionFolderId:y.folderId},V=ee(v.posix.relative(f,c.fsPath)),O=c.getSidebar?.(c);return!a.ignoreCustomSidebar&&O?.length?{type:"group",fsPath:c.fsPath,metadata:c.metadata,link:c.slug,routeSlug:c.slug,label:await c.getNavText?.()||c.slug,[p]:c[p],[b]:c[b],sidebarItems:k(O,L,c[p],c[b]),...L,relativePathFromDirectory:v.relative(f,c.fsPath).replace(/@[^\/]+\//,"")}:{type:"link",fsPath:c.fsPath,metadata:c.metadata,[p]:c[p],[b]:c[b],label:await c.getNavText?.()||c.slug,link:c.slug,routeSlug:c.slug,...L,relativePathFromDirectory:V}}))).filter(m);return e.flatten?T($,a):Z($,a)}let d=typeof e=="string"?e:e?.page,r,l;if(d){if(d.includes("#")){const[i,u]=d.split("#");u?l=u:A.warn(`Invalid heading anchor format in sidebar: "${u}". Heading anchors should contain only alphanumeric characters, hyphens, and underscores.`),d=i}if(d=j(d),a.locale&&a.locale!==_){const i=U(v.join(a.locale.toLowerCase(),d));r=n.getRouteBySlug(i)}r||(r=n.getRouteBySlug(d)),r||(r=n.getRouteByFsPath(F(n.contentDir,s,a,d,t.fs)))}const g=r?.metadata;if(e?.$ref){let i=F(n.contentDir,s,a,e.$ref,t.fs);if(a.ref!==void 0&&(i=v.posix.join(a.ref,e.$ref)),!t.fs.exists(i))return await S.panicOnBuildContentError(`Failed to load ${i} file. Make sure sidebar $ref path is correct.`),[];const u=await t.cache.load(i,"yaml"),o=v.dirname(i);return await I(u.data,s,n,t,{...a,navFile:i,ref:o})||[]}if(!r){const i=a.excludedFromLinkCheckerPatterns?.catalog.some(o=>o.test(d||"")),u=a.excludedFromLinkCheckerPatterns?.apiFunctions.some(o=>o.test(d||e.href||""));(u||i)&&(e={...e,href:d||e.href,page:void 0,target:e.target??(u?"_blank":void 0)}),await X(e,a,t,s)}if(r&&!e.disconnect&&!a.ignoreCustomSidebar&&(l||r?.getSidebar)){const i=r.versions?.find(o=>o.active),u=i&&{version:i.version,isDefault:i.default,versionFolderId:i.folderId};if(l){let o=[];if(r.getSidebar&&(o=r.getSidebar(r,{...e,...await P(e,n,t,a)}),o&&o.length>0)){const h=o[0];h&&h.link&&(h.link=`${h.link}#${l}`)}if(!o||o.length===0){let h=e.group||e.label||l;o=[{type:"link",fsPath:r.fsPath,metadata:r.metadata,link:`${r.slug}#${l}`,routeSlug:r.slug,label:h,labelTranslationKey:e.labelTranslationKey,...await P(e,n,t,a),[p]:r[p],[b]:{slug:r.slug,fsPath:r.fsPath},...u}]}return k(o,u,r[p],r[b])}if(r?.getSidebar){const o=r.getSidebar(r,{...e,...await P(e,n,t,a)}),h=e.group&&o?.[0]?.routeSlug===r.slug?o.slice(1):o;return k(a.groupCustomSidebars||e.group?[{type:"group",fsPath:r.fsPath,link:r.slug,routeSlug:r.slug,label:e.group||e.label||await r.getNavText?.()||r.slug,items:h,labelTranslationKey:e.labelTranslationKey,metadata:g,badges:e.badges,...await P(e,n,t,a)}]:o,u,r[p],r[b])}}if(r&&!e.group){const i=l?`${r.slug}#${l}`:r.slug;let u=e.label||l||"";u||(u=await r.getNavText?.()||r.slug);const o=r.versions?.find(m=>m.active),h=o&&{version:o.version,isDefault:o.default,versionFolderId:o.folderId};return{type:"link",fsPath:r.fsPath,linkedSidebars:e.linkedSidebars,metadata:g,[p]:e?.rbac||r[p],[b]:{slug:r.slug,fsPath:r.fsPath},label:u,labelTranslationKey:e.labelTranslationKey,link:i,items:await I(e.items,s,n,t,a),separatorLine:e.separatorLine,linePosition:e.linePosition,routeSlug:e.disconnect?void 0:i,external:e.external,target:e.target,badges:e.badges,...await P(e,n,t,a),...h,additionalProps:e.additionalProps}}else if(e?.group){const i=r?.versions?.find(o=>o.active),u=R(a?.navFile);return{type:"group",fsPath:r?.fsPath,linkedSidebars:e.linkedSidebars,metadata:g,version:i?.version||u?.versionName,versionFolderId:i?.folderId||(u?.versionFolderPath?C(u.versionFolderPath):void 0),label:e.group,link:r?.slug,routeSlug:r?.slug,badges:e.badges,labelTranslationKey:e.groupTranslationKey,items:await I(e.items,s,n,t,a),expanded:e.expanded?e.expanded.toString():void 0,selectFirstItemOnExpand:e.selectFirstItemOnExpand,menuStyle:e.menuStyle,separatorLine:e.separatorLine,linePosition:e.linePosition,...await P(e,n,t,a),[p]:e?.rbac,[b]:{slug:r?.slug||"",fsPath:r?.fsPath||""},additionalProps:e.additionalProps}}else{if(e?.href||e?.label)return{type:"link",metadata:g,link:e.href||"",label:e?.label||e?.href||"",labelTranslationKey:e.labelTranslationKey,external:e.external,target:e.target,separatorLine:e.separatorLine,linePosition:e.linePosition,badges:e.badges,...await P(e,n,t,a),[p]:e?.rbac,additionalProps:e.additionalProps};if(e?.separator!=null||e?.separatorLine!=null){const i=R(a?.navFile);return{type:"separator",metadata:g,version:i?.versionName,versionFolderId:i?.versionFolderPath?C(i.versionFolderPath):void 0,label:e.separator,labelTranslationKey:e.separatorTranslationKey,separatorLine:e.separatorLine,linePosition:e.linePosition,...await P(e,n,t,a),[p]:e?.rbac,additionalProps:e.additionalProps}}else{const i=R(a?.navFile);return{type:"error",label:`Can't resolve page: ${JSON.stringify(e)}`,version:i?.versionName,versionFolderId:i?.versionFolderPath?C(i.versionFolderPath):void 0}}}}async function X(e,s,n,t){const{href:a,page:f}=e;if(a||!f)return;const d=F(n.fs.cwd,t,s,f,n.fs),r=n.fs.exists(d),l=await n.isPathIgnored(d),g=(r?"The page is ignored: ":"Can't resolve page: ")+f;(!r||l)&&S.reportBrokenLink({type:"BROKEN_LINK",brokenLinkType:"LINK",title:e.label||e.group||"",link:d,rawLink:f,message:g,sourceFileRelativePath:s.navFile,sourceFileLocation:{line:0}})}function F(e,s,n,t="",a){if(n.ref!==void 0)return w(v.relative(e,v.resolve(e,v.join(n.ref,t))));if(t.startsWith("/")){const f=B(s)?q(s):void 0,d=f?`${a.localizationFolder}/${f}/`:"",r=t.slice(1);return B(r)?r:d+w(r)}return w(v.relative(e,v.resolve(e,s,t)))}function Z(e,s){const n={};for(const r of e){const l=v.dirname(r.relativePathFromDirectory),g=r.version?M+r.version:"",i=v.basename(r.relativePathFromDirectory)+g;d(l,r,i)}const t=f(a(n));return T(t,s);function a(r){const l=[];for(const g of Object.keys(r)){const i=r[g];l.push({...i,items:i.items?a(i.items):void 0})}return l}function f(r){return r.sort((l,g)=>{const i=typeof l=="string"?l.toLowerCase():l.relativePathFromDirectory||l.label||"",u=typeof g=="string"?g.toLowerCase():g.relativePathFromDirectory||g.label||"";return i.startsWith("index.")?-1:u.startsWith("index.")?1:i.localeCompare(u,void 0,{numeric:!0})})}function d(r,l,g){r==="."&&(r="");const i=r.split("/").filter(Boolean);let u=n;for(const o of i){const h=o+(l?.version||"");u[h]||(u[h]={type:"group",version:l?.version,label:o,isDefault:l?.isDefault,versionFolderId:l.versionFolderId,items:{}}),u=u[h].items}u[g]=l}}function T(e,s){return e.flatMap(n=>n?.sidebarItems?s.groupCustomSidebars?{...n,items:n.sidebarItems,sidebarItems:void 0,relativePathFromDirectory:void 0}:n.sidebarItems:{...n,items:n.items?T(n.items,s):void 0})}function k(e,s,n,t){return e.map(a=>({...a,...s,[p]:a[p]||n,[b]:a[b]||t,items:a.type==="group"&&a.items?k(a.items,s,n):a.items}))}function ee(e){return e.replace(/@[^\/]+\//,"")}async function Pe(e,s,n,t){const a=(e?.items||[]).filter(r=>r.linkedSidebars?.length).map(r=>({...r,items:void 0})),f=await D(a,s.contentDir,s,n,t),d=new Map;for(const r of f)if(r.linkedSidebars?.length)for(const l of r.linkedSidebars){if(d.has(l)){A.warn(`Only one navbar item can belong to sidebar. "${l}" on 'linkedSidebars' property on "${r.label}" will be ignored.`);continue}d.set(l,{label:r.label,link:r.link})}return d}export{Pe as collectItemsLinkedToSidebars,N as normalizeItems,K as resolveItem,I as resolveItems,D as resolveLinksFromConfig};
1
+ import*as v from"path";import{REDOCLY_ROUTE_RBAC as b,REDOCLY_TEAMS_RBAC as p}from"@redocly/config";import{VERSION_SEPARATOR as M}from"../constants/common.js";import{DEFAULT_LOCALE_PLACEHOLDER as _}from"../../constants/common.js";import{removeTrailingSlash as j}from"../../utils/url/remove-trailing-slash.js";import{isPrimitive as W}from"../../utils/guards/is-primitive.js";import{slash as w}from"../../utils/path/slash.js";import{isAbsoluteUrl as z}from"../../utils/url/is-absolute-url.js";import{normalizeRouteSlug as U}from"../../utils/path/normalize-route-slug.js";import{parsePathVersions as R}from"../../utils/path/parse-path-versions.js";import{logger as A}from"../tools/notifiers/logger.js";import{reporter as S}from"../tools/notifiers/reporter.js";import{shaDirPathShort as C}from"../utils/crypto/sha-dir-path-short.js";import{copyStaticFile as H,FileNotFoundError as E}from"../utils/fs.js";import{isIconPath as J,resolveAssetPath as Y}from"../utils/index.js";import{resolveSrcSet as G}from"../utils/resolve-src-set.js";import{isL10nPath as B}from"../fs/utils/is-l10n-path.js";import{getLocaleFromRelativePath as q}from"../fs/utils/get-locale-from-relative-path.js";async function D(e,s,n,t,a){if(!e)return;const f={...a,ignoreCustomSidebar:!0};if(W(e)){if(typeof e=="string"){const r=F(n.contentDir,s,a,e,t.fs);if(t.fs.exists(r)){if(n.getRouteByFsPath(r))return K({page:e},s,n,t,f);{const g=t.fs.getFileInfo(r);return g?H(n.contentDir,g.realRelativePath,n.outdir):void 0}}}return e}return Array.isArray(e)?I(N(e),s,n,t,f):Object.fromEntries(await Promise.all(Object.entries(e).map(async([r,l])=>[r,await D(l,s,n,t,a)])))}function N(e){return e.map(s=>({...s,items:s.items?N(s.items):void 0}))}async function I(e,s,n,t,a){if(Array.isArray(e))return(await Promise.all(e.map(f=>K(f,s,n,t,a)))).flatMap(f=>f)}async function P(e,s,n,t){let a,f;if(typeof e.icon=="object"){if("srcSet"in e.icon)try{a=await G(e.icon.srcSet,n.fs,{fromFileRelativePath:t.navFile,contentDir:s.contentDir,outdir:s.outdir})}catch(d){d instanceof E?await S.panicOnBuildContentError(`Cannot resolve "item.icon.srcSet" from ${t.navFile}: ${d.message}`):await S.panicOnBuild(`Cannot resolve "item.icon.srcSet" from ${t.navFile}: ${d.message}`)}}else if(typeof e.icon=="string")if(z(e.icon)||J(e.icon))try{f=await Y(e.icon,n.fs,{fromFileRelativePath:t.navFile,contentDir:s.contentDir,outdir:s.outdir})}catch(d){d instanceof E?await S.panicOnBuildContentError(`Cannot resolve "item.icon" from ${t.navFile}: file ${f} does not exist`):await S.panicOnBuild(`Cannot resolve "item.icon" from ${t.navFile}: ${d.message}`)}else f=e.icon;return{icon:f,srcSet:a}}function Q(e){return s=>{if(s.type==="link"||s.type==="group"){const n=s.metadata;return n?Object.entries(e).every(([t,a])=>Array.isArray(a)?a.some(f=>n[t]===f):n[t]===a):!1}return!0}}async function K(e,s,n,t,a){if(e?.directory&&e.items?.length)return{type:"error",label:`Can't have both "directory" and "items" in the nav item: ${JSON.stringify(e)}`};e?.directory&&e?.group&&(e={...e,directory:void 0,items:[{directory:e.directory}]});const f=e?.directory?F(n.contentDir,s,a,e.directory,t.fs):void 0;if(f!==void 0){const i=f===""?"":f+"/",{locale:u,ignoredRoutes:o}=a;let h=n.getAllRoutesForLocale(u).filter(c=>!o?.has(c.baseSlug||"")&&c.fsPath.startsWith(i)&&!c.excludeFromSidebar).sort((c,y)=>c.fsPath===y.fsPath?0:c.baseSlug.localeCompare(y.baseSlug,void 0,{numeric:!0}));const m=e.includeByMetadata?Q(e.includeByMetadata):Boolean;if(!h.length)return[];const $=(await Promise.all(h.map(async c=>{const y=c.versions?.find(x=>x.active),L=y&&{version:y.version,isDefault:y.default,versionFolderId:y.folderId},V=ee(v.posix.relative(f,c.fsPath)),O=c.getSidebar?.(c);return!a.ignoreCustomSidebar&&O?.length?{type:"group",fsPath:c.fsPath,metadata:c.metadata,link:c.slug,routeSlug:c.slug,label:await c.getNavText?.()||c.slug,[p]:c[p],[b]:c[b],sidebarItems:k(O,L,c[p],c[b]),...L,relativePathFromDirectory:v.relative(f,c.fsPath).replace(/@[^/]+\//,"")}:{type:"link",fsPath:c.fsPath,metadata:c.metadata,[p]:c[p],[b]:c[b],label:await c.getNavText?.()||c.slug,link:c.slug,routeSlug:c.slug,...L,relativePathFromDirectory:V}}))).filter(m);return e.flatten?T($,a):Z($,a)}let d=typeof e=="string"?e:e?.page,r,l;if(d){if(d.includes("#")){const[i,u]=d.split("#");u?l=u:A.warn(`Invalid heading anchor format in sidebar: "${u}". Heading anchors should contain only alphanumeric characters, hyphens, and underscores.`),d=i}if(d=j(d),a.locale&&a.locale!==_){const i=U(v.join(a.locale.toLowerCase(),d));r=n.getRouteBySlug(i)}r||(r=n.getRouteBySlug(d)),r||(r=n.getRouteByFsPath(F(n.contentDir,s,a,d,t.fs)))}const g=r?.metadata;if(e?.$ref){let i=F(n.contentDir,s,a,e.$ref,t.fs);if(a.ref!==void 0&&(i=v.posix.join(a.ref,e.$ref)),!t.fs.exists(i))return await S.panicOnBuildContentError(`Failed to load ${i} file. Make sure sidebar $ref path is correct.`),[];const u=await t.cache.load(i,"yaml"),o=v.dirname(i);return await I(u.data,s,n,t,{...a,navFile:i,ref:o})||[]}if(!r){const i=a.excludedFromLinkCheckerPatterns?.catalog.some(o=>o.test(d||"")),u=a.excludedFromLinkCheckerPatterns?.apiFunctions.some(o=>o.test(d||e.href||""));(u||i)&&(e={...e,href:d||e.href,page:void 0,target:e.target??(u?"_blank":void 0)}),await X(e,a,t,s)}if(r&&!e.disconnect&&!a.ignoreCustomSidebar&&(l||r?.getSidebar)){const i=r.versions?.find(o=>o.active),u=i&&{version:i.version,isDefault:i.default,versionFolderId:i.folderId};if(l){let o=[];if(r.getSidebar&&(o=r.getSidebar(r,{...e,...await P(e,n,t,a)}),o&&o.length>0)){const h=o[0];h&&h.link&&(h.link=`${h.link}#${l}`)}if(!o||o.length===0){let h=e.group||e.label||l;o=[{type:"link",fsPath:r.fsPath,metadata:r.metadata,link:`${r.slug}#${l}`,routeSlug:r.slug,label:h,labelTranslationKey:e.labelTranslationKey,...await P(e,n,t,a),[p]:r[p],[b]:{slug:r.slug,fsPath:r.fsPath},...u}]}return k(o,u,r[p],r[b])}if(r?.getSidebar){const o=r.getSidebar(r,{...e,...await P(e,n,t,a)}),h=e.group&&o?.[0]?.routeSlug===r.slug?o.slice(1):o;return k(a.groupCustomSidebars||e.group?[{type:"group",fsPath:r.fsPath,link:r.slug,routeSlug:r.slug,label:e.group||e.label||await r.getNavText?.()||r.slug,items:h,labelTranslationKey:e.labelTranslationKey,metadata:g,badges:e.badges,...await P(e,n,t,a)}]:o,u,r[p],r[b])}}if(r&&!e.group){const i=l?`${r.slug}#${l}`:r.slug;let u=e.label||l||"";u||(u=await r.getNavText?.()||r.slug);const o=r.versions?.find(m=>m.active),h=o&&{version:o.version,isDefault:o.default,versionFolderId:o.folderId};return{type:"link",fsPath:r.fsPath,linkedSidebars:e.linkedSidebars,metadata:g,[p]:e?.rbac||r[p],[b]:{slug:r.slug,fsPath:r.fsPath},label:u,labelTranslationKey:e.labelTranslationKey,link:i,items:await I(e.items,s,n,t,a),separatorLine:e.separatorLine,linePosition:e.linePosition,routeSlug:e.disconnect?void 0:i,external:e.external,target:e.target,badges:e.badges,...await P(e,n,t,a),...h,additionalProps:e.additionalProps}}else if(e?.group){const i=r?.versions?.find(o=>o.active),u=R(a?.navFile);return{type:"group",fsPath:r?.fsPath,linkedSidebars:e.linkedSidebars,metadata:g,version:i?.version||u?.versionName,versionFolderId:i?.folderId||(u?.versionFolderPath?C(u.versionFolderPath):void 0),label:e.group,link:r?.slug,routeSlug:r?.slug,badges:e.badges,labelTranslationKey:e.groupTranslationKey,items:await I(e.items,s,n,t,a),expanded:e.expanded?e.expanded.toString():void 0,selectFirstItemOnExpand:e.selectFirstItemOnExpand,menuStyle:e.menuStyle,separatorLine:e.separatorLine,linePosition:e.linePosition,...await P(e,n,t,a),[p]:e?.rbac,[b]:{slug:r?.slug||"",fsPath:r?.fsPath||""},additionalProps:e.additionalProps}}else{if(e?.href||e?.label)return{type:"link",metadata:g,link:e.href||"",label:e?.label||e?.href||"",labelTranslationKey:e.labelTranslationKey,external:e.external,target:e.target,separatorLine:e.separatorLine,linePosition:e.linePosition,badges:e.badges,...await P(e,n,t,a),[p]:e?.rbac,additionalProps:e.additionalProps};if(e?.separator!=null||e?.separatorLine!=null){const i=R(a?.navFile);return{type:"separator",metadata:g,version:i?.versionName,versionFolderId:i?.versionFolderPath?C(i.versionFolderPath):void 0,label:e.separator,labelTranslationKey:e.separatorTranslationKey,separatorLine:e.separatorLine,linePosition:e.linePosition,...await P(e,n,t,a),[p]:e?.rbac,additionalProps:e.additionalProps}}else{const i=R(a?.navFile);return{type:"error",label:`Can't resolve page: ${JSON.stringify(e)}`,version:i?.versionName,versionFolderId:i?.versionFolderPath?C(i.versionFolderPath):void 0}}}}async function X(e,s,n,t){const{href:a,page:f}=e;if(a||!f)return;const d=F(n.fs.cwd,t,s,f,n.fs),r=n.fs.exists(d),l=await n.isPathIgnored(d),g=(r?"The page is ignored: ":"Can't resolve page: ")+f;(!r||l)&&S.reportBrokenLink({type:"BROKEN_LINK",brokenLinkType:"LINK",title:e.label||e.group||"",link:d,rawLink:f,message:g,sourceFileRelativePath:s.navFile,sourceFileLocation:{line:0}})}function F(e,s,n,t="",a){if(n.ref!==void 0)return w(v.relative(e,v.resolve(e,v.join(n.ref,t))));if(t.startsWith("/")){const f=B(s)?q(s):void 0,d=f?`${a.localizationFolder}/${f}/`:"",r=t.slice(1);return B(r)?r:d+w(r)}return w(v.relative(e,v.resolve(e,s,t)))}function Z(e,s){const n={};for(const r of e){const l=v.dirname(r.relativePathFromDirectory),g=r.version?M+r.version:"",i=v.basename(r.relativePathFromDirectory)+g;d(l,r,i)}const t=f(a(n));return T(t,s);function a(r){const l=[];for(const g of Object.keys(r)){const i=r[g];l.push({...i,items:i.items?a(i.items):void 0})}return l}function f(r){return r.sort((l,g)=>{const i=typeof l=="string"?l.toLowerCase():l.relativePathFromDirectory||l.label||"",u=typeof g=="string"?g.toLowerCase():g.relativePathFromDirectory||g.label||"";return i.startsWith("index.")?-1:u.startsWith("index.")?1:i.localeCompare(u,void 0,{numeric:!0})})}function d(r,l,g){r==="."&&(r="");const i=r.split("/").filter(Boolean);let u=n;for(const o of i){const h=o+(l?.version||"");u[h]||(u[h]={type:"group",version:l?.version,label:o,isDefault:l?.isDefault,versionFolderId:l.versionFolderId,items:{}}),u=u[h].items}u[g]=l}}function T(e,s){return e.flatMap(n=>n?.sidebarItems?s.groupCustomSidebars?{...n,items:n.sidebarItems,sidebarItems:void 0,relativePathFromDirectory:void 0}:n.sidebarItems:{...n,items:n.items?T(n.items,s):void 0})}function k(e,s,n,t){return e.map(a=>({...a,...s,[p]:a[p]||n,[b]:a[b]||t,items:a.type==="group"&&a.items?k(a.items,s,n):a.items}))}function ee(e){return e.replace(/@[^/]+\//,"")}async function Pe(e,s,n,t){const a=(e?.items||[]).filter(r=>r.linkedSidebars?.length).map(r=>({...r,items:void 0})),f=await D(a,s.contentDir,s,n,t),d=new Map;for(const r of f)if(r.linkedSidebars?.length)for(const l of r.linkedSidebars){if(d.has(l)){A.warn(`Only one navbar item can belong to sidebar. "${l}" on 'linkedSidebars' property on "${r.label}" will be ignored.`);continue}d.set(l,{label:r.label,link:r.link})}return d}export{Pe as collectItemsLinkedToSidebars,N as normalizeItems,K as resolveItem,I as resolveItems,D as resolveLinksFromConfig};
@@ -1,5 +1,4 @@
1
- import type { RedoclyConfig } from '@redocly/config';
2
- import type { PageProps, PageStaticData } from '@redocly/config';
1
+ import type { RedoclyConfig, PageProps, PageStaticData } from '@redocly/config';
3
2
  import type { PageRouteDetails } from '../../../types';
4
3
  import type { LLMsTxt } from './types.js';
5
4
  export declare function isIncludedInLlmsTxt(llmsTxt: LLMsTxt, route: PageRouteDetails<PageStaticData, PageProps>, config: RedoclyConfig): boolean;
@@ -1 +1 @@
1
- import{and as g,eq as v,gt as c,lt as a,or as b,sql as p}from"drizzle-orm";import{decodeCursor as q}from"./utils/decode-cursor.js";const G=e=>{if(e===null||typeof e!="object")return!1;const r=e;return typeof r.value=="string"&&typeof r.id=="string"},M=e=>{if(e===null||typeof e!="object")return!1;const r=e;return Array.isArray(r.values)&&r.values.every(f=>typeof f=="string")&&typeof r.id=="string"};function k(e,r,f){if(e.length!==r.length)return p`0`;const h=[];for(let t=0;t<e.length;t++){const C=p.identifier(e[t].field),y=r[t],m=e[t].order==="ASC",d=f==="after"&&m||f==="before"&&!m?c(C,y):a(C,y);if(t===0)h.push(d);else{const o=e.slice(0,t).map((i,S)=>v(p.identifier(i.field),r[S]));h.push(g(g(...o),d))}}return b(...h)}const N=(e,r)=>{const{after:f,before:h}=r;if(!f&&!h)return{sqlBuilder:e,whereCondition:null};const t=q(f),C=q(h),y=t!=null,m=C!=null&&!y,l=r.sort&&r.sort.length>0?r.sort:[{field:"id",order:"ASC"}],d=l[0],o=p.identifier(d.field),i=p.identifier("id");let S=null;function j(B,A){if(!B)return null;try{const n=JSON.parse(B);if(M(n)){const F=l[l.length-1]?.field==="id",I=n.id!=null,w=l.length===n.values.length+1&&F&&I,T=!F&&I&&l.length===n.values.length,x=T?[...l,{field:"id",order:l[0]?.order??"ASC"}]:l,E=w||T?[...n.values,n.id]:n.values;return k(x,E,A)}if(!G(n))return null;const s=String(n.value),u=String(n.id);return d.field==="id"?d.order==="ASC"?A==="after"?c(i,u):a(i,u):A==="after"?a(i,u):c(i,u):d.order==="ASC"?A==="after"?b(c(o,s),g(v(o,s),c(i,u))):b(a(o,s),g(v(o,s),a(i,u))):A==="after"?b(a(o,s),g(v(o,s),a(i,u))):b(c(o,s),g(v(o,s),c(i,u)))}catch{return null}}return y?S=j(t,"after"):m&&(S=j(C,"before")),{sqlBuilder:e,whereCondition:S}};export{N as applyAfterAndBefore};
1
+ import{and as g,eq as v,gt as c,lt as a,or as b,sql as p}from"drizzle-orm";import{decodeCursor as q}from"./utils/decode-cursor.js";const G=e=>{if(e===null||typeof e!="object")return!1;const r=e;return typeof r.value=="string"&&typeof r.id=="string"},M=e=>{if(e===null||typeof e!="object")return!1;const r=e;return Array.isArray(r.values)&&r.values.every(f=>typeof f=="string")&&typeof r.id=="string"};function k(e,r,f){if(e.length!==r.length)return p`0`;const h=[];for(let t=0;t<e.length;t++){const C=p.identifier(e[t].field),y=r[t],m=e[t].order==="ASC",d=f==="after"&&m||f==="before"&&!m?c(C,y):a(C,y);if(t===0)h.push(d);else{const n=e.slice(0,t).map((o,S)=>v(p.identifier(o.field),r[S]));h.push(g(g(...n),d))}}return b(...h)}const N=(e,r)=>{const{after:f,before:h}=r;if(!f&&!h)return{sqlBuilder:e,whereCondition:null};const t=q(f),C=q(h),y=t!=null,m=C!=null&&!y,l=r.sort&&r.sort.length>0?r.sort:[{field:"id",order:"ASC"}],d=l[0],n=p.identifier(d.field),o=p.identifier("id");let S=null;function j(B,A){if(!B)return null;try{const i=JSON.parse(B);if(M(i)){const F=l[l.length-1]?.field==="id",I=i.id!=null,w=l.length===i.values.length+1&&F&&I,T=!F&&I&&l.length===i.values.length,x=T?[...l,{field:"id",order:l[0]?.order??"ASC"}]:l,E=w||T?[...i.values,i.id]:i.values;return k(x,E,A)}if(!G(i))return null;const s=String(i.value),u=String(i.id);return d.field==="id"?d.order==="ASC"?A==="after"?c(o,u):a(o,u):A==="after"?a(o,u):c(o,u):d.order==="ASC"?A==="after"?b(c(n,s),g(v(n,s),c(o,u))):b(a(n,s),g(v(n,s),a(o,u))):A==="after"?b(a(n,s),g(v(n,s),a(o,u))):b(c(n,s),g(v(n,s),c(o,u)))}catch{return null}}return y?S=j(t,"after"):m&&(S=j(C,"before")),{sqlBuilder:e,whereCondition:S}};export{N as applyAfterAndBefore};
@@ -1 +1 @@
1
- import{isBase64 as r}from"./is-base-64.js";function n(e){if(!e)return e;if(r(e))try{return Buffer.from(e,"base64url").toString()}catch{return e}return e}export{n as decodeCursor};
1
+ import{isBase64 as e}from"./is-base-64.js";function f(t){if(!t)return t;if(e(t))try{return Buffer.from(t,"base64url").toString()}catch{return t}return t}export{f as decodeCursor};
@@ -1 +1 @@
1
- function t(r){try{return Buffer.from(r,"base64").toString("base64")===r}catch{return!1}}export{t as isBase64};
1
+ function r(e){try{return Buffer.from(e,"base64").toString("base64")===e}catch{return!1}}export{r as isBase64};
@@ -1,3 +1,6 @@
1
1
  export declare const MAX_HOST_OUTPUT_BYTES: number;
2
2
  export declare const DEFAULT_GLOBAL_NAME = "hostFunctions";
3
+ /** Guest error names for host-side failures, so the sandbox can tell them from a guest throw. */
4
+ export declare const HOST_FUNCTION_ERROR_NAME = "HostFunctionError";
5
+ export declare const HOST_OUTPUT_TOO_LARGE_ERROR_NAME = "HostOutputTooLargeError";
3
6
  //# sourceMappingURL=host-functions.d.ts.map
@@ -1 +1 @@
1
- const o=1048576,t="hostFunctions";export{t as DEFAULT_GLOBAL_NAME,o as MAX_HOST_OUTPUT_BYTES};
1
+ const o=1048576,t="hostFunctions",_="HostFunctionError",O="HostOutputTooLargeError";export{t as DEFAULT_GLOBAL_NAME,_ as HOST_FUNCTION_ERROR_NAME,O as HOST_OUTPUT_TOO_LARGE_ERROR_NAME,o as MAX_HOST_OUTPUT_BYTES};
@@ -6,4 +6,14 @@ export declare const MAX_ALLOCATION_BYTES: number;
6
6
  export declare const MAX_TOTAL_MEMORY_BYTES: number;
7
7
  export declare const INITIAL_TOTAL_MEMORY_BYTES: number;
8
8
  export declare const WASM_PAGE_BYTES: number;
9
+ /** Why a run failed. */
10
+ export declare const SANDBOX_FAILURE: {
11
+ readonly NoReturn: 'no_return';
12
+ readonly OutputTooLarge: 'output_too_large';
13
+ readonly Timeout: 'timeout';
14
+ readonly MemoryLimit: 'memory_limit';
15
+ readonly SyntaxError: 'syntax_error';
16
+ readonly HostError: 'host_error';
17
+ readonly RuntimeError: 'runtime_error';
18
+ };
9
19
  //# sourceMappingURL=sandbox.d.ts.map