@redocly/redoc-reef 0.136.0-next.4 → 0.136.0-next.6

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 (127) hide show
  1. package/CHANGELOG.md +47 -0
  2. package/dist/client/ErrorBoundary.js +1 -1
  3. package/dist/client/app/Sidebar/helpers/hide-empty-separators.d.ts +13 -0
  4. package/dist/client/app/Sidebar/helpers/hide-empty-separators.js +1 -0
  5. package/dist/client/app/Sidebar/utils.js +1 -1
  6. package/dist/client/app/l10n/hooks/useTranslate.js +1 -1
  7. package/dist/client/app/l10n/initL10n.js +1 -1
  8. package/dist/client/app/utils/same-resolved-route.d.ts +5 -0
  9. package/dist/client/app/utils/same-resolved-route.js +1 -0
  10. package/dist/client/providers/post-message/PostMessageProvider.js +1 -1
  11. package/dist/client/templates/openapi-docs/helpers.d.ts +1 -1
  12. package/dist/client/templates/openapi-docs/helpers.js +2 -2
  13. package/dist/constants/common.d.ts +13 -1
  14. package/dist/constants/common.js +1 -1
  15. package/dist/server/config/env-config.d.ts +2 -4
  16. package/dist/server/config/env-schema.d.ts +5 -10
  17. package/dist/server/config/env-schemas/feature-flags.d.ts +4 -8
  18. package/dist/server/config/env-schemas/feature-flags.js +1 -1
  19. package/dist/server/constants/common.d.ts +2 -0
  20. package/dist/server/constants/common.js +1 -1
  21. package/dist/server/constants/entitlements.js +1 -1
  22. package/dist/server/plugins/config-parser/loaders/utils/read-and-validate-config.js +1 -1
  23. package/dist/server/plugins/markdown/search/create-render-tag-fn.d.ts +2 -1
  24. package/dist/server/plugins/markdown/search/create-render-tag-fn.js +1 -1
  25. package/dist/server/plugins/markdown/search/get-ai-search-documents.js +9 -9
  26. package/dist/server/plugins/mcp/auth/auth-handlers.d.ts +1 -0
  27. package/dist/server/plugins/mcp/auth/auth-handlers.js +1 -1
  28. package/dist/server/plugins/mcp/codemode/tools/execute.js +1 -1
  29. package/dist/server/plugins/mcp/gateway-mcp/elicitation.d.ts +27 -0
  30. package/dist/server/plugins/mcp/gateway-mcp/elicitation.js +2 -0
  31. package/dist/server/plugins/mcp/gateway-mcp/eligibility.d.ts +4 -15
  32. package/dist/server/plugins/mcp/gateway-mcp/eligibility.js +1 -1
  33. package/dist/server/plugins/mcp/gateway-mcp/fetch/allowed-hosts.d.ts +8 -8
  34. package/dist/server/plugins/mcp/gateway-mcp/fetch/allowed-hosts.js +1 -1
  35. package/dist/server/plugins/mcp/gateway-mcp/fetch/fetch-bridge.d.ts +17 -1
  36. package/dist/server/plugins/mcp/gateway-mcp/fetch/fetch-bridge.js +1 -1
  37. package/dist/server/plugins/mcp/gateway-mcp/fetch/fetch-errors.d.ts +11 -0
  38. package/dist/server/plugins/mcp/gateway-mcp/fetch/fetch-errors.js +1 -0
  39. package/dist/server/plugins/mcp/gateway-mcp/fetch/fetch-telemetry.d.ts +13 -0
  40. package/dist/server/plugins/mcp/gateway-mcp/fetch/fetch-telemetry.js +1 -0
  41. package/dist/server/plugins/mcp/gateway-mcp/fetch/redact.d.ts +4 -0
  42. package/dist/server/plugins/mcp/gateway-mcp/fetch/redact.js +1 -0
  43. package/dist/server/plugins/mcp/gateway-mcp/fetch/ssrf-blocklist.d.ts +22 -0
  44. package/dist/server/plugins/mcp/gateway-mcp/fetch/ssrf-blocklist.js +1 -0
  45. package/dist/server/plugins/mcp/gateway-mcp/fetch/ssrf-guard.d.ts +1 -1
  46. package/dist/server/plugins/mcp/gateway-mcp/fetch/ssrf-guard.js +1 -1
  47. package/dist/server/plugins/mcp/gateway-mcp/fetch/ssrf-safe-lookup.d.ts +13 -0
  48. package/dist/server/plugins/mcp/gateway-mcp/fetch/ssrf-safe-lookup.js +1 -0
  49. package/dist/server/plugins/mcp/gateway-mcp/fetch-capability.d.ts +8 -1
  50. package/dist/server/plugins/mcp/gateway-mcp/fetch-capability.js +1 -1
  51. package/dist/server/plugins/mcp/gateway-mcp/rate-limit/apply-edge-rate-limit.d.ts +3 -0
  52. package/dist/server/plugins/mcp/gateway-mcp/rate-limit/apply-edge-rate-limit.js +1 -0
  53. package/dist/server/plugins/mcp/gateway-mcp/rate-limit/edge-limiter.d.ts +16 -0
  54. package/dist/server/plugins/mcp/gateway-mcp/rate-limit/edge-limiter.js +1 -0
  55. package/dist/server/plugins/mcp/gateway-mcp/rate-limit/ip-key.d.ts +2 -0
  56. package/dist/server/plugins/mcp/gateway-mcp/rate-limit/ip-key.js +1 -0
  57. package/dist/server/plugins/mcp/gateway-mcp/rate-limit/limits.d.ts +7 -0
  58. package/dist/server/plugins/mcp/gateway-mcp/rate-limit/limits.js +1 -0
  59. package/dist/server/plugins/mcp/gateway-mcp/rate-limit/window-counter.d.ts +15 -0
  60. package/dist/server/plugins/mcp/gateway-mcp/rate-limit/window-counter.js +1 -0
  61. package/dist/server/plugins/mcp/gateway-mcp/secret-store.d.ts +24 -0
  62. package/dist/server/plugins/mcp/gateway-mcp/secret-store.js +1 -0
  63. package/dist/server/plugins/mcp/gateway-mcp/upstream-auth-scheme.d.ts +18 -0
  64. package/dist/server/plugins/mcp/gateway-mcp/upstream-auth-scheme.js +1 -0
  65. package/dist/server/plugins/mcp/gateway-mcp/upstream-auth.d.ts +10 -0
  66. package/dist/server/plugins/mcp/gateway-mcp/upstream-auth.js +1 -0
  67. package/dist/server/plugins/mcp/handlers/docs-mcp-handler.js +1 -1
  68. package/dist/server/plugins/mcp/handlers/errors.d.ts +3 -3
  69. package/dist/server/plugins/mcp/handlers/errors.js +1 -1
  70. package/dist/server/plugins/mcp/handlers/handle-mcp-request.js +1 -1
  71. package/dist/server/plugins/mcp/handlers/mcp-credentials-handler.d.ts +5 -0
  72. package/dist/server/plugins/mcp/handlers/mcp-credentials-handler.js +101 -0
  73. package/dist/server/plugins/mcp/index.d.ts +1 -0
  74. package/dist/server/plugins/mcp/index.js +1 -1
  75. package/dist/server/plugins/mcp/servers/docs-server.d.ts +5 -2
  76. package/dist/server/plugins/mcp/servers/docs-server.js +1 -1
  77. package/dist/server/plugins/mcp/servers/mcp-server.d.ts +13 -2
  78. package/dist/server/plugins/mcp/servers/mcp-server.js +1 -1
  79. package/dist/server/plugins/mcp/servers/session-manager.d.ts +15 -0
  80. package/dist/server/plugins/mcp/servers/session-manager.js +1 -0
  81. package/dist/server/plugins/mcp/types.d.ts +9 -12
  82. package/dist/server/plugins/mcp/utils/jwt.d.ts +0 -9
  83. package/dist/server/plugins/mcp/utils/jwt.js +1 -1
  84. package/dist/server/plugins/mcp/utils/mode.d.ts +12 -2
  85. package/dist/server/plugins/mcp/utils/mode.js +1 -1
  86. package/dist/server/plugins/mcp/utils/telemetry-attributes.d.ts +8 -0
  87. package/dist/server/plugins/mcp/utils/telemetry-attributes.js +1 -0
  88. package/dist/server/plugins/mcp/workers/execute-mcp-tool.js +1 -1
  89. package/dist/server/plugins/mcp/workers/mcp-tool-telemetry.js +1 -1
  90. package/dist/server/plugins/openapi-docs/search/get-ai-search-documents.js +16 -16
  91. package/dist/server/plugins/openapi-docs/utils.js +1 -1
  92. package/dist/server/plugins/sso/index.js +1 -1
  93. package/dist/server/sandbox/types.d.ts +3 -2
  94. package/dist/server/sandbox/utils/execution-budget.d.ts +4 -3
  95. package/dist/server/sandbox/utils/execution-budget.js +1 -1
  96. package/dist/server/types/plugins/markdown.d.ts +2 -2
  97. package/dist/server/utils/crypto/constants.d.ts +5 -0
  98. package/dist/server/utils/crypto/constants.js +1 -0
  99. package/dist/server/utils/crypto/decrypt-aes-gcm.d.ts +6 -0
  100. package/dist/server/utils/crypto/decrypt-aes-gcm.js +1 -0
  101. package/dist/server/utils/crypto/decrypt-claim-value.d.ts +6 -0
  102. package/dist/server/utils/crypto/decrypt-claim-value.js +1 -0
  103. package/dist/server/utils/crypto/derive-key.d.ts +5 -0
  104. package/dist/server/utils/crypto/derive-key.js +1 -0
  105. package/dist/server/utils/crypto/encrypt-aes-gcm.d.ts +6 -0
  106. package/dist/server/utils/crypto/encrypt-aes-gcm.js +1 -0
  107. package/dist/server/utils/crypto/encrypt-claim-value.d.ts +6 -0
  108. package/dist/server/utils/crypto/encrypt-claim-value.js +1 -0
  109. package/dist/server/utils/l10n/get-build-translate-context.d.ts +7 -0
  110. package/dist/server/utils/l10n/get-build-translate-context.js +1 -0
  111. package/dist/server/utils/rbac.d.ts +4 -0
  112. package/dist/server/utils/rbac.js +1 -1
  113. package/dist/server/web-server/auth.d.ts +33 -3
  114. package/dist/server/web-server/auth.js +3 -3
  115. package/dist/server/web-server/handle-api-route-request.js +1 -1
  116. package/dist/server/web-server/routes/api-routes/api-routes.js +1 -1
  117. package/dist/server/web-server/routes/auth.js +1 -1
  118. package/dist/server/web-server/routes/mcp-routes/mcp-oauth.d.ts +5 -2
  119. package/dist/server/web-server/routes/mcp-routes/mcp-oauth.js +1 -1
  120. package/dist/server/web-server/routes/mcp-routes/mcp-routes.js +1 -1
  121. package/dist/server/workers/worker-pool.js +1 -1
  122. package/dist/types/entitlements.d.ts +6 -1
  123. package/dist/utils/l10n/build-i18n-config.d.ts +24 -0
  124. package/dist/utils/l10n/build-i18n-config.js +1 -0
  125. package/dist/utils/l10n/create-translate.d.ts +19 -0
  126. package/dist/utils/l10n/create-translate.js +1 -0
  127. package/package.json +11 -10
@@ -1 +1 @@
1
- import{fileURLToPath as O}from"node:url";import{dirname as T,join as c}from"node:path";import{logger as g}from"../../tools/notifiers/logger.js";import{reporter as A}from"../../tools/notifiers/reporter.js";import{isDefined as R}from"../../../utils/guards/is-defined.js";import{buildGraphqlDescriptions as w,filterIgnoredApiDescriptions as u,getCleanedUpApiDescriptions as L,isMcpInRedirects as q}from"./utils.js";import{isMcpCodeModeEnabled as G}from"./utils/mode.js";import{getDefaultToolSchemas as N}from"./docs-mcp/tool-schemas.js";import{EXECUTE_TOOL_SCHEMA as j}from"./codemode/tools/execute-schema.js";import{isGatewayCapabilityEnabled as U,isGatewayEligible as H}from"./gateway-mcp/eligibility.js";import{telemetryTraceStep as I}from"../../../cli/telemetry/helpers/trace-step.js";import{DEFAULT_DOCS_MCP_SERVER_NAME as F,MCP_NOT_ALLOWED_TEMPLATE_ID as x}from"./constants.js";const h="mcp-docs-server-handler",V="/mcp",p=T(O(import.meta.url));async function B(){let r=!1;return{id:"mcp",async processContent(i,o){r||await I("build.plugin.mcp",async a=>{const s=await i.loadOpenApiDefinitions(o),l=await i.loadGraphqlDefinitions(o),n=await o.getConfig(),{mcp:t,redirects:D}=n;if(a?.setAttribute("config",JSON.stringify(t||{})),!(t?.hide||t?.docs?.hide)&&(q(D)&&await A.panicOnBuildContentError('The reserved route "/mcp" cannot be used in redirect configuration. Please remove any redirects involving "/mcp" from your redocly.yaml config.'),i.createTemplate(x,"@redocly/theme/layouts/McpNotAllowed"),!t?.docs?.hide)){g.info("Configuring MCP servers...");const C=c(p,"./handlers/docs-mcp-handler.js"),E=L(u(s,t?.docs?.ignore||[])),M=!!n?.access?.requiresLogin,d=n?.access?.rbac||{},v=U(t),m=new Map;for(const e of E){const b=e.definition.info?.title||"",S=e.definition.info?.version||"";m.set(e.relativePath,{name:b,description:e.definition.info?.description||"",version:S,servers:e.definition.servers||[],relativePath:e.relativePath,...v&&H(e.definition.info,e.relativePath,d)?{fetchEligible:!0}:{}})}const f=w(u(l,t?.docs?.ignore||[])),y=Object.values(n.products||{}).map(e=>e?.name).filter(R),P=n.l10n?.locales?.map(e=>e.code)??o.fs.localeFolders,_=N({products:y,locales:P,requiresLogin:M,rbac:d,hasGraphqlApis:f.length>0});i.addMcpTools(c(p,"./docs-mcp/tools/index.js"),_),G()&&i.addMcpTools(c(p,"./codemode/tools/execute.js"),[j]),await J({actions:i,handlerPath:C,apiDescriptionsMap:Object.fromEntries(m),graphqlDescriptions:f,mcpConfig:t}),r=!0}})},async afterRoutesCreated(i,o){const a=await o.getConfig(),{mcp:s}=a;i.setGlobalData({mcpData:{docs:{enabled:!s?.hide&&!s?.docs?.hide,name:s?.docs?.name}}})}}}var te=B;async function J({actions:r,handlerPath:i,apiDescriptionsMap:o,graphqlDescriptions:a,mcpConfig:s}){r.createRequestHandler(h,i),r.addApiRoute({slug:V,requestHandlerId:h,httpMethod:"all",getStaticData:async()=>({props:{config:{apiDescriptionsMap:o,graphqlDescriptions:a,mcpDocsServerName:s?.docs?.name||F},serverOutDir:r.serverOutDir,tools:r.getMcpTools().map(({importPath:l,...n})=>n)}})}),g.info("Registered Docs MCP Server endpoint at /mcp")}export{h as MCP_DOCS_SERVER_HANDLER_ID,te as default,B as mcpServerPlugin};
1
+ import{fileURLToPath as w}from"node:url";import{dirname as q,join as p}from"node:path";import{logger as f}from"../../tools/notifiers/logger.js";import{reporter as G}from"../../tools/notifiers/reporter.js";import{isDefined as N}from"../../../utils/guards/is-defined.js";import{buildGraphqlDescriptions as H,filterIgnoredApiDescriptions as E,getCleanedUpApiDescriptions as I,isMcpInRedirects as U}from"./utils.js";import{getMcpMode as j,isMcpElicitationEnabled as x}from"./utils/mode.js";import{getDefaultToolSchemas as F}from"./docs-mcp/tool-schemas.js";import{EXECUTE_TOOL_SCHEMA as B}from"./codemode/tools/execute-schema.js";import{isGatewayCapabilityEnabled as V,isGatewayEligible as J}from"./gateway-mcp/eligibility.js";import{resolveGatewayFetchLimits as W}from"./gateway-mcp/rate-limit/limits.js";import{telemetryTraceStep as X}from"../../../cli/telemetry/helpers/trace-step.js";import{DEFAULT_DOCS_MCP_SERVER_NAME as M,MCP_NOT_ALLOWED_TEMPLATE_ID as k}from"./constants.js";const C="mcp-docs-server-handler",z="/mcp",P="mcp-credentials-handler",K="/mcp/credentials",d=q(w(import.meta.url));async function Q(){let o=!1;return{id:"mcp",async processContent(t,r){o||await X("build.plugin.mcp",async a=>{const n=await t.loadOpenApiDefinitions(r),l=await t.loadGraphqlDefinitions(r),s=await r.getConfig(),{mcp:i,redirects:c}=s;if(a?.setAttribute("config",JSON.stringify(i||{})),!(i?.hide||i?.docs?.hide)&&(U(c)&&await G.panicOnBuildContentError('The reserved route "/mcp" cannot be used in redirect configuration. Please remove any redirects involving "/mcp" from your redocly.yaml config.'),t.createTemplate(k,"@redocly/theme/layouts/McpNotAllowed"),!i?.docs?.hide)){f.info("Configuring MCP servers...");const m=p(d,"./handlers/docs-mcp-handler.js"),_=I(E(n,i?.docs?.ignore||[])),v=!!s?.access?.requiresLogin,g=s?.access?.rbac||{},y=V(i),u=new Map;for(const e of _){const O=e.definition.info?.title||"",L=e.definition.info?.version||"";u.set(e.relativePath,{name:O,description:e.definition.info?.description||"",version:L,servers:e.definition.servers||[],relativePath:e.relativePath,...y&&J(e.definition.info,e.relativePath,g)?{fetchEligible:!0}:{}})}const h=H(E(l,i?.docs?.ignore||[])),R=Object.values(s.products||{}).map(e=>e?.name).filter(N),S=s.l10n?.locales?.map(e=>e.code)??r.fs.localeFolders,b=F({products:R,locales:S,requiresLogin:v,rbac:g,hasGraphqlApis:h.length>0});t.addMcpTools(p(d,"./docs-mcp/tools/index.js"),b);const D=j(),A=x(),{budgetPerExec:T}=W();D==="code"&&t.addMcpTools(p(d,"./codemode/tools/execute.js"),[B]),await Y({actions:t,handlerPath:m,apiDescriptionsMap:Object.fromEntries(u),graphqlDescriptions:h,mcpConfig:i,mcpMode:D,elicitationEnabled:A,gatewayFetchBudgetPerExec:T}),o=!0}})},async afterRoutesCreated(t,r){const a=await r.getConfig(),{mcp:n}=a;t.setGlobalData({mcpData:{docs:{enabled:!n?.hide&&!n?.docs?.hide,name:n?.docs?.name||M}}})}}}var le=Q;async function Y({actions:o,handlerPath:t,apiDescriptionsMap:r,graphqlDescriptions:a,mcpConfig:n,mcpMode:l,elicitationEnabled:s,gatewayFetchBudgetPerExec:i}){if(o.createRequestHandler(C,t),o.addApiRoute({slug:z,requestHandlerId:C,httpMethod:"all",getStaticData:async()=>({props:{config:{apiDescriptionsMap:r,graphqlDescriptions:a,mcpDocsServerName:n?.docs?.name||M,mcpMode:l,elicitationEnabled:s,gatewayFetchBudgetPerExec:i},serverOutDir:o.serverOutDir,tools:o.getMcpTools().map(({importPath:c,...m})=>m)}})}),f.info("Registered Docs MCP Server endpoint at /mcp"),s){const c=p(d,"./handlers/mcp-credentials-handler.js");o.createRequestHandler(P,c),o.addApiRoute({slug:K,requestHandlerId:P,httpMethod:"all",getStaticData:async()=>({props:{}})}),f.info("Registered MCP credentials endpoint at /mcp/credentials")}}export{P as MCP_CREDENTIALS_HANDLER_ID,C as MCP_DOCS_SERVER_HANDLER_ID,le as default,Q as mcpServerPlugin};
@@ -1,10 +1,13 @@
1
1
  import type { McpToolSchema } from '../../../types';
2
2
  import type { McpToolContext, SkillMcpResource } from '../types.js';
3
- import { type McpServerInstance } from './mcp-server.js';
4
- export declare function createDocsMcpServer({ name, tools, context, skills, }: {
3
+ import type { KvService } from '@redocly/config';
4
+ import { type McpServerInstance, type McpSessionHooks } from './mcp-server.js';
5
+ export declare function createDocsMcpServer({ name, tools, context, sessionHooks, skills, getKv, }: {
5
6
  name: string;
6
7
  tools: McpToolSchema[];
7
8
  context: McpToolContext;
9
+ sessionHooks?: McpSessionHooks;
8
10
  skills?: SkillMcpResource[];
11
+ getKv: () => Promise<KvService>;
9
12
  }): Promise<McpServerInstance>;
10
13
  //# sourceMappingURL=docs-server.d.ts.map
@@ -1 +1 @@
1
- import{logger as O}from"../../../tools/notifiers/logger.js";import{mcpToolWorkers as _,MCP_TOOL_IS_AVAILABLE_KEY as u}from"../../../workers/mcp-tool-worker-pool.js";import{EXECUTE_TOOL_SCHEMA as C}from"../codemode/tools/execute-schema.js";import{EXECUTE_TOOL_NAME as p,DESCRIBE_TOOLS_TOOL_NAME as M,CODE_MODE_TOOL_NAMES as b,FETCH_TOOL_NAME as S}from"../codemode/constants.js";import{buildCodeModeInstructions as A,buildExecuteDescription as h,DESCRIBE_TOOLS_DESCRIPTION as x}from"../codemode/prompts.js";import{composeExecuteAnnotations as L,getActiveCapabilities as D}from"../codemode/capabilities/index.js";import{describeToolsSchema as v,describeTools as y}from"../codemode/tools/describe-tools.js";import{isMcpCodeModeEnabled as g}from"../utils/mode.js";import{connectMcpServer as I,createMcpServer as k,createToolDispatch as w,extractSerializableContext as N}from"./mcp-server.js";async function K({name:E,tools:a,context:i,skills:d=[]}){const n=g(),r=n?D(i):[],s=r.some(e=>e.id===S),{server:o,transport:f}=k(E,n?A(s):void 0),c=N(i),m=w(c),l=async e=>{try{return await _.exec(u,[{toolName:e,context:c}],{timeout:1e4})}catch(t){return O.error(`Failed to check MCP tool availability for "${e}": ${t instanceof Error?t.message:String(t)}`),!1}};if(n){const e=a.filter(t=>!b.has(t.name));o.tool(p,h(s),C.schema,L(r),m(p)),o.tool(M,x,v(e,r),y(e,l,r,i))}else await Promise.all(a.map(async e=>{const t=e.annotations||{title:e.name},T=o.tool(e.name,e.description,e.schema,t,m(e.name));await l(e.name)||T.disable()}));for(const e of d)o.registerResource(e.slug,e.uri,{title:e.name,description:e.description,mimeType:"text/markdown"},async()=>({contents:[{uri:e.uri,mimeType:"text/markdown",text:e.content}]}));return I(o,f)}export{K as createDocsMcpServer};
1
+ import{logger as _}from"../../../tools/notifiers/logger.js";import{mcpToolWorkers as u,MCP_TOOL_IS_AVAILABLE_KEY as b}from"../../../workers/mcp-tool-worker-pool.js";import{EXECUTE_TOOL_SCHEMA as M}from"../codemode/tools/execute-schema.js";import{EXECUTE_TOOL_NAME as p,DESCRIBE_TOOLS_TOOL_NAME as S,CODE_MODE_TOOL_NAMES as A,FETCH_TOOL_NAME as h}from"../codemode/constants.js";import{buildCodeModeInstructions as L,buildExecuteDescription as g,DESCRIBE_TOOLS_DESCRIPTION as v}from"../codemode/prompts.js";import{composeExecuteAnnotations as x,getActiveCapabilities as D}from"../codemode/capabilities/index.js";import{describeToolsSchema as y,describeTools as I}from"../codemode/tools/describe-tools.js";import{connectMcpServer as k,createMcpServer as w,createToolDispatch as N,extractSerializableContext as P}from"./mcp-server.js";async function K({name:E,tools:n,context:o,sessionHooks:d,skills:T=[],getKv:f}){const a=o.mcpMode==="code",r=a?D(o):[],s=r.some(e=>e.id===h),{server:i,transport:C}=w(E,a?L(s):void 0,d),c=P(o),m=N(c,{getClientCapabilities:()=>i.server.getClientCapabilities(),getKv:f}),l=async e=>{try{return await u.exec(b,[{toolName:e,context:c}],{timeout:1e4})}catch(t){return _.error(`Failed to check MCP tool availability for "${e}": ${t instanceof Error?t.message:String(t)}`),!1}};if(a){const e=n.filter(t=>!A.has(t.name));i.tool(p,g(s),M.schema,x(r),m(p)),i.tool(S,v,y(e,r),I(e,l,r,o))}else await Promise.all(n.map(async e=>{const t=e.annotations||{title:e.name},O=i.tool(e.name,e.description,e.schema,t,m(e.name));await l(e.name)||O.disable()}));for(const e of T)i.registerResource(e.slug,e.uri,{title:e.name,description:e.description,mimeType:"text/markdown"},async()=>({contents:[{uri:e.uri,mimeType:"text/markdown",text:e.content}]}));return k(i,C)}export{K as createDocsMcpServer};
@@ -2,17 +2,28 @@ import { McpServer } from '@redocly/mcp-typescript-sdk/server/mcp.js';
2
2
  import { StreamableHTTPServerTransport } from '@redocly/mcp-typescript-sdk/server/streamableHttp.js';
3
3
  import type { ToolCallback } from '@redocly/mcp-typescript-sdk/server/mcp.js';
4
4
  import type { McpToolContext } from '../types.js';
5
+ import type { KvService } from '@redocly/config';
5
6
  export type McpServerInstance = {
6
7
  server: McpServer;
7
8
  transport: StreamableHTTPServerTransport;
8
9
  cleanup: () => Promise<void>;
9
10
  };
10
- export declare function createMcpServer(name: string, instructions?: string): {
11
+ export type McpSessionHooks = {
12
+ onInitialized: (sessionId: string) => void;
13
+ onClosed: (sessionId: string) => void;
14
+ };
15
+ export declare function createMcpServer(name: string, instructions?: string, sessionHooks?: McpSessionHooks): {
11
16
  server: McpServer;
12
17
  transport: StreamableHTTPServerTransport;
13
18
  };
14
19
  export declare function connectMcpServer(server: McpServer, transport: StreamableHTTPServerTransport): Promise<McpServerInstance>;
20
+ export type ToolDispatchDeps = {
21
+ getClientCapabilities: () => {
22
+ elicitation?: unknown;
23
+ } | undefined;
24
+ getKv: () => Promise<KvService>;
25
+ };
15
26
  /** Build the tool callback that ships a tool call to the worker pool. */
16
- export declare function createToolDispatch(serializableContext: McpToolContext): (toolName: string) => ToolCallback<Record<string, unknown>>;
27
+ export declare function createToolDispatch(serializableContext: McpToolContext, deps?: ToolDispatchDeps): (toolName: string) => ToolCallback<Record<string, unknown>>;
17
28
  export declare function extractSerializableContext(context: McpToolContext): McpToolContext;
18
29
  //# sourceMappingURL=mcp-server.d.ts.map
@@ -1 +1 @@
1
- import{McpServer as i}from"@redocly/mcp-typescript-sdk/server/mcp.js";import{StreamableHTTPServerTransport as t}from"@redocly/mcp-typescript-sdk/server/streamableHttp.js";import{logger as n}from"../../../tools/notifiers/logger.js";import{mcpToolWorkers as c,MCP_TOOL_WORKER_KEY as u}from"../../../workers/mcp-tool-worker-pool.js";const p=6e4;function T(e,r){const o=new i({name:e,version:new Date().toISOString().slice(0,10)},{capabilities:{logging:{}},...r?{instructions:r}:{}}),a=new t({sessionIdGenerator:void 0});return{server:o,transport:a}}async function g(e,r){return await e.connect(r),{server:e,transport:r,cleanup:async()=>{r.close()}}}function S(e){return r=>async(o,a)=>{n.info(`MCP tool called: ${r}`);const s={toolName:r,args:o,context:e,extra:l(a)};return await c.exec(u,[s],{timeout:p})}}function l(e){return{sessionId:e.sessionId,authInfo:e.authInfo,requestId:e.requestId,requestInfo:e.requestInfo,_meta:e._meta}}function q(e){return{user:e.user,config:e.config,outdir:e.outdir,baseUrl:e.baseUrl,params:e.params,query:e.query,cookies:e.cookies,apiDescriptionsMap:e.apiDescriptionsMap,graphqlDescriptions:e.graphqlDescriptions,products:e.products,accessToken:e.accessToken,metadata:e.metadata,upstreamAuthorization:e.upstreamAuthorization}}export{g as connectMcpServer,T as createMcpServer,S as createToolDispatch,q as extractSerializableContext};
1
+ import{randomUUID as w}from"node:crypto";import{McpServer as h}from"@redocly/mcp-typescript-sdk/server/mcp.js";import{StreamableHTTPServerTransport as E}from"@redocly/mcp-typescript-sdk/server/streamableHttp.js";import{logger as d}from"../../../tools/notifiers/logger.js";import{mcpToolWorkers as M,MCP_TOOL_WORKER_KEY as q}from"../../../workers/mcp-tool-worker-pool.js";import{secretStore as v}from"../gateway-mcp/secret-store.js";import{readAuthRequiredMeta as y,stripAuthRequiredMeta as T}from"../gateway-mcp/upstream-auth.js";import{runUpstreamCredentialElicitation as b}from"../gateway-mcp/elicitation.js";import{resolveUpstreamAuthScheme as U}from"../gateway-mcp/upstream-auth-scheme.js";const D=6e4,p=new Map;function O(e,t){const r=p.get(e);if(r)return r;const s=t().finally(()=>{p.delete(e)});return p.set(e,s),s}function z(e,t,r){const s=new h({name:e,version:new Date().toISOString().slice(0,10)},{capabilities:{logging:{}},...t?{instructions:t}:{}}),i=new E(r?{sessionIdGenerator:()=>w(),onsessioninitialized:r.onInitialized,onsessionclosed:r.onClosed}:{sessionIdGenerator:void 0});return{server:s,transport:i}}async function G(e,t){return await e.connect(t),{server:e,transport:t,cleanup:async()=>{t.close()}}}function L(e,t){return r=>async(s,i)=>{d.info(`MCP tool called: ${r}`);const m=async()=>{if(!(!e.elicitationEnabled||!i.sessionId||!t?.getKv))try{const n=await t.getKv();return await v.getSecretsForSession(n,i.sessionId)}catch(n){d.warn(`gateway mcp secret store error, continuing unauthenticated: ${String(n)}`);return}},l=async()=>{const n=await m(),c={toolName:r,args:s,context:{...e,upstreamSecrets:n},extra:_(i)};return await M.exec(q,[c],{timeout:D})};let a=await l();const o=y(a);if(o.length>0&&e.elicitationEnabled&&i.sessionId&&t?.getKv){const n=i.sessionId,c=await t.getKv(),f=await U(e,o[0].api),u=await O(`${n}:${o[0].api}`,()=>b({sendRequest:(g,I,S)=>i.sendRequest(g,I,S),clientSupportsElicitation:!!t?.getClientCapabilities()?.elicitation,sessionId:n,baseUrl:e.baseUrl??"",events:o,auth:f,kv:c}));u.status==="accepted"?a=await l():u.status==="fallback"&&(a={...a,content:[...a.content,{type:"text",text:u.text}]})}return T(a)}}function _(e){return{sessionId:e.sessionId,authInfo:e.authInfo,requestId:e.requestId,requestInfo:e.requestInfo,_meta:e._meta}}function W(e){return{user:e.user,config:e.config,outdir:e.outdir,baseUrl:e.baseUrl,params:e.params,query:e.query,cookies:e.cookies,apiDescriptionsMap:e.apiDescriptionsMap,graphqlDescriptions:e.graphqlDescriptions,products:e.products,accessToken:e.accessToken,metadata:e.metadata,upstreamAuthorization:e.upstreamAuthorization,mcpMode:e.mcpMode,elicitationEnabled:e.elicitationEnabled,gatewayFetchBudgetPerExec:e.gatewayFetchBudgetPerExec,clientIp:e.clientIp,upstreamSecrets:e.upstreamSecrets}}export{G as connectMcpServer,z as createMcpServer,L as createToolDispatch,W as extractSerializableContext};
@@ -0,0 +1,15 @@
1
+ import type { McpServerInstance } from './mcp-server.js';
2
+ type SessionManagerOptions = {
3
+ maxSessions?: number;
4
+ onEvict?: (sessionId: string) => void;
5
+ };
6
+ export declare class McpSessionManager {
7
+ #private;
8
+ constructor(options?: SessionManagerOptions);
9
+ get(sessionId: string): McpServerInstance | undefined;
10
+ set(sessionId: string, instance: McpServerInstance): void;
11
+ close(sessionId: string): Promise<void>;
12
+ }
13
+ export declare const mcpSessionManager: McpSessionManager;
14
+ export {};
15
+ //# sourceMappingURL=session-manager.d.ts.map
@@ -0,0 +1 @@
1
+ import{logger as i}from"../../../tools/notifiers/logger.js";const a=1800*1e3,c=60*1e3,o=500;class r{#t=new Map;#e;#s;constructor(t={}){this.#e=t.maxSessions??o,this.#s=t.onEvict??(()=>{}),setInterval(()=>{this.#i()},c).unref?.()}get(t){const e=this.#t.get(t);if(e)return e.lastAccess=Date.now(),this.#t.delete(t),this.#t.set(t,e),e.instance}set(t,e){const s=this.#t.get(t);if(this.#t.delete(t),this.#t.set(t,{instance:e,lastAccess:Date.now()}),s&&s.instance!==e&&this.#n(t,s.instance),this.#t.size>this.#e){const n=this.#t.keys().next().value;n!==void 0&&this.close(n)}}async close(t){const e=this.#t.get(t);e&&(this.#t.delete(t),this.#s(t),await this.#n(t,e.instance))}async#n(t,e){try{await e.cleanup()}catch(s){i.warn(`Failed to clean up MCP session ${t.slice(0,8)}\u2026: ${s instanceof Error?s.message:String(s)}`)}}async#i(){const t=Date.now()-a;for(const[e,s]of this.#t)s.lastAccess<=t&&await this.close(e)}}const f=new r;export{r as McpSessionManager,f as mcpSessionManager};
@@ -6,6 +6,7 @@ import type { OpenAPIServer } from '@redocly/openapi-docs/lib/types/open-api.js'
6
6
  import type { McpErrorCodes, McpServerType } from './constants';
7
7
  import type { McpToolSchema } from '../../types';
8
8
  import type { Skill } from '../../types/plugins/skills.js';
9
+ import type { StoredSecret } from './gateway-mcp/secret-store.js';
9
10
  type ObjectValues<T> = T[keyof T];
10
11
  export type McpServerType = ObjectValues<typeof McpServerType>;
11
12
  export type McpErrorCodeTypes = ObjectValues<typeof McpErrorCodes>;
@@ -26,6 +27,9 @@ export type McpDocsStaticDataPropsConfig = {
26
27
  mcpDocsServerName: string;
27
28
  apiDescriptionsMap: Record<string, ApiDescriptionInfo>;
28
29
  graphqlDescriptions: GraphqlDescriptionInfo[];
30
+ mcpMode: McpMode;
31
+ elicitationEnabled: boolean;
32
+ gatewayFetchBudgetPerExec: number;
29
33
  };
30
34
  export type McpDocsStaticData = PageStaticData & {
31
35
  props: {
@@ -59,18 +63,6 @@ export type McpEndpoint = OpenAPIOperation & {
59
63
  'x-mcp'?: XMcpConfig;
60
64
  };
61
65
  export type McpMode = 'tools' | 'code';
62
- export type McpPluginConfig = {
63
- readonly hide: boolean;
64
- readonly docs: {
65
- readonly hide: boolean;
66
- readonly name: string;
67
- readonly ignore: readonly string[];
68
- };
69
- readonly gateway?: {
70
- readonly hide: boolean;
71
- readonly allowedHosts?: readonly string[];
72
- };
73
- };
74
66
  export type McpUserInfo = {
75
67
  email?: string;
76
68
  name?: string;
@@ -102,6 +94,11 @@ export type McpToolContext = Omit<ApiFunctionsContext, 'telemetry' | 'getKv' | k
102
94
  accessToken?: string;
103
95
  metadata?: Record<string, unknown>;
104
96
  upstreamAuthorization?: string;
97
+ mcpMode?: McpMode;
98
+ elicitationEnabled?: boolean;
99
+ gatewayFetchBudgetPerExec?: number;
100
+ clientIp?: string;
101
+ upstreamSecrets?: Record<string, StoredSecret>;
105
102
  };
106
103
  export type McpToolHandler<TArgs extends Record<string, unknown> = Record<string, unknown>> = (args: TArgs, context: McpToolContext, extra: McpToolExtra) => Promise<McpToolWorkerResponse>;
107
104
  export type McpToolIsAvailable = (context: McpToolContext) => boolean | Promise<boolean>;
@@ -1,14 +1,5 @@
1
- import type { McpUserInfo } from '../types';
2
1
  /**
3
2
  * Extract JWT token from Authorization header
4
3
  */
5
4
  export declare function extractTokenFromAuthHeader(authHeader?: string | string[]): string | null;
6
- /**
7
- * Decode and validate JWT token to get user information
8
- */
9
- export declare function getUserInfoFromToken(token: string): McpUserInfo | null;
10
- /**
11
- * Get user info from MCP request headers
12
- */
13
- export declare function getUserInfoFromHeaders(headers: Record<string, string | string[] | undefined>): McpUserInfo | null;
14
5
  //# sourceMappingURL=jwt.d.ts.map
@@ -1 +1 @@
1
- import*as t from"../../../web-server/jwt/jwt.js";function n(e){if(!e)return null;const r=Array.isArray(e)?e[0]:e;return!r||!r.startsWith("Bearer ")?null:r.replace(/^Bearer /,"")}function u(e){try{const{payload:r}=t.decode(e),o=Math.floor(Date.now()/1e3);return typeof r.exp=="number"&&r.exp<o?null:r}catch(r){return console.error("Failed to decode JWT token:",r),null}}function a(e){const r=e.authorization||e.Authorization,o=n(r);return o?u(o):null}export{n as extractTokenFromAuthHeader,a as getUserInfoFromHeaders,u as getUserInfoFromToken};
1
+ function n(r){if(!r)return null;const e=Array.isArray(r)?r[0]:r;return!e||!e.startsWith("Bearer ")?null:e.replace(/^Bearer /,"")}export{n as extractTokenFromAuthHeader};
@@ -1,7 +1,17 @@
1
1
  import type { McpMode } from '../types.js';
2
- /** Codemode - `execute` sandbox and `describeTools`. */
2
+ /**
3
+ * Codemode - `execute` sandbox and `describeTools`. Gated by the org-level `mcpMode`
4
+ * entitlement (GrowthBook `mcp-mode` flag → PLAN_GATES JWT).
5
+ *
6
+ * Read the VALUE, never `canAccessFeature('mcpMode')` — 'tools' is truthy.
7
+ * Only call these helpers where EntitlementsProvider is initialized: the build lifecycle
8
+ * and web-server routes. Request handlers and workers run in module graphs with an
9
+ * UNINITIALIZED provider copy — they must read the build-stamped `mcpMode` from static
10
+ * data / McpToolContext instead (see docs-mcp-handler / execute-mcp-tool).
11
+ */
3
12
  export declare function isMcpCodeModeEnabled(): boolean;
4
- /** The gateway capability — a guarded `fetch` in the `execute` sandbox. Requires codemode to be on. */
13
+ /** The gateway capability — a guarded `fetch` in the `execute` sandbox. Requires code mode. */
5
14
  export declare function isMcpGatewayEnabled(): boolean;
15
+ export declare function isMcpElicitationEnabled(): boolean;
6
16
  export declare function getMcpMode(): McpMode;
7
17
  //# sourceMappingURL=mode.d.ts.map
@@ -1 +1 @@
1
- import{envConfig as e}from"../../../config/env-config.js";function o(){return e.REDOCLY_EXP_MCP_CODE_MODE_ENABLED??!1}function n(){return(e.REDOCLY_EXP_MCP_GATEWAY_SERVER_ENABLED??!1)&&o()}function t(){return o()?"code":"tools"}export{t as getMcpMode,o as isMcpCodeModeEnabled,n as isMcpGatewayEnabled};
1
+ import{EntitlementsProvider as e}from"../../../entitlements/entitlements-provider.js";import{envConfig as n}from"../../../config/env-config.js";function t(){return e.instance().entitlements?.mcpMode==="code"}function o(){return!!e.instance().canAccessFeature("mcpGateway")&&t()}function i(){return(n.REDOCLY_EXP_MCP_ELICITATION_ENABLED??!0)&&o()}function a(){return t()?"code":"tools"}export{a as getMcpMode,t as isMcpCodeModeEnabled,i as isMcpElicitationEnabled,o as isMcpGatewayEnabled};
@@ -0,0 +1,8 @@
1
+ import type { McpServerType } from '../types.js';
2
+ /** CloudEvent resource attributes shared by every `mcpServer` telemetry event. */
3
+ export declare function serverAttributes(serverType: McpServerType): {
4
+ id: "docs";
5
+ object: 'mcpServer';
6
+ uri: string;
7
+ };
8
+ //# sourceMappingURL=telemetry-attributes.d.ts.map
@@ -0,0 +1 @@
1
+ function e(r){return{id:r,object:"mcpServer",uri:`urn:redocly:realm:mcp:server:${r}`}}export{e as serverAttributes};
@@ -1 +1 @@
1
- import{telemetry as d}from"../../../telemetry/index.js";import{mcpToolHandlers as w}from"../../../../client/mcp-tool-handlers-entry.js";import{getMcpMode as h}from"../utils/mode.js";import{McpServerType as i}from"../constants.js";import{reportMcpToolCalled as x,reportMcpToolError as u}from"./mcp-tool-telemetry.js";async function A(r){d.initialize();const{toolName:o,args:l,context:f,extra:t}=r,a=h(),n=performance.now();try{const e=w[o];if(!e)throw new Error(`Unknown MCP tool: ${o}`);const{default:M}=await e(),c=M[o];if(!c)throw new Error(`MCP tool module does not export a handler for "${o}". Expected \`export default { '${o}': handler }\`.`);const s=await(typeof c=="function"?c:c.execute)(l,f,t);if(!g(s))throw new Error(`MCP tool "${o}" returned an invalid result.`);const m=Math.round(performance.now()-n);if(s.isError)u({tool:o,message:s.content.map(({text:p})=>p).join(" "),mode:a,serverType:i.Docs,durationMs:m});else{const p=s.content.map(({text:y})=>y).join("").length;x({tool:o,mode:a,serverType:i.Docs,durationMs:m,outputLength:p})}return s}catch(e){throw u({tool:o,message:e instanceof Error?e.message:String(e),mode:a,serverType:i.Docs,durationMs:Math.round(performance.now()-n),stack:e instanceof Error&&e.stack||""}),e}}function g(r){return!r||typeof r!="object"?!1:Array.isArray(r.content)}async function j(r){d.initialize();const{toolName:o,context:l}=r,f=performance.now();try{const t=w[o];if(!t)return!1;const{default:a}=await t(),n=a[o];return n?typeof n=="object"&&typeof n.isAvailable=="function"?await n.isAvailable(l):!0:!1}catch(t){throw u({tool:o,message:"Failed to check if MCP tool is available: "+(t instanceof Error?t.message:String(t)),mode:h(),serverType:i.Docs,durationMs:Math.round(performance.now()-f),stack:t instanceof Error&&t.stack||""}),t}}export{A as executeMcpTool,j as isMcpToolAvailable};
1
+ import{telemetry as d}from"../../../telemetry/index.js";import{mcpToolHandlers as w}from"../../../../client/mcp-tool-handlers-entry.js";import{McpServerType as f}from"../constants.js";import{reportMcpToolCalled as y,reportMcpToolError as u}from"./mcp-tool-telemetry.js";async function b(r){d.initialize();const{toolName:o,args:c,context:i,extra:t}=r,a=i?.mcpMode??"tools",n=performance.now();try{const e=w[o];if(!e)throw new Error(`Unknown MCP tool: ${o}`);const{default:h}=await e(),l=h[o];if(!l)throw new Error(`MCP tool module does not export a handler for "${o}". Expected \`export default { '${o}': handler }\`.`);const s=await(typeof l=="function"?l:l.execute)(c,i,t);if(!x(s))throw new Error(`MCP tool "${o}" returned an invalid result.`);const m=Math.round(performance.now()-n);if(s.isError)u({tool:o,message:s.content.map(({text:p})=>p).join(" "),mode:a,serverType:f.Docs,durationMs:m});else{const p=s.content.map(({text:M})=>M).join("").length;y({tool:o,mode:a,serverType:f.Docs,durationMs:m,outputLength:p})}return s}catch(e){throw u({tool:o,message:e instanceof Error?e.message:String(e),mode:a,serverType:f.Docs,durationMs:Math.round(performance.now()-n),stack:e instanceof Error&&e.stack||""}),e}}function x(r){return!r||typeof r!="object"?!1:Array.isArray(r.content)}async function k(r){d.initialize();const{toolName:o,context:c}=r,i=performance.now();try{const t=w[o];if(!t)return!1;const{default:a}=await t(),n=a[o];return n?typeof n=="object"&&typeof n.isAvailable=="function"?await n.isAvailable(c):!0:!1}catch(t){throw u({tool:o,message:"Failed to check if MCP tool is available: "+(t instanceof Error?t.message:String(t)),mode:c?.mcpMode??"tools",serverType:f.Docs,durationMs:Math.round(performance.now()-i),stack:t instanceof Error&&t.stack||""}),t}}export{b as executeMcpTool,k as isMcpToolAvailable};
@@ -1 +1 @@
1
- import{telemetry as c}from"../../../telemetry/index.js";function l(r){return{id:r,object:"mcpServer",uri:`urn:redocly:realm:mcp:server:${r}`,server_type:r}}function s({tool:r,mode:e,serverType:o,durationMs:t,outputLength:n}){c.sendMcpToolCalledMessage([{...l(o),tool:r,mode:e,output_length:n,duration_ms:t}])}function i({tool:r,mode:e,serverType:o,durationMs:t,message:n,stack:p=""}){c.sendMcpErrorMessage([{...l(o),tool:r,message:n,stack:p,mode:e,duration_ms:t}])}export{s as reportMcpToolCalled,i as reportMcpToolError};
1
+ import{telemetry as s}from"../../../telemetry/index.js";import{serverAttributes as l}from"../utils/telemetry-attributes.js";function u({tool:r,mode:o,serverType:e,durationMs:t,outputLength:p}){s.sendMcpToolCalledMessage([{...l(e),tool:r,mode:o,output_length:p,duration_ms:t}])}function a({tool:r,mode:o,serverType:e,durationMs:t,message:p,stack:n=""}){s.sendMcpErrorMessage([{...l(e),tool:r,message:p,stack:n,mode:o,duration_ms:t}])}export{u as reportMcpToolCalled,a as reportMcpToolError};
@@ -1,5 +1,5 @@
1
- import{REDOCLY_TEAMS_RBAC as w}from"@redocly/config";import{basename as _,join as q}from"node:path";import C from"@markdoc/markdoc";import{joinSectionContent as J}from"../../../plugins/markdown/search/join-section-content.js";import{toMarkdown as G}from"../../../plugins/markdown/search/to-markdown.js";import{AstToSearchNodeTransformer as z}from"../../../plugins/markdown/search/walk-sections.js";import{createRenderTagFn as B}from"../../../plugins/markdown/search/create-render-tag-fn.js";import{canDownloadApiDefinition as v,isResourcePubliclyAccessible as V}from"../../../utils/rbac.js";import{PUBLIC_API_DEFINITIONS_FOLDER as Y}from"../../../constants/common.js";import{DEFAULT_ANONYMOUS_VISITOR_TEAM as H}from"../../../../constants/common.js";import{getLlmsTxtMdPathBySlug as I}from"../../../utils/llmstxt/get-llms-txt-md-path-by-slug.js";import{AiSearchIndexer as K}from"../ai-search-indexer.js";import{getLocaleFromRelativePath as Q}from"../../../fs/utils/get-locale-from-relative-path.js";import{extractDocumentSearchFacets as W}from"./search-facets.js";import{formatDocumentMetadata as X}from"../../search/utils.js";import{llmsTxtLink as M}from"../../search/llmstxt/index.js";import{replaceFileExtension as Z}from"../store-definition-bundles.js";const k=new Map,xe=({parser:s,options:c,info:n,tagOperations:r,relativePath:t,openapiContentItem:e,metadata:i,getSearchFacets:u,includeInLLMsTxt:a,excludeFromSearch:f})=>async(o,p,l,j)=>{if(f)return;const P=await o.getNavText?.()||_(o.fsPath),D=new K(s,c,o.baseSlug||o.slug),d=D.addItem(e);if(!d)return;const O=await l.getConfig(),b=Array.isArray(d.title)?d.title.join(" "):d.title;let g,m,y=k.get(t);if((e.type==="tag"||e.type==="section"&&e.infoDefinition)&&!y){const{all:A,publiclyAccessible:$}=ae(r.tagged,D,O),{all:S,publiclyAccessible:T}=ue(r.untagged,D,O);k.set(t,{taggedSearchDocuments:new Map(A),untaggedSearchDocuments:S,publiclyAccessibleTaggedSearchDocuments:new Map($),publiclyAccessibleUntaggedSearchDocuments:T})}y=k.get(t);const h="#";switch(e.type){case"operation":const A=D.getOperation(e);g=m=se({title:b,security:s.definition.security,document:d,version:d.version||n.version,headingLevel:h,operation:A});break;case"section":if(e.infoDefinition){y=k.get(t),m=await N({parser:s,info:n,staticData:p,relativePath:t,headingLevel:h,pageName:P,config:O}),m+=`
2
- `;for(const[S,T]of y?.publiclyAccessibleTaggedSearchDocuments?.entries()||[]){if(!T.length)continue;const U=s.definition.tags?.find(L=>L.name===S);m+=x({title:U?.["x-displayName"]||S,description:U?.description,operationSearchDocuments:T,headingLevel:`${h}#`})}const $=y?.publiclyAccessibleUntaggedSearchDocuments||[];$.length&&(m+=x({title:"Other",description:void 0,operationSearchDocuments:$,headingLevel:`${h}#`})),g=await N({parser:s,info:n,staticData:p,relativePath:t,headingLevel:h,pageName:P,config:O})}else if(e.ast){const $=new C.Ast.Node("document",{},e.ast),S=Array.from(new z({ast:$,partials:{},renderTag:B(j.markdocOptions.tags),getInnerContent:G,skipConditionals:!0}).transform());m=g=J(S)}break;case"tag":m=x({title:b,description:e.description,operationSearchDocuments:y?.publiclyAccessibleTaggedSearchDocuments.get(e.name)||[],headingLevel:h}),g=x({title:b,description:e.description,operationSearchDocuments:[],headingLevel:h});break;case"rsrc":case"prompt":case"tool":m=ce({title:b,description:e.description,name:e.name,xMcpConfig:s.definition["x-mcp"],headingLevel:h}),g=m;break}return{async getLLMsTxts(){return[{title:e.name,description:e.type==="tag"?e.description:void 0,content:m||"",slug:o.slug,fsPath:o.fsPath,includeInLLMsTxt:a}]},async getSearchDocuments(){if(e.type==="operation"||e.type==="section"&&(e.infoDefinition||e.ast)||e.type==="tag"){const A=Q(o.fsPath),$=W({...d,...i},n,u);return[{title:b,description:Array.isArray(d.text)?d.text.join(" "):d.text,content:g||"",url:d.url??o.slug,fsPath:o.fsPath,locale:A,product:o.product?.name,rbacTeams:d.rbacTeams,facets:$}]}return[]}}};async function N({parser:s,info:c,staticData:n,relativePath:r,pageName:t,headingLevel:e,config:i}){const u=X(c["x-metadata"]);let a=c.title?`${e} ${c.title}
1
+ import{REDOCLY_TEAMS_RBAC as x}from"@redocly/config";import{basename as C,join as _}from"node:path";import q from"@markdoc/markdoc";import{joinSectionContent as G}from"../../../plugins/markdown/search/join-section-content.js";import{toMarkdown as J}from"../../../plugins/markdown/search/to-markdown.js";import{AstToSearchNodeTransformer as B}from"../../../plugins/markdown/search/walk-sections.js";import{createRenderTagFn as z}from"../../../plugins/markdown/search/create-render-tag-fn.js";import{getBuildTranslateContext as v}from"../../../utils/l10n/get-build-translate-context.js";import{canDownloadApiDefinition as V,isResourcePubliclyAccessible as Y}from"../../../utils/rbac.js";import{PUBLIC_API_DEFINITIONS_FOLDER as H}from"../../../constants/common.js";import{DEFAULT_ANONYMOUS_VISITOR_TEAM as I}from"../../../../constants/common.js";import{getLlmsTxtMdPathBySlug as K}from"../../../utils/llmstxt/get-llms-txt-md-path-by-slug.js";import{AiSearchIndexer as Q}from"../ai-search-indexer.js";import{getLocaleFromRelativePath as W}from"../../../fs/utils/get-locale-from-relative-path.js";import{extractDocumentSearchFacets as X}from"./search-facets.js";import{formatDocumentMetadata as Z}from"../../search/utils.js";import{llmsTxtLink as M}from"../../search/llmstxt/index.js";import{replaceFileExtension as ee}from"../store-definition-bundles.js";const j=new Map,Ee=({parser:s,options:c,info:n,tagOperations:r,relativePath:t,openapiContentItem:e,metadata:i,getSearchFacets:u,includeInLLMsTxt:a,excludeFromSearch:f})=>async(o,p,l,O)=>{if(f)return;const U=await o.getNavText?.()||C(o.fsPath),T=new Q(s,c,o.baseSlug||o.slug),m=T.addItem(e);if(!m)return;const w=await l.getConfig(),D=Array.isArray(m.title)?m.title.join(" "):m.title;let $,d,y=j.get(t);if((e.type==="tag"||e.type==="section"&&e.infoDefinition)&&!y){const{all:A,publiclyAccessible:g}=ue(r.tagged,T,w),{all:S,publiclyAccessible:b}=le(r.untagged,T,w);j.set(t,{taggedSearchDocuments:new Map(A),untaggedSearchDocuments:S,publiclyAccessibleTaggedSearchDocuments:new Map(g),publiclyAccessibleUntaggedSearchDocuments:b})}y=j.get(t);const h="#";switch(e.type){case"operation":const A=T.getOperation(e);$=d=ce({title:D,security:s.definition.security,document:m,version:m.version||n.version,headingLevel:h,operation:A});break;case"section":if(e.infoDefinition){y=j.get(t),d=await N({parser:s,info:n,staticData:p,relativePath:t,headingLevel:h,pageName:U,config:w}),d+=`
2
+ `;for(const[S,b]of y?.publiclyAccessibleTaggedSearchDocuments?.entries()||[]){if(!b.length)continue;const k=s.definition.tags?.find(L=>L.name===S);d+=E({title:k?.["x-displayName"]||S,description:k?.description,operationSearchDocuments:b,headingLevel:`${h}#`})}const g=y?.publiclyAccessibleUntaggedSearchDocuments||[];g.length&&(d+=E({title:"Other",description:void 0,operationSearchDocuments:g,headingLevel:`${h}#`})),$=await N({parser:s,info:n,staticData:p,relativePath:t,headingLevel:h,pageName:U,config:w})}else if(e.ast){const g=new q.Ast.Node("document",{},e.ast),{locale:S,translate:b}=await v(o.slug,O.getGlobalData?.().l10n),k=Array.from(new B({ast:g,partials:{},renderTag:z(O.markdocOptions.tags,S,b),getInnerContent:J,skipConditionals:!0}).transform());d=$=G(k)}break;case"tag":d=E({title:D,description:e.description,operationSearchDocuments:y?.publiclyAccessibleTaggedSearchDocuments.get(e.name)||[],headingLevel:h}),$=E({title:D,description:e.description,operationSearchDocuments:[],headingLevel:h});break;case"rsrc":case"prompt":case"tool":d=re({title:D,description:e.description,name:e.name,xMcpConfig:s.definition["x-mcp"],headingLevel:h}),$=d;break}return{async getLLMsTxts(){return[{title:e.name,description:e.type==="tag"?e.description:void 0,content:d||"",slug:o.slug,fsPath:o.fsPath,includeInLLMsTxt:a}]},async getSearchDocuments(){if(e.type==="operation"||e.type==="section"&&(e.infoDefinition||e.ast)||e.type==="tag"){const A=W(o.fsPath),g=X({...m,...i},n,u);return[{title:D,description:Array.isArray(m.text)?m.text.join(" "):m.text,content:$||"",url:m.url??o.slug,fsPath:o.fsPath,locale:A,product:o.product?.name,rbacTeams:m.rbacTeams,facets:g}]}return[]}}};async function N({parser:s,info:c,staticData:n,relativePath:r,pageName:t,headingLevel:e,config:i}){const u=Z(c["x-metadata"]);let a=c.title?`${e} ${c.title}
3
3
 
4
4
  `:`${e} ${t}
5
5
 
@@ -12,14 +12,14 @@ import{REDOCLY_TEAMS_RBAC as w}from"@redocly/config";import{basename as _,join a
12
12
  `:"",e=`${e}#`,a+=u.length?`Metadata:
13
13
  ${u}
14
14
  `:"",a+=`
15
- `,a+=ee({parser:s,headingLevel:e}),a+=te({parser:s,headingLevel:e}),a+=await ne({info:c,staticData:n,relativePath:r,pageName:t,headingLevel:e,config:i}),a}function x({title:s="",description:c,operationSearchDocuments:n,headingLevel:r}){let t=`${r} ${s}
15
+ `,a+=ne({parser:s,headingLevel:e}),a+=se({parser:s,headingLevel:e}),a+=await te({info:c,staticData:n,relativePath:r,pageName:t,headingLevel:e,config:i}),a}function E({title:s="",description:c,operationSearchDocuments:n,headingLevel:r}){let t=`${r} ${s}
16
16
 
17
17
  `;return c&&(t+=`${c}
18
18
 
19
19
  `),n.length&&n.forEach(e=>{const i=Array.isArray(e.title)?e.title.join(" "):e.title;t+=`${r}# ${i}${e.deprecated?" (deprecated)":""}
20
20
 
21
- `,t+=` - ${M({title:`${e.httpMethod?.toUpperCase()} ${e.httpPath}`,description:Array.isArray(e.text)?e.text.join(" "):e.text,slug:I(e.url)})}`,t+=`
22
- `}),t}function ee({parser:s,headingLevel:c}){const{servers:n}=s.definition;if(n&&n.length){let r=`${c} Servers
21
+ `,t+=` - ${M({title:`${e.httpMethod?.toUpperCase()} ${e.httpPath}`,description:Array.isArray(e.text)?e.text.join(" "):e.text,slug:K(e.url)})}`,t+=`
22
+ `}),t}function ne({parser:s,headingLevel:c}){const{servers:n}=s.definition;if(n&&n.length){let r=`${c} Servers
23
23
 
24
24
  `;return n.forEach(t=>{r+=t.description?`${t.description}
25
25
  `:"",r+=`\`\`\`
@@ -31,9 +31,9 @@ ${t.url}
31
31
  `,r+=i.default?`Default: ${JSON.stringify(i.default)}
32
32
  `:"",r+=i.enum?`Enum: ${i.enum.map(u=>JSON.stringify(u)).join(", ")}
33
33
  `:""}),r+=`
34
- `)}),r}return""}async function ne({info:s,staticData:c,relativePath:n,pageName:r,headingLevel:t,config:e}){const i=q(c.props?.outdir||"",Y,Z(n,".yaml")),u=e.access?.rbac,a=e.access?.requiresLogin;if(v(i,u??{},a??!1,{isAuthenticated:!1,teams:[H]})){let f=`${t} Download OpenAPI description
34
+ `)}),r}return""}async function te({info:s,staticData:c,relativePath:n,pageName:r,headingLevel:t,config:e}){const i=_(c.props?.outdir||"",H,ee(n,".yaml")),u=e.access?.rbac,a=e.access?.requiresLogin;if(V(i,u??{},a??!1,{isAuthenticated:!1,teams:[I]})){let f=`${t} Download OpenAPI description
35
35
 
36
- `;return f+=M({title:s.title||r||"OpenAPI definition",description:void 0,slug:i}),f}return""}function te({parser:s,headingLevel:c}){if(!s.definition.components?.securitySchemes)return"";let n=`${c} Security
36
+ `;return f+=M({title:s.title||r||"OpenAPI definition",description:void 0,slug:i}),f}return""}function se({parser:s,headingLevel:c}){if(!s.definition.components?.securitySchemes)return"";let n=`${c} Security
37
37
 
38
38
  `;const{securitySchemes:r}=s.definition.components;return Object.keys(r).forEach(t=>{const e=r[t];e&&(n+=`${c}# ${t}
39
39
 
@@ -52,19 +52,19 @@ ${t.url}
52
52
  `),e.flows?.password?.scopes&&(n+=`Scopes:
53
53
  `,Object.entries(e.flows?.password?.scopes||{}).forEach(([i,u])=>{n+=`- \`${i}\`: ${u}
54
54
  `})),n+=`
55
- `)}),n}function se({title:s,security:c,document:n,version:r,headingLevel:t,operation:e}){const{text:i,httpMethod:u,httpPath:a,deprecated:f}=n,o=oe(n.parameters||[],`${t}#`),p=re(`${t}#`,n.parameters,e);let l=s?`${t} ${s}${f?" (deprecated)":""}
55
+ `)}),n}function ce({title:s,security:c,document:n,version:r,headingLevel:t,operation:e}){const{text:i,httpMethod:u,httpPath:a,deprecated:f}=n,o=ae(n.parameters||[],`${t}#`),p=ie(`${t}#`,n.parameters,e);let l=s?`${t} ${s}${f?" (deprecated)":""}
56
56
 
57
57
  `:"";return l+=i?`${i}
58
58
 
59
59
  `:"",l+=`Endpoint: ${u?.toUpperCase()} ${a}
60
60
  `,l+=r?`Version: ${r}
61
61
  `:"",l+=n.security?.length?`Security: ${n.security.join(", ")}
62
- `:c?.length?`Security: ${c.map(j=>j.id).join(", ")}
62
+ `:c?.length?`Security: ${c.map(O=>O.id).join(", ")}
63
63
  `:"",l+=`
64
64
  `,l+=o?`${o}
65
65
  `:"",l+=`
66
66
  `,l+=`${p.join(`
67
- `)}`,l}function ce({title:s,name:c,xMcpConfig:n,headingLevel:r}){const t=n?.tools.find(i=>i.name===c);if(!t)return"";let e=`${r} ${s}
67
+ `)}`,l}function re({title:s,name:c,xMcpConfig:n,headingLevel:r}){const t=n?.tools.find(i=>i.name===c);if(!t)return"";let e=`${r} ${s}
68
68
 
69
69
  `;return e+=t.description?`${t.description}
70
70
 
@@ -80,15 +80,15 @@ ${JSON.stringify(t.inputSchema,null,2)}
80
80
  ${JSON.stringify(t.outputSchema,null,2)}
81
81
  \`\`\`
82
82
 
83
- `),e}function re(s,c,n){return!c&&!n||!n?.responses?[]:n?.responses.filter(t=>!t.content?.mediaTypes[0]?.schema).map(t=>`${s} ${R(`response ${t.code} fields`)}
84
- `)}function ie(s,c,n,r){const t=JSON.stringify(s),e=r.get(t);return e?`${n}Enum: same as ${e} (${s.length} values)
83
+ `),e}function ie(s,c,n){return!c&&!n||!n?.responses?[]:n?.responses.filter(t=>!t.content?.mediaTypes[0]?.schema).map(t=>`${s} ${R(`response ${t.code} fields`)}
84
+ `)}function oe(s,c,n,r){const t=JSON.stringify(s),e=r.get(t);return e?`${n}Enum: same as ${e} (${s.length} values)
85
85
  `:(r.set(t,c),`${n}Enum: ${s.map(i=>JSON.stringify(i)).join(", ")}
86
- `)}function E(s,c,n,r){const t=`${c} `,e=s.oneOf,u=[...s.path||[],s.name].join("."),a=Array.isArray(s.description)?s.description.join(" "):s.description,f=!!e&&e.variants.length>1;let o=`${c}- \`${u}\` (${s.type}${s.required?", required":""})`;if(f&&(o+=e.discriminator?` \u2014 one of (discriminator: ${e.discriminator}):`:" \u2014 one of:"),o+=`
86
+ `)}function P(s,c,n,r){const t=`${c} `,e=s.oneOf,u=[...s.path||[],s.name].join("."),a=Array.isArray(s.description)?s.description.join(" "):s.description,f=!!e&&e.variants.length>1;let o=`${c}- \`${u}\` (${s.type}${s.required?", required":""})`;if(f&&(o+=e.discriminator?` \u2014 one of (discriminator: ${e.discriminator}):`:" \u2014 one of:"),o+=`
87
87
  `,o+=a?`${t}${a.trim()}
88
- `:"",s.enum){const p=r?`\`${u}\` in "${r}"`:`\`${u}\``;o+=ie(s.enum,p,t,n)}else s.example&&(o+=`${t}Example: ${s.example}
88
+ `:"",s.enum){const p=r?`\`${u}\` in "${r}"`:`\`${u}\``;o+=oe(s.enum,p,t,n)}else s.example&&(o+=`${t}Example: ${s.example}
89
89
  `);if(f)for(const p of e.variants){o+=`${c} - ${p.title}:
90
- `;for(const l of p.parameters)o+=E(l,`${c} `,n,p.title)}else if(e)for(const p of e.variants[0].parameters)o+=E(p,`${c} `,n);return o}function oe(s,c){const n={};for(const e of s){const i=`${e.place}${e.mediaType?` (${e.mediaType})`:""}`;n[i]=[...n[i]||[],e]}const r=new Map;return Object.entries(n).map(([e,i])=>{const u=i.map(a=>E(a," ",r));return`${c} ${R(e)}:
90
+ `;for(const l of p.parameters)o+=P(l,`${c} `,n,p.title)}else if(e)for(const p of e.variants[0].parameters)o+=P(p,`${c} `,n);return o}function ae(s,c){const n={};for(const e of s){const i=`${e.place}${e.mediaType?` (${e.mediaType})`:""}`;n[i]=[...n[i]||[],e]}const r=new Map;return Object.entries(n).map(([e,i])=>{const u=i.map(a=>P(a," ",r));return`${c} ${R(e)}:
91
91
 
92
92
  ${u.join(`
93
93
  `)}`}).join(`
94
- `)}function ae(s,c,n){const r=[],t=[];return s.forEach((e,i)=>{const u=[],a=[];e.forEach(f=>{const o=c.addItem(f);o&&(u.push(o),F({[w]:f[w],slug:o.url},n)&&a.push(o))}),r.push([i,u]),t.push([i,a])}),{all:r,publiclyAccessible:t}}function ue(s,c,n){const r=[],t=[];return s.forEach(e=>{const i=c.addItem(e);i&&(r.push(i),F({[w]:e[w],slug:i.url},n)&&t.push(i))}),{all:r,publiclyAccessible:t}}function R(s){return s.charAt(0).toUpperCase()+s.slice(1)}function F(s,c){return c.access?.requiresLogin?!0:V(s,c)}export{xe as getAiDocumentsStore};
94
+ `)}function ue(s,c,n){const r=[],t=[];return s.forEach((e,i)=>{const u=[],a=[];e.forEach(f=>{const o=c.addItem(f);o&&(u.push(o),F({[x]:f[x],slug:o.url},n)&&a.push(o))}),r.push([i,u]),t.push([i,a])}),{all:r,publiclyAccessible:t}}function le(s,c,n){const r=[],t=[];return s.forEach(e=>{const i=c.addItem(e);i&&(r.push(i),F({[x]:e[x],slug:i.url},n)&&t.push(i))}),{all:r,publiclyAccessible:t}}function R(s){return s.charAt(0).toUpperCase()+s.slice(1)}function F(s,c){return c.access?.requiresLogin?!0:Y(s,c)}export{Ee as getAiDocumentsStore};
@@ -1 +1 @@
1
- import{REDOCLY_TEAMS_RBAC as i}from"@redocly/config";import{combineUrls as p}from"@redocly/theme/core/utils";import{FEEDBACK_TYPES as c}from"../../../constants/common.js";import{normalizeRouteSlug as g}from"../../../utils/path/normalize-route-slug.js";function u(t){const{contentItems:r,sidebarItems:a,routeSlug:o,navItem:s}=t;let b=!0;for(const e of r){let n;switch(e.type){case"group":a.push({type:"separator",label:e.name,[i]:e[i]}),u({...t,contentItems:e.items,sidebarItems:a});break;case"tag":n=p(o,e.href);const m={type:"group",label:e.name,items:[],link:n,routeSlug:n,[i]:e[i]};a.push(m),u({routeSlug:o,contentItems:e.items,sidebarItems:m.items||[],navItem:s});break;case"operation":case"schema":case"rsrc":case"prompt":case"tool":e.isWebhook&&b&&(a.push({type:"separator",label:"Webhooks",variant:"secondary"}),b=!1),n=p(o,e.href),a.push({type:"link",label:e.name,httpVerb:e.type==="operation"?e.httpVerb:e.type,routeSlug:g(n),badges:e.badges,link:n,deprecated:e.deprecated,isAdditionalOperation:e.isAdditionalOperation,[i]:e[i]});break;case"section":if(e.depth===-1)continue;n=p(o,e.href);const l=e.href==="/",f={type:e.items.length?"group":"link",label:l&&s?.label?s.label:e.name,labelTranslationKey:s?.labelTranslationKey,routeSlug:n.split("#")[0]===o?o:g(n),link:n,items:[],...l&&s?.icon&&{icon:typeof s.icon=="object"?s.icon.srcSet:s.icon},...l&&s?.badges&&{badges:s.badges}};a.push(f),e.items.length&&u({routeSlug:o,contentItems:e.items,sidebarItems:f.items});break}}}function S({item:t}){return t.id===""?!0:t.type!=="group"||t.description!==""}const I=t=>(typeof t=="string"?t:t?.raw)?.replace(/\[(.*?)\][\[\(].*?[\]\)]/g,"$1")||"";function O(t){if(!t)return;let r="";const{type:a,settings:o}=t;switch(a){case c.RATING:r="Rate this section";break;case c.SENTIMENT:r="Was this section helpful?";break;case c.MOOD:r="Was this section helpful?";break;case c.COMMENT:r="Share your feedback about this section";break;case c.SCALE:r="How would you rate this section?";break}return{...t,settings:{...o,label:o?.label||r}}}function A(t){return(typeof t=="string"?t:t?.raw||"").replace(/<[^>]*>/g,"").replace(/```([\s\S]*?)```/g,"$1").replace(/`([^`]+)`/g,"$1").replace(/\*\*(.*?)\*\*/g,"$1").replace(/\*(.*?)\*/g,"$1").trim()}function E(t){if(t?.oneOf)return t;if(t?.items?.oneOf)return t.items}export{u as convertOpenAPIDocs2Sidebar,E as getOneOfSchema,O as normalizeFeedbackOptions,I as removeMarkdownLinks,S as shouldAddRoute,A as stripFormatting};
1
+ import{REDOCLY_TEAMS_RBAC as i}from"@redocly/config";import{combineUrls as l}from"@redocly/theme/core/utils";import{FEEDBACK_TYPES as c}from"../../../constants/common.js";import{normalizeRouteSlug as f}from"../../../utils/path/normalize-route-slug.js";function u(t){const{contentItems:r,sidebarItems:a,routeSlug:o,navItem:s}=t;let m=!0;for(const e of r){let n;switch(e.type){case"group":a.push({type:"separator",label:e.name,hideWhenEmpty:!0,[i]:e[i]}),u({...t,contentItems:e.items,sidebarItems:a});break;case"tag":n=l(o,e.href);const b={type:"group",label:e.name,items:[],link:n,routeSlug:n,[i]:e[i]};a.push(b),u({routeSlug:o,contentItems:e.items,sidebarItems:b.items||[],navItem:s});break;case"operation":case"schema":case"rsrc":case"prompt":case"tool":e.isWebhook&&m&&(a.push({type:"separator",label:"Webhooks",variant:"secondary",hideWhenEmpty:!0}),m=!1),n=l(o,e.href),a.push({type:"link",label:e.name,httpVerb:e.type==="operation"?e.httpVerb:e.type,routeSlug:f(n),badges:e.badges,link:n,deprecated:e.deprecated,isAdditionalOperation:e.isAdditionalOperation,[i]:e[i]});break;case"section":if(e.depth===-1)continue;n=l(o,e.href);const p=e.href==="/",d={type:e.items.length?"group":"link",label:p&&s?.label?s.label:e.name,labelTranslationKey:s?.labelTranslationKey,routeSlug:n.split("#")[0]===o?o:f(n),link:n,items:[],...p&&s?.icon&&{icon:typeof s.icon=="object"?s.icon.srcSet:s.icon},...p&&s?.badges&&{badges:s.badges}};a.push(d),e.items.length&&u({routeSlug:o,contentItems:e.items,sidebarItems:d.items});break}}}function S({item:t}){return t.id===""?!0:t.type!=="group"||t.description!==""}const I=t=>(typeof t=="string"?t:t?.raw)?.replace(/\[(.*?)\][\[\(].*?[\]\)]/g,"$1")||"";function E(t){if(!t)return;let r="";const{type:a,settings:o}=t;switch(a){case c.RATING:r="Rate this section";break;case c.SENTIMENT:r="Was this section helpful?";break;case c.MOOD:r="Was this section helpful?";break;case c.COMMENT:r="Share your feedback about this section";break;case c.SCALE:r="How would you rate this section?";break}return{...t,settings:{...o,label:o?.label||r}}}function O(t){return(typeof t=="string"?t:t?.raw||"").replace(/<[^>]*>/g,"").replace(/```([\s\S]*?)```/g,"$1").replace(/`([^`]+)`/g,"$1").replace(/\*\*(.*?)\*\*/g,"$1").replace(/\*(.*?)\*/g,"$1").trim()}function A(t){if(t?.oneOf)return t;if(t?.items?.oneOf)return t.items}export{u as convertOpenAPIDocs2Sidebar,A as getOneOfSchema,E as normalizeFeedbackOptions,I as removeMarkdownLinks,S as shouldAddRoute,O as stripFormatting};
@@ -1 +1 @@
1
- import{DEFAULT_SSO_IDP_TITLE as A}from"../../../constants/common.js";import{envConfig as d}from"../../config/env-config.js";import{telemetryTraceStep as I}from"../../../cli/telemetry/helpers/trace-step.js";import{logger as C}from"../../tools/notifiers/logger.js";const O="https://auth.cloud.redocly.com/oidc/.well-known/openid-configuration",_="https://auth.cloud.redocly.com/api/sso/oidc/introspect";async function S(T){return{id:"sso",async processContent(i){await I("build.plugin.sso",async f=>{const o=i.getConfig(),s=o.access;if(f?.setAttribute("config",`{"ssoDirect": ${JSON.stringify(o.ssoDirect||{})}}, {"sso": ${JSON.stringify(s?.sso||{})}}, {"idps": ${JSON.stringify(s?.idps||{})}}`),o.ssoDirect&&typeof o.ssoDirect=="object"&&Object.keys(o.ssoDirect).length!==0)return;const y=!!s?.sso&&(Array.isArray(s.sso)?s.sso.length>0:!0),r=!!s?.idps&&(Array.isArray(s.idps)?s.idps.length>0:!0);if(s?.sso&&Array.isArray(s.sso)&&!s.sso.length&&!r)return;const g=!!(s?.rbac&&typeof s.rbac=="object"&&Object.keys(s.rbac).length!==0),u=s?.requiresLogin;if(!g&&!u)return;y&&r&&C.error("access.sso and access.idps both set \u2014 should have been rejected by config validation",{sso:s.sso,idps:s.idps});let c=O,a=d.REDOCLY_OAUTH_USE_INTROSPECT?_:"";const e=s?.residency;if(e){const l=e.endsWith("/")?e.slice(0,-1):e;c=`${l.replace("app.","auth.")}/oidc/.well-known/openid-configuration`,a=d.REDOCLY_OAUTH_USE_INTROSPECT?`${l}/api/sso/oidc/introspect`:""}let n="AUTO";s?.sso&&(Array.isArray(s.sso)?n=s.sso.join(","):n=s.sso);let t="";s?.idps&&(Array.isArray(s.idps)?t=s.idps.join(","):t=s.idps);const p={login_hint:"{{ process.env.ORGANIZATION_ID }}",login_type:n};t&&(p.login_idps=t);const m={oidc:{title:A,type:"OIDC",configurationUrl:c,clientId:"{{ process.env.OAUTH_CLIENT_ID }}",clientSecret:"{{ process.env.OAUTH_CLIENT_SECRET }}",teamsClaimName:"https://redocly.com/sso/teams",scopes:["openid"],authorizationRequestCustomParams:p,audience:"{{ process.env.ORGANIZATION_ID }}",introspectEndpoint:a}};i.setGlobalConfig({ssoDirect:m})})},async afterRoutesCreated(i){}}}export{S as ssoPlugin};
1
+ import{DEFAULT_SSO_IDP_TITLE as A}from"../../../constants/common.js";import{envConfig as d}from"../../config/env-config.js";import{telemetryTraceStep as I}from"../../../cli/telemetry/helpers/trace-step.js";import{logger as C}from"../../tools/notifiers/logger.js";const O="https://auth.cloud.redocly.com/oidc/.well-known/openid-configuration",_="https://auth.cloud.redocly.com/api/sso/oidc/introspect";async function S(T){return{id:"sso",async processContent(i){await I("build.plugin.sso",async f=>{const o=i.getConfig(),s=o.access;if(f?.setAttribute("config",`{"ssoDirect": ${JSON.stringify(o.ssoDirect||{})}}, {"sso": ${JSON.stringify(s?.sso||{})}}, {"idps": ${JSON.stringify(s?.idps||{})}}`),o.ssoDirect&&typeof o.ssoDirect=="object"&&Object.keys(o.ssoDirect).length!==0)return;const y=!!s?.sso&&(Array.isArray(s.sso)?s.sso.length>0:!0),r=!!s?.idps&&(Array.isArray(s.idps)?s.idps.length>0:!0);if(s?.sso&&Array.isArray(s.sso)&&!s.sso.length&&!r)return;const g=!!(s?.rbac&&typeof s.rbac=="object"&&Object.keys(s.rbac).length!==0),u=s?.requiresLogin;if(!g&&!u)return;y&&r&&C.error("access.sso and access.idps both set \u2014 should have been rejected by config validation",{sso:s.sso,idps:s.idps});let c=O,a=d.REDOCLY_OAUTH_USE_INTROSPECT?_:"";const e=s?.residency;if(e){const l=e.endsWith("/")?e.slice(0,-1):e;c=`${l.replace("app.","auth.")}/oidc/.well-known/openid-configuration`,a=d.REDOCLY_OAUTH_USE_INTROSPECT?`${l}/api/sso/oidc/introspect`:""}let n="AUTO";s?.sso&&(Array.isArray(s.sso)?n=s.sso.join(","):n=s.sso);let t="";s?.idps&&(Array.isArray(s.idps)?t=s.idps.join(","):t=s.idps);const p={login_hint:"{{ process.env.ORGANIZATION_ID }}",login_type:n};t&&(p.login_idps=t);const m={oidc:{title:A,type:"OIDC",configurationUrl:c,clientId:"{{ process.env.OAUTH_CLIENT_ID }}",clientSecret:"{{ process.env.OAUTH_CLIENT_SECRET }}",teamsClaimName:"https://redocly.com/sso/teams",scopes:["openid","offline"],authorizationRequestCustomParams:p,audience:"{{ process.env.ORGANIZATION_ID }}",introspectEndpoint:a}};i.setGlobalConfig({ssoDirect:m})})},async afterRoutesCreated(i){}}}export{S as ssoPlugin};
@@ -6,8 +6,9 @@ export type SandboxResult = {
6
6
  export type ExecutionBudget = {
7
7
  /**
8
8
  * Run `work()` as a host call: its latency is exempt from the compute budget (`timeoutMs`).
9
- * While the call is in flight the idle timer is paused, and the guest gets a fresh CPU
10
- * deadline when it settles — so time spent off in the host isn't charged as guest compute.
9
+ * While the call is in flight the idle timer is paused and the remaining compute budget is
10
+ * frozen, resuming where it stopped when the call settles — so time spent off in the host
11
+ * isn't charged as guest compute and the budget is never refreshed per call.
11
12
  */
12
13
  hostCall<T>(work: () => Promise<T>): Promise<T>;
13
14
  /** Rejects when a wall-clock deadline fires */
@@ -1,9 +1,10 @@
1
1
  import type { ExecutionBudget } from '../types.js';
2
2
  import type { QuickJSContext } from 'quickjs-emscripten-core';
3
3
  /**
4
- * Time-bounds a single sandbox run. Two deadlines — a refreshable per-stretch compute budget
5
- * (`timeoutMs`) and a fixed whole-run ceiling (`maxLifetimeMs`) are each enforced two ways,
6
- * because the guest is only ever in one of two states and each enforcer reaches only one:
4
+ * Time-bounds a single sandbox run. Two deadlines — a drawn-down compute budget (`timeoutMs`,
5
+ * spent only while the guest runs bytecode and frozen across host-call latency) and a fixed
6
+ * whole-run ceiling (`maxLifetimeMs`) are each enforced two ways, because the guest is only
7
+ * ever in one of two states and each enforcer reaches only one:
7
8
  * - while the guest RUNS bytecode → the interrupt handler
8
9
  * - while the guest is PARKED on an `await` → a wall-clock `setTimeout`
9
10
  */
@@ -1 +1 @@
1
- function f(a,t,i){const s=Date.now()+i;let c=Date.now()+t,l=()=>{};const d=new Promise((e,o)=>{l=r=>o(new Error(r))});let n;const u=()=>{clearTimeout(n),n=setTimeout(()=>l(`Execution timed out after ${t}ms`),t)};a.runtime.setInterruptHandler(()=>{const e=Date.now();return e>c||e>s}),u();const T=setTimeout(()=>l(`Exceeded the maximum lifetime of ${i}ms`),i);let m=0;return{hostCall:e=>{m++,clearTimeout(n);const o=()=>{a.alive&&(c=Date.now()+t,--m===0&&u())},r=e();return r.then(o,o),r},aborted:d,dispose(){clearTimeout(n),clearTimeout(T)}}}export{f as createExecutionBudget};
1
+ function f(c,t,i){const d=Date.now()+i;let l=Date.now()+t,u=t,a=()=>{};const T=new Promise((e,o)=>{a=r=>o(new Error(r))});let n;const m=()=>{clearTimeout(n),n=setTimeout(()=>a(`Execution timed out after ${t}ms`),t)};c.runtime.setInterruptHandler(()=>{const e=Date.now();return e>l||e>d}),m();const w=setTimeout(()=>a(`Exceeded the maximum lifetime of ${i}ms`),i);let s=0;return{hostCall:e=>{u=l-Date.now(),s++,clearTimeout(n);const o=()=>{c.alive&&(l=Date.now()+u,--s===0&&m())},r=e();return r.then(o,o),r},aborted:T,dispose(){clearTimeout(n),clearTimeout(w)}}}export{f as createExecutionBudget};
@@ -2,7 +2,7 @@ import type { Node } from '@markdoc/markdoc';
2
2
  import type { PageStaticData, REDOCLY_ROUTE_RBAC, REDOCLY_TEAMS_RBAC, RbacScopeItems } from '@redocly/config';
3
3
  import type { PluginDefaultOptions, PageRouteDetails, LifecycleContext, AfterRoutesCreatedActions, MarkdownParseInput } from '../../types';
4
4
  import type { LINK_ORIGINAL_ATTR_NAME } from '../../constants/common';
5
- import type { RenderForLlmsContext } from '@redocly/theme/markdoc/tags/types';
5
+ import type { RenderForLlmsRenderContext } from '@redocly/theme/markdoc/tags/types';
6
6
  export type RoutesInfoActions = {
7
7
  outdir: string;
8
8
  getRouteByFsPath: (relativePath: string) => PageRouteDetails | undefined;
@@ -42,5 +42,5 @@ export type ParseMarkdocOpts = {
42
42
  deps?: MarkdocDeps;
43
43
  resource?: string;
44
44
  };
45
- export type RenderTagFn = (node: Node, context: RenderForLlmsContext) => string | undefined;
45
+ export type RenderTagFn = (node: Node, context: RenderForLlmsRenderContext) => string | undefined;
46
46
  //# sourceMappingURL=markdown.d.ts.map
@@ -0,0 +1,5 @@
1
+ export declare const IV_LENGTH_BYTES = 12;
2
+ export declare const AUTH_TAG_LENGTH_BYTES = 16;
3
+ /** Marks a JWT claim value as encrypted; unprefixed values are legacy plaintext. */
4
+ export declare const ENCRYPTED_CLAIM_PREFIX = "enc.v1.";
5
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ const E=12,T=16,_="enc.v1.";export{T as AUTH_TAG_LENGTH_BYTES,_ as ENCRYPTED_CLAIM_PREFIX,E as IV_LENGTH_BYTES};
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Decrypts a payload produced by `encryptAesGcm`.
3
+ * Throws when the payload is tampered with or the secret is wrong.
4
+ */
5
+ export declare function decryptAesGcm(payload: string, secret: string): string;
6
+ //# sourceMappingURL=decrypt-aes-gcm.d.ts.map
@@ -0,0 +1 @@
1
+ import{createDecipheriv as u}from"node:crypto";import{AUTH_TAG_LENGTH_BYTES as e,IV_LENGTH_BYTES as a}from"./constants.js";import{deriveKey as f}from"./derive-key.js";function h(o,c){const r=Buffer.from(o,"base64url"),n=r.subarray(0,a),i=r.subarray(r.length-e),s=r.subarray(a,r.length-e),t=u("aes-256-gcm",f(c),n);return t.setAuthTag(i),Buffer.concat([t.update(s),t.final()]).toString("utf8")}export{h as decryptAesGcm};
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Returns the decrypted claim value, the value itself when it is legacy
3
+ * plaintext, or undefined when it is missing or fails to decrypt.
4
+ */
5
+ export declare function decryptClaimValue(value: unknown, secret: string): string | undefined;
6
+ //# sourceMappingURL=decrypt-claim-value.d.ts.map
@@ -0,0 +1 @@
1
+ import{ENCRYPTED_CLAIM_PREFIX as t}from"./constants.js";import{decryptAesGcm as n}from"./decrypt-aes-gcm.js";function c(r,e){if(!(typeof r!="string"||!r)){if(!r.startsWith(t))return r;try{return n(r.slice(t.length),e)}catch{return}}}export{c as decryptClaimValue};
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Derives the AES-256-GCM key for a secret via HKDF-SHA256, cached per secret.
3
+ */
4
+ export declare function deriveKey(secret: string): Buffer;
5
+ //# sourceMappingURL=derive-key.d.ts.map
@@ -0,0 +1 @@
1
+ import{hkdfSync as t}from"node:crypto";const r=32,c="redocly-portal",f="claim-encryption",n=new Map;function y(o){let e=n.get(o);return e||(e=Buffer.from(t("sha256",o,c,f,r)),n.set(o,e)),e}export{y as deriveKey};
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Encrypts with AES-256-GCM using a key derived from the secret.
3
+ * Output layout: base64url(iv | ciphertext | authTag).
4
+ */
5
+ export declare function encryptAesGcm(plaintext: string, secret: string): string;
6
+ //# sourceMappingURL=encrypt-aes-gcm.d.ts.map
@@ -0,0 +1 @@
1
+ import{createCipheriv as i,randomBytes as n}from"node:crypto";import{IV_LENGTH_BYTES as f}from"./constants.js";import{deriveKey as a}from"./derive-key.js";function s(r,o){const e=n(f),t=i("aes-256-gcm",a(o),e),c=Buffer.concat([t.update(r,"utf8"),t.final()]);return Buffer.concat([e,c,t.getAuthTag()]).toString("base64url")}export{s as encryptAesGcm};
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Encrypts a JWT claim value and prefixes it so `decryptClaimValue` can tell
3
+ * encrypted values apart from legacy plaintext ones.
4
+ */
5
+ export declare function encryptClaimValue(value: string, secret: string): string;
6
+ //# sourceMappingURL=encrypt-claim-value.d.ts.map
@@ -0,0 +1 @@
1
+ import{ENCRYPTED_CLAIM_PREFIX as e}from"./constants.js";import{encryptAesGcm as m}from"./encrypt-aes-gcm.js";function p(r,t){return`${e}${m(r,t)}`}export{p as encryptClaimValue};
@@ -0,0 +1,7 @@
1
+ import type { TFunction } from '@redocly/theme/core/types';
2
+ import type { GlobalData } from '../../../types/index.js';
3
+ export declare function getBuildTranslateContext(slug: string, l10n: GlobalData['l10n']): Promise<{
4
+ locale: string;
5
+ translate: TFunction;
6
+ }>;
7
+ //# sourceMappingURL=get-build-translate-context.d.ts.map
@@ -0,0 +1 @@
1
+ import i from"i18next";import{getLocaleFromPathname as s}from"@redocly/theme/core/utils";import{DEFAULT_LOCALE_PLACEHOLDER as c}from"../../../constants/common.js";import{buildI18nConfig as l}from"../../../utils/l10n/build-i18n-config.js";import{createTranslate as f}from"../../../utils/l10n/create-translate.js";let o;function m(t){if(!o||o.l10n!==t){const e=(async()=>{const a=i.createInstance(),n=t?.defaultLocale||c;return await a.init(await l(t,n)),a})();o={l10n:t,instance:e}}return o.instance}async function x(t,e){const a=e?.defaultLocale||c,n=s(t,a,e?.locales??[]),r=await m(e);return{locale:n,translate:f(r.getFixedT(n))}}export{x as getBuildTranslateContext};
@@ -11,6 +11,7 @@ export declare function getScopeItemsForResource(rbacConfig: RbacConfig | undefi
11
11
  fsPath?: string;
12
12
  slug?: string;
13
13
  }): RbacScopeItems;
14
+ export declare function hasScopeAccess(scopeItems: RbacScopeItems, teams: string[], email?: string): boolean;
14
15
  export declare function canAccessFeature(feature: RbacFeatures, auth: AuthDetails, rbacConfig?: RbacConfig, requiresLogin?: boolean): boolean;
15
16
  export declare function isResourcePubliclyAccessible(resource: {
16
17
  slug: string;
@@ -140,6 +141,9 @@ export declare const normalizeRbacConfig: (rbacConfig: RbacConfig) => {
140
141
  aiSearch?: {
141
142
  [x: string]: string;
142
143
  } | undefined;
144
+ mcp?: {
145
+ [x: string]: string;
146
+ } | undefined;
143
147
  } | undefined;
144
148
  reunite?: {
145
149
  [x: string]: string;