@redocly/reef 0.132.0-next.5 → 0.132.0-next.7

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 (126) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/dist/cli/telemetry/index.js +1 -1
  3. package/dist/client/App.js +1 -1
  4. package/dist/client/app/CircularProgress.js +8 -8
  5. package/dist/client/app/hooks/utils/match-banner-target.d.ts +23 -1
  6. package/dist/client/app/hooks/utils/match-banner-target.js +1 -1
  7. package/dist/client/mcp-tool-handlers-entry.d.ts +3 -0
  8. package/dist/client/mcp-tool-handlers-entry.js +1 -0
  9. package/dist/client/templates/asyncapi-docs/helpers.d.ts +1 -1
  10. package/dist/client/types/ai-search.d.ts +5 -3
  11. package/dist/constants/l10n/langs/ar.js +1 -1
  12. package/dist/constants/l10n/langs/de.js +1 -1
  13. package/dist/constants/l10n/langs/en.js +1 -1
  14. package/dist/constants/l10n/langs/es.js +1 -1
  15. package/dist/constants/l10n/langs/fr.js +1 -1
  16. package/dist/constants/l10n/langs/hi.js +1 -1
  17. package/dist/constants/l10n/langs/it.js +1 -1
  18. package/dist/constants/l10n/langs/ja.js +1 -1
  19. package/dist/constants/l10n/langs/ko.js +1 -1
  20. package/dist/constants/l10n/langs/pl.js +1 -1
  21. package/dist/constants/l10n/langs/pt-BR.js +1 -1
  22. package/dist/constants/l10n/langs/pt.js +1 -1
  23. package/dist/constants/l10n/langs/ru.js +1 -1
  24. package/dist/constants/l10n/langs/uk.js +1 -1
  25. package/dist/constants/l10n/langs/zh.js +1 -1
  26. package/dist/markdoc/nodes/fence/index.js +1 -1
  27. package/dist/markdoc/nodes/index.d.ts +1 -1
  28. package/dist/markdoc/nodes/index.js +1 -1
  29. package/dist/server/api-routes/run-api-routes-worker.js +1 -1
  30. package/dist/server/config/env-schema.d.ts +6 -3
  31. package/dist/server/config/env-schemas/api-urls.d.ts +3 -3
  32. package/dist/server/config/env-schemas/api-urls.js +1 -1
  33. package/dist/server/config/env-schemas/auth.d.ts +3 -0
  34. package/dist/server/config/env-schemas/auth.js +1 -1
  35. package/dist/server/esbuild/esbuild.js +3 -3
  36. package/dist/server/esbuild/plugins/codegen/index.d.ts +1 -0
  37. package/dist/server/esbuild/plugins/codegen/index.js +7 -3
  38. package/dist/server/esbuild/plugins/mcp-tool-handlers-resolver.d.ts +7 -0
  39. package/dist/server/esbuild/plugins/mcp-tool-handlers-resolver.js +1 -0
  40. package/dist/server/plugins/catalog-entities/plugin.js +1 -1
  41. package/dist/server/plugins/config-parser/index.js +1 -1
  42. package/dist/server/plugins/config-parser/loaders/content-slugs-loader.js +1 -1
  43. package/dist/server/plugins/default-theme/resolve-products-config.js +1 -1
  44. package/dist/server/plugins/dev-onboarding/api/adapter-factory.d.ts +10 -3
  45. package/dist/server/plugins/dev-onboarding/api/adapter-factory.js +1 -1
  46. package/dist/server/plugins/dev-onboarding/api/adapters/apigee/adapter.d.ts +5 -4
  47. package/dist/server/plugins/dev-onboarding/api/adapters/apigee/adapter.js +4 -4
  48. package/dist/server/plugins/dev-onboarding/api/adapters/gravitee/client.d.ts +3 -3
  49. package/dist/server/plugins/dev-onboarding/api/adapters/gravitee/client.js +1 -1
  50. package/dist/server/plugins/dev-onboarding/api/middlewares/integrations.d.ts +3 -2
  51. package/dist/server/plugins/dev-onboarding/api/middlewares/integrations.js +1 -1
  52. package/dist/server/plugins/dev-onboarding/api/routes/index.js +1 -1
  53. package/dist/server/plugins/dev-onboarding/api/types.d.ts +8 -0
  54. package/dist/server/plugins/dev-onboarding/template/components/ApiLogsActions.js +5 -5
  55. package/dist/server/plugins/dev-onboarding/template/components/DialogStyledComponents.js +1 -1
  56. package/dist/server/plugins/dev-onboarding/template/components/MultiSelect.js +1 -1
  57. package/dist/server/plugins/dev-onboarding/template/components/TextField.js +3 -3
  58. package/dist/server/plugins/enforce-login/index.js +1 -1
  59. package/dist/server/plugins/lifecycle.js +2 -2
  60. package/dist/server/plugins/markdown/attribute-resolvers/index.js +1 -1
  61. package/dist/server/plugins/markdown/attribute-resolvers/resolve-diagram-from-file.d.ts +4 -0
  62. package/dist/server/plugins/markdown/attribute-resolvers/resolve-diagram-from-file.js +1 -0
  63. package/dist/server/plugins/markdown/attribute-resolvers/resolve-native-md-link.js +1 -1
  64. package/dist/server/plugins/markdown/markdoc/markdoc-options.d.ts +1 -1
  65. package/dist/server/plugins/markdown/markdoc/plugins/render-diagrams.d.ts +16 -0
  66. package/dist/server/plugins/markdown/markdoc/plugins/render-diagrams.js +1 -0
  67. package/dist/server/plugins/markdown/runtime-transform.js +1 -1
  68. package/dist/server/plugins/markdown/search/to-markdown.js +24 -16
  69. package/dist/server/plugins/markdown/search/walk-sections.js +1 -1
  70. package/dist/server/plugins/mcp/docs-mcp/tool-schemas.d.ts +7 -0
  71. package/dist/server/plugins/mcp/docs-mcp/tool-schemas.js +1 -0
  72. package/dist/server/plugins/mcp/docs-mcp/tools/get-endpoint-info.d.ts +5 -9
  73. package/dist/server/plugins/mcp/docs-mcp/tools/get-endpoint-info.js +1 -1
  74. package/dist/server/plugins/mcp/docs-mcp/tools/get-endpoints.d.ts +5 -9
  75. package/dist/server/plugins/mcp/docs-mcp/tools/get-endpoints.js +1 -1
  76. package/dist/server/plugins/mcp/docs-mcp/tools/get-full-api-description.d.ts +5 -9
  77. package/dist/server/plugins/mcp/docs-mcp/tools/get-full-api-description.js +1 -1
  78. package/dist/server/plugins/mcp/docs-mcp/tools/get-security-schemes.d.ts +5 -9
  79. package/dist/server/plugins/mcp/docs-mcp/tools/get-security-schemes.js +1 -1
  80. package/dist/server/plugins/mcp/docs-mcp/tools/helpers/load-api-description.d.ts +4 -0
  81. package/dist/server/plugins/mcp/docs-mcp/tools/helpers/load-api-description.js +1 -0
  82. package/dist/server/plugins/mcp/docs-mcp/tools/index.d.ts +10 -7
  83. package/dist/server/plugins/mcp/docs-mcp/tools/index.js +1 -1
  84. package/dist/server/plugins/mcp/docs-mcp/tools/list-apis.d.ts +5 -9
  85. package/dist/server/plugins/mcp/docs-mcp/tools/list-apis.js +1 -1
  86. package/dist/server/plugins/mcp/docs-mcp/tools/search.d.ts +5 -10
  87. package/dist/server/plugins/mcp/docs-mcp/tools/search.js +3 -3
  88. package/dist/server/plugins/mcp/docs-mcp/tools/utils.d.ts +6 -3
  89. package/dist/server/plugins/mcp/docs-mcp/tools/utils.js +6 -6
  90. package/dist/server/plugins/mcp/docs-mcp/tools/whoami.d.ts +5 -9
  91. package/dist/server/plugins/mcp/docs-mcp/tools/whoami.js +1 -1
  92. package/dist/server/plugins/mcp/handlers/docs-mcp-handler.js +1 -1
  93. package/dist/server/plugins/mcp/handlers/handle-mcp-request.js +1 -1
  94. package/dist/server/plugins/mcp/index.js +1 -1
  95. package/dist/server/plugins/mcp/servers/docs-server.d.ts +13 -22
  96. package/dist/server/plugins/mcp/servers/docs-server.js +1 -1
  97. package/dist/server/plugins/mcp/types.d.ts +24 -56
  98. package/dist/server/plugins/mcp/workers/execute-mcp-tool.d.ts +2 -2
  99. package/dist/server/plugins/mcp/workers/execute-mcp-tool.js +1 -1
  100. package/dist/server/plugins/openapi-docs/index.js +1 -1
  101. package/dist/server/plugins/openapi-docs/search-indexer.js +1 -1
  102. package/dist/server/store.d.ts +5 -2
  103. package/dist/server/store.js +1 -1
  104. package/dist/server/telemetry/index.js +1 -1
  105. package/dist/server/types/plugins/common.d.ts +15 -2
  106. package/dist/server/types/redirects.d.ts +6 -0
  107. package/dist/server/utils/rbac.js +1 -1
  108. package/dist/server/utils/redirects/find-redirect.d.ts +8 -31
  109. package/dist/server/utils/redirects/find-redirect.js +1 -1
  110. package/dist/server/utils/redirects/follow-redirect-chain.d.ts +9 -0
  111. package/dist/server/utils/redirects/follow-redirect-chain.js +1 -0
  112. package/dist/server/utils/redirects/validate-redirects.d.ts +8 -0
  113. package/dist/server/utils/redirects/validate-redirects.js +1 -0
  114. package/dist/server/web-server/routes/otel/otel.js +1 -1
  115. package/dist/server/workers/types.d.ts +2 -2
  116. package/dist/server/workers/worker-pool.js +1 -1
  117. package/dist/types/global-data.d.ts +7 -2
  118. package/package.json +10 -10
  119. package/dist/server/plugins/markdown/markdoc/plugins/render-mermaid.d.ts +0 -4
  120. package/dist/server/plugins/markdown/markdoc/plugins/render-mermaid.js +0 -1
  121. package/dist/server/plugins/mcp/docs-mcp/tools/docs-mcp-tool.d.ts +0 -55
  122. package/dist/server/plugins/mcp/docs-mcp/tools/docs-mcp-tool.js +0 -1
  123. package/dist/server/plugins/mcp/handlers/mcp-request-handler.d.ts +0 -11
  124. package/dist/server/plugins/mcp/handlers/mcp-request-handler.js +0 -1
  125. package/dist/server/plugins/mcp/servers/base-server.d.ts +0 -17
  126. package/dist/server/plugins/mcp/servers/base-server.js +0 -1
@@ -1 +1 @@
1
- import b from"@markdoc/markdoc";import{getPathnameForLocale as A}from"@redocly/theme/core/utils";import{DEFAULT_LOCALE_PLACEHOLDER as f}from"../constants/common.js";import{DEFAULT_TITLE as C}from"./constants/common.js";import{GATED_MARKDOC_TAGS as D}from"./constants/entitlements.js";import{isObject as O}from"../utils/guards/is-object.js";import{mapObject as T}from"../utils/object/map-object.js";import{getValueDeep as S}from"../utils/object/get-value-deep.js";import{removeTrailingSlash as M}from"../utils/url/remove-trailing-slash.js";import{normalizeRouteSlug as p}from"../utils/path/normalize-route-slug.js";import{isLocalLink as L}from"../utils/path/is-local-link.js";import{reporter as w}from"./tools/notifiers/reporter.js";import{logger as g}from"./tools/notifiers/logger.js";import{sha1 as k}from"./utils/crypto/sha1.js";import{writeEnvVariable as _}from"./utils/envs/write-env-variable.js";import{envConfig as F}from"./config/env-config.js";import{KvService as G}from"./persistence/kv/services/kv-service.js";import{writeSharedData as B}from"./utils/index.js";import{renderComponents as I}from"./ssr/render.js";import{readStaticData as N,writeStaticData as V}from"./utils/static-data.js";import{parseAndResolveMarkdoc as j}from"./plugins/markdown/compiler.js";import{getMarkdocOptions as H}from"./plugins/markdown/markdoc/markdoc-options.js";import{EntitlementsProvider as y}from"./entitlements/entitlements-provider.js";import{isL10nPath as K}from"./fs/utils/is-l10n-path.js";import{resolveMetadataGlobs as U}from"./utils/globs.js";import{replaceEnvVariablesDeep as J}from"./utils/envs/replace-env-variables-deep.js";import{findRedirect as q}from"./utils/redirects/find-redirect.js";import{addWildcardRedirectToTree as x}from"./utils/redirects/add-wildcard-redirect-to-tree.js";import{telemetryTraceStep as $}from"../cli/telemetry/helpers/trace-step.js";const R={routesBySlug:"map",apiRoutes:"object",middleware:"object",routesByFsPath:"map",routesSharedData:"map",globalData:"object",config:"object",ssr:"object",searchFacets:"map",routesPartials:"map"},m="markdown/partials",W="markdown/partials-deps",v="PLAN_GATES",z=["OAUTH_CLIENT_ID","OAUTH_CLIENT_SECRET","ORGANIZATION_SLUG","ORGANIZATION_ID","ORG_ID"],At="userDefinedApiFunctions";class E{routesBySlug=new Map;replacedEnvVars={};unsetEnvVars=new Set;lifecycleContext;newRoutes=[];#t={};routesByFsPath=new Map;apiRoutes=[];middleware=[];routesSharedData=new Map;sharedDataDeps=new Map;sharedDataMarkdocComponents=new Map;routesDynamicComponents=new Map;routesPartials=new Map;ssr={preBodyTags:[],postBodyTags:[],headTags:[]};searchFacets=new Map;searchEngine;templates=new Map;browserPlugins=new Set;apiRoutesRequestHandlers=new Map;serverPropsGetters=new Map;pagePropsGetters=new Map;listeners=new Map;globalData={};#s=void 0;config={configFilePath:"",redirects:{},wildcardRedirectsTree:{},access:{rbac:{},requiresLogin:!1},directoryPermissions:{},devLogin:!1,ssoDirect:{}};#r;serverMode;serverOutDir;outdir;buildRevision=0;hasSitemap=!1;compilationErrors=[];#a;userCodeReady;#o=Promise.resolve();#i;#n=Promise.resolve();#c;#e=new Map;constructor({outdir:t,contentDir:e,serverMode:s=!1,serverOutDir:a}){this.#r=e,this.outdir=t,this.serverMode=s,this.serverOutDir=a,this.userCodeReady=new Promise(r=>{this.#a=r})}on(t,e){const s=this.listeners.get(t);s?s.add(e):this.listeners.set(t,new Set([e]))}queueEvent=(t,e,...s)=>{this.#e.set(t+String(e),[t,e,...s])};runListeners=(t,e,...s)=>{for(const a of this.listeners.get(t)||new Set)e?a(e,...s):a(...s)};startPluginsRun(){this.clear(),this.#o=new Promise(t=>{this.#i=t})}waitForPluginsLifecycle(){return Promise.all([this.#o,this.#n])}finishPluginsRun(){this.#i?.();for(const t of this.#e.values())this.runListeners(...t);this.#e.clear()}startEsbuildRun(){this.#n=new Promise(t=>{this.#c=t})}finishEsbuildRun(){this.#c?.()}get contentDir(){if(this.serverMode)throw new Error("contentDir should not be used in server mode");return this.#r}markUserCodeReady(){this.#a?.(!0)}async reloadMarkdocOptions(){await $("build.reload_markdoc_options",async()=>{const t=y.instance(),e=await H(this.serverOutDir),s=Object.fromEntries(Object.entries(e.tags).filter(([a])=>D[a]!=null?t.canAccessFeature(D[a]):!0));this.#s={...e,tags:s}})}get markdocOptions(){return{...this.#s,partials:this.getGlobalConfig(m),themeConfig:this.config.markdown}}setGlobalData=t=>{const e=this.globalData,s={...this.globalData,...t};this.globalData=s,JSON.stringify(s)!==JSON.stringify(e)&&this.queueEvent("global-data-updated",void 0,s)};getGlobalData=()=>this.globalData;getKv=async()=>G.getInstance({baseDbDir:this.serverOutDir});parseMarkdoc=async({input:t,context:e,deps:s,resource:a})=>{const{data:{info:r,ast:c},compoundHash:l}=await j(t,this.markdocOptions,{actions:this,context:e},a);for(const i of r.sharedDataDeps||[]){for(const o of s?.routeSlugs||[])this.addRouteSharedData(o,i,i);for(const o of s?.sharedDataIds||[]){const n=this.sharedDataDeps.get(o)||new Set;n.add(i),this.sharedDataDeps.set(o,n)}}for(const i of r.dynamicMarkdocComponents||[]){for(const o of s?.routeSlugs||[]){const n=this.routesDynamicComponents.get(o)||new Set;n.add(i),this.routesDynamicComponents.set(o,n)}for(const o of s?.sharedDataIds||[]){const n=this.sharedDataMarkdocComponents.get(o)||new Set;n.add(i),this.sharedDataMarkdocComponents.set(o,n)}}if(s?.routeSlugs&&r.partials?.length)for(const i of s.routeSlugs){const o=this.routesPartials.get(i)||[];for(const n of r.partials)o.includes(n)||o.push(n);this.routesPartials.set(i,o)}return{info:r,ast:c,compoundHash:l}};async loadOpenApiDefinitions(t){return(await t.cache.load(".","load-oas-docs")).data}async loadAsyncApiDefinitions(t){return(await t.cache.load(".","asyncapi-docs")).data}setSearchEngine(t){this.searchEngine=t}setSearchFacets=t=>{this.searchFacets=t};setGlobalConfig=t=>{const e=Object.keys(t);for(const c of e)for(const l in this.replacedEnvVars)if(l===c||l.startsWith(`${c}:`)){const i=l.split(":"),{error:o,value:n}=S(t,i);(o||n!==this.replacedEnvVars[l].replaced)&&delete this.replacedEnvVars[l]}const{resolvedObj:s,unsetEnvVars:a,replacedValues:r}=J(t);for(const c of a)this.unsetEnvVars.add(c);Object.assign(this.replacedEnvVars,r),Object.assign(this.config,s)};getConfig=()=>this.config;getGlobalConfig=t=>this.config[t];getSearchFacets=()=>this.searchFacets;addRedirect=(t,e)=>{if(!y.instance().canAccessFeature("redirects")&&t!=="/")return;this.config.redirects||(this.config.redirects={});const r=p(t).toLowerCase();this.config.redirects[r]=e,r.endsWith("*")&&x(this.config.wildcardRedirectsTree,r)};getRedirect=t=>{const e=p(t).toLowerCase();return q(e,this.config.redirects,this.config.wildcardRedirectsTree)};createSharedData=async(t,e,s)=>{if(s&&this.#t[t]===s)return t;const a=JSON.stringify(e),r=s??k(a);return this.#t[t]===r||(this.#t[t]=r,await B(t,a,this.outdir),this.queueEvent("shared-data-updated",t)),t};addRouteSharedData=(t,e,s)=>{const a=M(t),r=this.routesSharedData.get(a)||{};r[e]=s,this.routesSharedData.set(a,r),g.verbose(`Adding shared data to ${t}, ${e}, ${s}`)};getRouteSharedDataByFsPath=t=>{const e=this.routesByFsPath.get(t);return e?this.routesSharedData.get(e)||{}:{}};getPartialsForRoute=t=>{const e=this.getGlobalConfig(m)||{},s=this.routesPartials.get(t);if(!s||s.length===0)return{};const a=this.getGlobalConfig(W)||{},r=new Set(s),c=Array.from(s);for(let i=0;i<c.length;i++){const o=c[i],n=a[o]?.partials??[];for(const d of n)r.has(d)||(r.add(d),c.push(d))}const l={};for(const i of r)e[i]&&(l[i]=e[i]);return l};addRoute=t=>{const s={...U(t.fsPath,this.config.metadataGlobs),...t.metadata||{}};this.newRoutes.push({...t,metadata:s}),g.verbose("Created route %s",t.slug)};addRouteSharedDataToAllLocales=(t,e,s)=>{const a=[f,...this.lifecycleContext?.fs.localeFolders||[]].map(r=>({code:r,name:r}));for(const r of a){const c=A(t,f,r.code,a);this.addRouteSharedData(c,e,s)}};addApiRoute=t=>{this.apiRoutes.push(t),g.verbose("Created API route %s",t.slug)};addMiddleware=t=>{this.middleware.push(t),g.verbose("Created middleware %s",t.id)};getRouteByFsPath=t=>{const e=this.routesByFsPath.get(t);return e?this.getRouteBySlug(e):void 0};getRouteBySlug=(t,e={})=>{const{followRedirect:s=!0}=e,a=this.getRedirect(t);return s&&a?this.routesBySlug.get(p(a.to)):this.routesBySlug.get(t)};slugHasRouteOrRedirect=t=>{if(this.routesBySlug.has(t))return!0;const e=this.getRedirect(t);if(!e)return!1;if(!L(e.to))return!0;const s=p(e.to);return this.routesBySlug.has(s)};getRoutesByTemplateId=t=>this.newRoutes.filter(e=>e.templateId===t);getAllRoutesForLocale=(t=f)=>{const e=Array.from(this.routesBySlug.values()),s=t.toLowerCase();return e.filter(a=>t===f?!K(a.fsPath):a.slug.startsWith(`/${s}`))};getAllRoutes=()=>Array.from(this.routesBySlug.values());getAllApiRoutes=()=>this.apiRoutes;getAllMiddleware=()=>this.middleware;getTemplate=t=>this.templates.get(t);getRequestHandler=t=>this.apiRoutesRequestHandlers.get(t);createTemplate=(t,e)=>(this.templates.set(t,e),t);addBrowserPlugin=t=>{this.browserPlugins.add(t)};createRequestHandler=(t,e)=>(this.apiRoutesRequestHandlers.set(t,e),t);registerServerPropsGetter=(t,e)=>(this.serverPropsGetters.set(t,e),t);registerPagePropsGetter=(t,e)=>{this.pagePropsGetters.set(t,e)};async writeRouteStaticData(t,e){const s=await this.resolveRouteStaticData(t,e,!1);s&&V(t.slug,s,this.outdir)}async resolveRouteStaticData(t,e,s){if(this.serverMode)return N(t.slug,this.outdir);const a={...this,contentDir:this.contentDir,parseMarkdoc:({input:n,context:d,resource:h})=>this.parseMarkdoc({input:n,context:d,deps:{routeSlugs:[t.slug]},resource:h})},r=await t.getStaticData?.(t,a)||{},c=new Set(this.routesDynamicComponents.get(t.slug)),l=this.routesSharedData.get(t.slug)||{};for(const n of Object.values(l)){const d=this.sharedDataMarkdocComponents.get(n);d&&d.forEach(u=>c.add(u));const h=this.sharedDataDeps.get(n);h&&h.forEach(u=>this.addRouteSharedData(t.slug,u,u))}const i=this.getGlobalConfig("seo"),o=r?.frontmatter||{};return{...r,frontmatter:{...o,seo:{...o?.seo,title:o?.seo?.title||await t.getNavText?.()}},props:{...r.props,dynamicMarkdocComponents:Array.from(c),metadata:{...r?.props?.metadata,...t.metadata},seo:{title:C,...i,...r.props?.seo},compilationErrors:this.compilationErrors},lastModified:s||!t.fsPath?null:await this.lifecycleContext?.fs.getLastModified(t.fsPath)}}addSsrComponents(t,e){if(!t?.length)return;const s=typeof t[0]=="string"?t.join(""):I(t);s&&(e==="head"?this.ssr.headTags.push(s):e==="preBody"?this.ssr.preBodyTags.push(s):this.ssr.postBodyTags.push(s))}clear=()=>{this.routesByFsPath.clear(),this.templates.clear(),this.newRoutes=[],this.routesBySlug.clear(),this.apiRoutes=[],this.middleware=[],this.routesSharedData.clear(),this.sharedDataDeps.clear(),this.sharedDataMarkdocComponents.clear(),this.routesDynamicComponents.clear(),this.routesPartials.clear(),this.config.redirects={},this.config.wildcardRedirectsTree={},this.config.directoryPermissions={},this.ssr={preBodyTags:[],postBodyTags:[],headTags:[]}};async toJson(){const t=[];for(const[s,a]of Object.entries(R))switch(a){case"map":const r=Array.from(this[s].entries());t.push([s,r]);break;case"object":s==="config"&&t.push([s,await this.getConfigWithEnvPlaceholders()]),t.push([s,this[s]]);break;default:throw new Error("Invalid format")}const e=Object.fromEntries(t);return e[v]=F.PLAN_GATES,e}static fromJson(t,e){const s=new E(e);for(const[r,c]of Object.entries(R))switch(c){case"map":s[r]=new Map(t[r]);break;case"object":if(r==="config"){s.setGlobalConfig(t[r]);break}s[r]=t[r];break;default:throw new Error("Invalid format")}s.config[m]=Y(s.config[m]||{});const a=t[v];return a&&_("PLAN_GATES",a),s}async getConfigWithEnvPlaceholders(){const t=JSON.parse(JSON.stringify(this.config));for(const e in this.replacedEnvVars){const{original:s}=this.replacedEnvVars[e],a=e.split(":"),r=a.pop(),{error:c,value:l}=S(t,a);if(c||!O(l)&&!Array.isArray(l)){await w.panicOnBuild(`Failed to replace env var with env name for ${e}`);continue}l[r]=s}return t}async reportUnsetEnvVars(){if(this.unsetEnvVars.size===0)return;const t=Array.from(this.unsetEnvVars).filter(s=>!z.includes(s));if(t.length===0)return;const e=`Failed to resolve config. The following environment variables are not set: ${t.join(", ")}`;await w.panicOnBuildContentError(e)}}function Y(P){return T(P,t=>b.Ast.fromJSON(JSON.stringify(t)))}export{m as MARKDOC_PARTIALS_DATA_KEY,W as MARKDOC_PARTIALS_DEPS_KEY,E as Store,At as USER_DEFINED_API_FUNCTIONS_COUNTER_KEY};
1
+ import A from"@markdoc/markdoc";import{getPathnameForLocale as C}from"@redocly/theme/core/utils";import{DEFAULT_LOCALE_PLACEHOLDER as g}from"../constants/common.js";import{DEFAULT_TITLE as T}from"./constants/common.js";import{GATED_MARKDOC_TAGS as D}from"./constants/entitlements.js";import{isObject as O}from"../utils/guards/is-object.js";import{mapObject as M}from"../utils/object/map-object.js";import{getValueDeep as y}from"../utils/object/get-value-deep.js";import{removeTrailingSlash as L}from"../utils/url/remove-trailing-slash.js";import{normalizeRouteSlug as h}from"../utils/path/normalize-route-slug.js";import{isLocalLink as S}from"../utils/path/is-local-link.js";import{reporter as w}from"./tools/notifiers/reporter.js";import{logger as u}from"./tools/notifiers/logger.js";import{sha1 as k}from"./utils/crypto/sha1.js";import{writeEnvVariable as _}from"./utils/envs/write-env-variable.js";import{envConfig as G}from"./config/env-config.js";import{KvService as F}from"./persistence/kv/services/kv-service.js";import{writeSharedData as B}from"./utils/index.js";import{renderComponents as I}from"./ssr/render.js";import{readStaticData as N,writeStaticData as V}from"./utils/static-data.js";import{parseAndResolveMarkdoc as j}from"./plugins/markdown/compiler.js";import{getMarkdocOptions as H}from"./plugins/markdown/markdoc/markdoc-options.js";import{EntitlementsProvider as R}from"./entitlements/entitlements-provider.js";import{isL10nPath as K}from"./fs/utils/is-l10n-path.js";import{resolveMetadataGlobs as U}from"./utils/globs.js";import{replaceEnvVariablesDeep as J}from"./utils/envs/replace-env-variables-deep.js";import{findRedirect as q}from"./utils/redirects/find-redirect.js";import{followRedirectChain as x}from"./utils/redirects/follow-redirect-chain.js";import{addWildcardRedirectToTree as W}from"./utils/redirects/add-wildcard-redirect-to-tree.js";import{telemetryTraceStep as $}from"../cli/telemetry/helpers/trace-step.js";const v={routesBySlug:"map",apiRoutes:"object",middleware:"object",routesByFsPath:"map",routesSharedData:"map",globalData:"object",config:"object",ssr:"object",searchFacets:"map",routesPartials:"map",mcpToolHandlers:"map"},m="markdown/partials",z="markdown/partials-deps",E="PLAN_GATES",Y=["OAUTH_CLIENT_ID","OAUTH_CLIENT_SECRET","ORGANIZATION_SLUG","ORGANIZATION_ID","ORG_ID"],Tt="userDefinedApiFunctions";class P{routesBySlug=new Map;replacedEnvVars={};unsetEnvVars=new Set;lifecycleContext;newRoutes=[];#t={};routesByFsPath=new Map;apiRoutes=[];middleware=[];routesSharedData=new Map;sharedDataDeps=new Map;sharedDataMarkdocComponents=new Map;routesDynamicComponents=new Map;routesPartials=new Map;ssr={preBodyTags:[],postBodyTags:[],headTags:[]};searchFacets=new Map;searchEngine;templates=new Map;browserPlugins=new Set;apiRoutesRequestHandlers=new Map;mcpToolHandlers=new Map;serverPropsGetters=new Map;pagePropsGetters=new Map;listeners=new Map;globalData={};#s=void 0;config={configFilePath:"",redirects:{},wildcardRedirectsTree:{},access:{rbac:{},requiresLogin:!1},directoryPermissions:{},devLogin:!1,ssoDirect:{}};#r;serverMode;serverOutDir;outdir;buildRevision=0;hasSitemap=!1;compilationErrors=[];#a;userCodeReady;#o=Promise.resolve();#i;#n=Promise.resolve();#c;#e=new Map;constructor({outdir:t,contentDir:s,serverMode:e=!1,serverOutDir:a}){this.#r=s,this.outdir=t,this.serverMode=e,this.serverOutDir=a,this.userCodeReady=new Promise(r=>{this.#a=r})}on(t,s){const e=this.listeners.get(t);e?e.add(s):this.listeners.set(t,new Set([s]))}queueEvent=(t,s,...e)=>{this.#e.set(t+String(s),[t,s,...e])};runListeners=(t,s,...e)=>{for(const a of this.listeners.get(t)||new Set)s?a(s,...e):a(...e)};startPluginsRun(){this.clear(),this.#o=new Promise(t=>{this.#i=t})}waitForPluginsLifecycle(){return Promise.all([this.#o,this.#n])}finishPluginsRun(){this.#i?.();for(const t of this.#e.values())this.runListeners(...t);this.#e.clear()}startEsbuildRun(){this.#n=new Promise(t=>{this.#c=t})}finishEsbuildRun(){this.#c?.()}get contentDir(){if(this.serverMode)throw new Error("contentDir should not be used in server mode");return this.#r}markUserCodeReady(){this.#a?.(!0)}async reloadMarkdocOptions(){await $("build.reload_markdoc_options",async()=>{const t=R.instance(),s=await H(this.serverOutDir),e=Object.fromEntries(Object.entries(s.tags).filter(([a])=>D[a]!=null?t.canAccessFeature(D[a]):!0));this.#s={...s,tags:e}})}get markdocOptions(){return{...this.#s,partials:this.getGlobalConfig(m),themeConfig:this.config.markdown}}setGlobalData=t=>{const s=this.globalData,e={...this.globalData,...t};this.globalData=e,JSON.stringify(e)!==JSON.stringify(s)&&this.queueEvent("global-data-updated",void 0,e)};getGlobalData=()=>this.globalData;getKv=async()=>F.getInstance({baseDbDir:this.serverOutDir});parseMarkdoc=async({input:t,context:s,deps:e,resource:a})=>{const{data:{info:r,ast:o},compoundHash:l}=await j(t,this.markdocOptions,{actions:this,context:s},a);for(const i of r.sharedDataDeps||[]){for(const n of e?.routeSlugs||[])this.addRouteSharedData(n,i,i);for(const n of e?.sharedDataIds||[]){const c=this.sharedDataDeps.get(n)||new Set;c.add(i),this.sharedDataDeps.set(n,c)}}for(const i of r.dynamicMarkdocComponents||[]){for(const n of e?.routeSlugs||[]){const c=this.routesDynamicComponents.get(n)||new Set;c.add(i),this.routesDynamicComponents.set(n,c)}for(const n of e?.sharedDataIds||[]){const c=this.sharedDataMarkdocComponents.get(n)||new Set;c.add(i),this.sharedDataMarkdocComponents.set(n,c)}}if(e?.routeSlugs&&r.partials?.length)for(const i of e.routeSlugs){const n=this.routesPartials.get(i)||[];for(const c of r.partials)n.includes(c)||n.push(c);this.routesPartials.set(i,n)}return{info:r,ast:o,compoundHash:l}};async loadOpenApiDefinitions(t){return(await t.cache.load(".","load-oas-docs")).data}async loadAsyncApiDefinitions(t){return(await t.cache.load(".","asyncapi-docs")).data}setSearchEngine(t){this.searchEngine=t}setSearchFacets=t=>{this.searchFacets=t};setGlobalConfig=t=>{const s=Object.keys(t);for(const o of s)for(const l in this.replacedEnvVars)if(l===o||l.startsWith(`${o}:`)){const i=l.split(":"),{error:n,value:c}=y(t,i);(n||c!==this.replacedEnvVars[l].replaced)&&delete this.replacedEnvVars[l]}const{resolvedObj:e,unsetEnvVars:a,replacedValues:r}=J(t);for(const o of a)this.unsetEnvVars.add(o);Object.assign(this.replacedEnvVars,r),Object.assign(this.config,e)};getConfig=()=>this.config;getGlobalConfig=t=>this.config[t];getSearchFacets=()=>this.searchFacets;addRedirect=(t,s,e={})=>{if(!R.instance().canAccessFeature("redirects")&&t!=="/")return;this.config.redirects||(this.config.redirects={});const o=h(t).toLowerCase();this.config.redirects[o]=s;const{trackOriginalSource:l=!0}=e,i=this.getGlobalConfig("originalRedirectSources");l&&Array.isArray(i)&&!i.includes(o)&&i.push(o),o.endsWith("*")&&W(this.config.wildcardRedirectsTree,o)};getRedirect=t=>{const s=h(t).toLowerCase(),e=q(s,this.config.redirects,this.config.wildcardRedirectsTree);if(!e)return null;if(S(e.to)){const a=h(e.to).toLowerCase();if(!a.endsWith("*")&&x(a,[s],this.config.redirects,this.config.wildcardRedirectsTree).type==="cycle")return null}return{to:e.to,type:e.type}};createSharedData=async(t,s,e)=>{if(e&&this.#t[t]===e)return t;const a=JSON.stringify(s),r=e??k(a);return this.#t[t]===r||(this.#t[t]=r,await B(t,a,this.outdir),this.queueEvent("shared-data-updated",t)),t};addRouteSharedData=(t,s,e)=>{const a=L(t),r=this.routesSharedData.get(a)||{};r[s]=e,this.routesSharedData.set(a,r),u.verbose(`Adding shared data to ${t}, ${s}, ${e}`)};getRouteSharedDataByFsPath=t=>{const s=this.routesByFsPath.get(t);return s?this.routesSharedData.get(s)||{}:{}};getPartialsForRoute=t=>{const s=this.getGlobalConfig(m)||{},e=this.routesPartials.get(t);if(!e||e.length===0)return{};const a=this.getGlobalConfig(z)||{},r=new Set(e),o=Array.from(e);for(let i=0;i<o.length;i++){const n=o[i],c=a[n]?.partials??[];for(const d of c)r.has(d)||(r.add(d),o.push(d))}const l={};for(const i of r)s[i]&&(l[i]=s[i]);return l};addRoute=t=>{const e={...U(t.fsPath,this.config.metadataGlobs),...t.metadata||{}};this.newRoutes.push({...t,metadata:e}),u.verbose("Created route %s",t.slug)};addRouteSharedDataToAllLocales=(t,s,e)=>{const a=[g,...this.lifecycleContext?.fs.localeFolders||[]].map(r=>({code:r,name:r}));for(const r of a){const o=C(t,g,r.code,a);this.addRouteSharedData(o,s,e)}};addApiRoute=t=>{this.apiRoutes.push(t),u.verbose("Created API route %s",t.slug)};addMcpTools=(t,s)=>{for(const e of s)this.mcpToolHandlers.set(e.name,{...e,importPath:t}),u.verbose("Created MCP tool %s",e.name)};getMcpTools=()=>Array.from(this.mcpToolHandlers.values());addMiddleware=t=>{this.middleware.push(t),u.verbose("Created middleware %s",t.id)};getRouteByFsPath=t=>{const s=this.routesByFsPath.get(t);return s?this.getRouteBySlug(s):void 0};getRouteBySlug=(t,s={})=>{const{followRedirect:e=!0}=s,a=this.getRedirect(t);return e&&a?this.routesBySlug.get(h(a.to)):this.routesBySlug.get(t)};slugHasRouteOrRedirect=t=>{if(this.routesBySlug.has(t))return!0;const s=this.getRedirect(t);if(!s)return!1;if(!S(s.to))return!0;const e=h(s.to);return this.routesBySlug.has(e)};getRoutesByTemplateId=t=>this.newRoutes.filter(s=>s.templateId===t);getAllRoutesForLocale=(t=g)=>{const s=Array.from(this.routesBySlug.values()),e=t.toLowerCase();return s.filter(a=>t===g?!K(a.fsPath):a.slug.startsWith(`/${e}`))};getAllRoutes=()=>Array.from(this.routesBySlug.values());getAllApiRoutes=()=>this.apiRoutes;getAllMiddleware=()=>this.middleware;getTemplate=t=>this.templates.get(t);getRequestHandler=t=>this.apiRoutesRequestHandlers.get(t);createTemplate=(t,s)=>(this.templates.set(t,s),t);addBrowserPlugin=t=>{this.browserPlugins.add(t)};createRequestHandler=(t,s)=>(this.apiRoutesRequestHandlers.set(t,s),t);registerServerPropsGetter=(t,s)=>(this.serverPropsGetters.set(t,s),t);registerPagePropsGetter=(t,s)=>{this.pagePropsGetters.set(t,s)};async writeRouteStaticData(t,s){const e=await this.resolveRouteStaticData(t,s,!1);e&&V(t.slug,e,this.outdir)}async resolveRouteStaticData(t,s,e){if(this.serverMode)return N(t.slug,this.outdir);const a={...this,contentDir:this.contentDir,parseMarkdoc:({input:c,context:d,resource:f})=>this.parseMarkdoc({input:c,context:d,deps:{routeSlugs:[t.slug]},resource:f})},r=await t.getStaticData?.(t,a)||{},o=new Set(this.routesDynamicComponents.get(t.slug)),l=this.routesSharedData.get(t.slug)||{};for(const c of Object.values(l)){const d=this.sharedDataMarkdocComponents.get(c);d&&d.forEach(p=>o.add(p));const f=this.sharedDataDeps.get(c);f&&f.forEach(p=>this.addRouteSharedData(t.slug,p,p))}const i=this.getGlobalConfig("seo"),n=r?.frontmatter||{};return{...r,frontmatter:{...n,seo:{...n?.seo,title:n?.seo?.title||await t.getNavText?.()}},props:{...r.props,dynamicMarkdocComponents:Array.from(o),metadata:{...r?.props?.metadata,...t.metadata},seo:{title:T,...i,...r.props?.seo},compilationErrors:this.compilationErrors},lastModified:e||!t.fsPath?null:await this.lifecycleContext?.fs.getLastModified(t.fsPath)}}addSsrComponents(t,s){if(!t?.length)return;const e=typeof t[0]=="string"?t.join(""):I(t);e&&(s==="head"?this.ssr.headTags.push(e):s==="preBody"?this.ssr.preBodyTags.push(e):this.ssr.postBodyTags.push(e))}clear=()=>{this.routesByFsPath.clear(),this.templates.clear(),this.newRoutes=[],this.routesBySlug.clear(),this.apiRoutes=[],this.middleware=[],this.routesSharedData.clear(),this.sharedDataDeps.clear(),this.sharedDataMarkdocComponents.clear(),this.routesDynamicComponents.clear(),this.routesPartials.clear(),this.config.redirects={},this.config.wildcardRedirectsTree={},this.config.directoryPermissions={},this.ssr={preBodyTags:[],postBodyTags:[],headTags:[]}};async toJson(){const t=[];for(const[e,a]of Object.entries(v))switch(a){case"map":const r=Array.from(this[e].entries());t.push([e,r]);break;case"object":e==="config"&&t.push([e,await this.getConfigWithEnvPlaceholders()]),t.push([e,this[e]]);break;default:throw new Error("Invalid format")}const s=Object.fromEntries(t);return s[E]=G.PLAN_GATES,s}static fromJson(t,s){const e=new P(s);for(const[r,o]of Object.entries(v))switch(o){case"map":e[r]=new Map(t[r]);break;case"object":if(r==="config"){e.setGlobalConfig(t[r]);break}e[r]=t[r];break;default:throw new Error("Invalid format")}e.config[m]=Z(e.config[m]||{});const a=t[E];return a&&_("PLAN_GATES",a),e}async getConfigWithEnvPlaceholders(){const t=JSON.parse(JSON.stringify(this.config));for(const s in this.replacedEnvVars){const{original:e}=this.replacedEnvVars[s],a=s.split(":"),r=a.pop(),{error:o,value:l}=y(t,a);if(o||!O(l)&&!Array.isArray(l)){await w.panicOnBuild(`Failed to replace env var with env name for ${s}`);continue}l[r]=e}return t}async reportUnsetEnvVars(){if(this.unsetEnvVars.size===0)return;const t=Array.from(this.unsetEnvVars).filter(e=>!Y.includes(e));if(t.length===0)return;const s=`Failed to resolve config. The following environment variables are not set: ${t.join(", ")}`;await w.panicOnBuildContentError(s)}}function Z(b){return M(b,t=>A.Ast.fromJSON(JSON.stringify(t)))}export{m as MARKDOC_PARTIALS_DATA_KEY,z as MARKDOC_PARTIALS_DEPS_KEY,P as Store,Tt as USER_DEFINED_API_FUNCTIONS_COUNTER_KEY};
@@ -1 +1 @@
1
- import{AsyncApiRealmAPI as o}from"@redocly/realm-asyncapi-sdk";import{envConfig as e}from"../config/env-config.js";import{PACKAGE_NAME as t}from"../../config/product-gates.js";import{OTEL_TRACES_DEV_URL as i,TELEMETRY_ENABLED as s}from"../constants/common.js";class l extends o.Telemetry{constructor(){super(),this.updateCloudEventData(()=>({organizationId:e.ORGANIZATION_ID||"",organizationSlug:e.ORGANIZATION_SLUG||"",projectId:e.PROJECT_ID||"",projectSlug:"",origin:"realmApi",actor:{id:"Anonymous",object:"user",uri:""},source:"server"}))}initialize(r=!1){this.init({otel:{serviceName:"realm-server",serviceVersion:`${t}@${e.REDOCLY_PORTAL_VERSION||""}`,collectorTraceUrl:r?i:e.OTEL_TRACES_URL||"https://otel.cloud.redocly.com/v1/traces",isProd:e.isProductionEnv,version:"1.0",tracerName:"server-telemetry",delayMillis:100},disabled:r?e.TELEMETRY_DEV_DEBUG!=="true":!s})}}const A=new l;export{A as telemetry};
1
+ import{AsyncApiRealmAPI as o}from"@redocly/realm-asyncapi-sdk";import{envConfig as e}from"../config/env-config.js";import{PACKAGE_NAME as t}from"../../config/product-gates.js";import{OTEL_TRACES_DEV_URL as i,TELEMETRY_ENABLED as s}from"../constants/common.js";class l extends o.Telemetry{constructor(){super(),this.updateCloudEventData(()=>({organizationId:e.ORGANIZATION_ID||"",organizationSlug:e.ORGANIZATION_SLUG||"",projectId:e.PROJECT_ID||"",projectSlug:e.PROJECT_SLUG||"",origin:"realmApi",actor:{id:"Anonymous",object:"user",uri:""},source:"server",env:e.redoclyEnv}))}initialize(r=!1){this.init({otel:{serviceName:"realm-server",serviceVersion:`${t}@${e.REDOCLY_PORTAL_VERSION||""}`,collectorTraceUrl:r?i:e.OTEL_TRACES_URL||"https://otel.cloud.redocly.com/v1/traces",isProd:e.isProductionEnv,version:"1.0",tracerName:"server-telemetry",delayMillis:100},disabled:r?e.TELEMETRY_DEV_DEBUG!=="true":!s})}}const A=new l;export{A as telemetry};
@@ -115,6 +115,14 @@ export type ApiRoute = RouteDetails & {
115
115
  httpMethod: ApiRouteMethod;
116
116
  requestHandlerId: string;
117
117
  };
118
+ export type McpToolSchema = {
119
+ name: string;
120
+ description: string;
121
+ schema: Record<string, unknown>;
122
+ };
123
+ export type McpToolRegistration = McpToolSchema & {
124
+ importPath: string;
125
+ };
118
126
  export type MiddlewareDetails = {
119
127
  id: string;
120
128
  importPath: string;
@@ -124,6 +132,9 @@ export type PathVersionInfo = {
124
132
  isDefault: boolean;
125
133
  versionFolderId: string;
126
134
  };
135
+ export type RedirectOptions = {
136
+ trackOriginalSource?: boolean;
137
+ };
127
138
  export type ProcessContentActions = {
128
139
  createSharedData(id: string, data: unknown, hash?: string): Promise<string>;
129
140
  addRouteSharedData(slug: string, dataKey: string, dataId: string): void;
@@ -141,8 +152,10 @@ export type ProcessContentActions = {
141
152
  getSearchFacets: () => Map<string, SearchFacet>;
142
153
  addRoute: (route: PageRouteInit) => void;
143
154
  addApiRoute: (route: ApiRoute) => void;
155
+ addMcpTools: (importPath: string, tools: McpToolSchema[]) => void;
156
+ getMcpTools: () => McpToolRegistration[];
144
157
  createRequestHandler: (id: string, importPath: string) => void;
145
- addRedirect: (from: string, to: RedirectConfig) => void;
158
+ addRedirect: (from: string, to: RedirectConfig, options?: RedirectOptions) => void;
146
159
  createTemplate: (id: string, importPath: string) => string;
147
160
  addBrowserPlugin: (importPath: string) => void;
148
161
  registerServerPropsGetter: (id: string, importPath: string) => string;
@@ -176,7 +189,7 @@ export type AfterRoutesCreatedActions = {
176
189
  setSearchFacets: (facets: Map<string, SearchFacet>) => void;
177
190
  getSearchFacets: () => Map<string, SearchFacet>;
178
191
  setSearchEngine: (engine: SearchEngine) => void;
179
- addRedirect: (from: string, to: RedirectConfig) => void;
192
+ addRedirect: (from: string, to: RedirectConfig, options?: RedirectOptions) => void;
180
193
  contentDir: string;
181
194
  outdir: string;
182
195
  serverOutDir: string;
@@ -3,4 +3,10 @@ export type WildcardRedirectsTree = {
3
3
  } & {
4
4
  '*'?: string;
5
5
  };
6
+ export type FollowRedirectChainResult = {
7
+ type: 'cycle';
8
+ cycle: string[];
9
+ } | {
10
+ type: 'no-cycle';
11
+ };
6
12
  //# sourceMappingURL=redirects.d.ts.map
@@ -1 +1 @@
1
- import R from"path";import x from"picomatch";import"../node-crypto-polyfill.js";import{REDOCLY_TEAMS_RBAC as _,REDOCLY_ROUTE_RBAC as A}from"@redocly/config";import{DEFAULT_ANONYMOUS_VISITOR_TEAM as O,ServerRoutes as w,PUBLIC_RBAC_SCOPE_ITEM as y,RBAC_ALL_OTHER_TEAMS as u,DEFAULT_RBAC_SCOPE as S}from"../../constants/common.js";import{DEPRECATED_PUBLIC_API_DEFINITIONS_FOLDER as I,PUBLIC_API_DEFINITIONS_FOLDER as C,PUBLIC_ASSETS_FOLDER as N}from"../constants/common.js";import{removeTrailingSlash as B}from"../../utils/url/remove-trailing-slash.js";import{removeLeadingSlash as k}from"../../utils/url/remove-leading-slash.js";import{parsePathVersions as M}from"../../utils/path/parse-path-versions.js";import{reporter as W}from"../tools/notifiers/reporter.js";import{bold as U}from"../tools/notifiers/helpers/colors.js";import{shaDirPathShort as $}from"../utils/crypto/sha-dir-path-short.js";import{isTruthy as b}from"../../utils/guards/is-truthy.js";import{canExpandConfig as v,expandRbacConfig as Y,getTeamFolderDefaults as z,parseTeamFoldersTemplate as H,parseTeamNameTemplate as K}from"./rbac-expand.js";import{getUserParamsFromCookies as G}from"../web-server/auth.js";import{getDeeperGlobPattern as V}from"./globs.js";import{EntitlementsProvider as J}from"../entitlements/entitlements-provider.js";const j=["NONE","READ","TRIAGE","WRITE","MAINTAIN","ADMIN"],Q=new Set(["x-parsed-md-description","x-parsed-md-summary"]);function yt(t,e){const n=j.indexOf(t.toUpperCase()),r=j.indexOf(e.toUpperCase());return n>r?t:e}const E={};function P(t,e){if(!t?.content)return y;const n=t.content,{slug:r,fsPath:s}=e;if(!r&&!s)return y;const o=f=>{const h=`slug:${f}`,m=E[h]??x(f);E[h]=m;const g=`fsPath:${f}`,L=E[g]??x(k(f));return E[g]=L,!!(r&&m(r))||!!(s&&L(s))};if(X(r||s||"")&&Object.keys(n).filter(m=>o(m)).length===0)return n[S]||y;const c=Object.keys(n).filter(f=>o(f));if(c.length==0)return y;const l=c.map(f=>x.scan(f,{tokens:!0,parts:!0}));let p=l[0];for(let f=1;f<l.length;f++)p=V(p,l[f]);return n[p.input]}function Et(t,e,n={},r=!1){if(r&&Object.keys(n).length===0)return e.isAuthenticated;const s=n.features?.[t];return s?e.teams.some(o=>s[o]&&s[o].toLowerCase()!=="none"):!0}function Pt(t,e){return T(t,{isAuthenticated:!1,teams:[O]},e.access?.rbac||{},e.access?.requiresLogin||!1)}function T(t,e={},n={},r=!1){if(t.slug&&typeof t.slug=="string"&&Object.values(w).some(c=>{const l=c.split(":")[0].replace(/\/$/,"");return t.slug===l||t.slug?.startsWith(c)})||typeof t.slug=="string"&&t.slug?.endsWith("/mcp")&&J.instance().canAccessFeature("mcp"))return!0;if(r&&Object.keys(n).length===0)return!!e.isAuthenticated;const s=Y(n,e.teams||[]),o=t[_]||P(s,t[A]||{});if(Object.keys(o||{}).length===0)return!1;if(Object.keys(o).length===1&&o[u]&&o[u].toLowerCase()!=="none")return!0;const a=(e?.email?[...e?.teams||[],e?.email]:e?.teams)||[],i=[];for(const c of a??[])o[c]?i.push(o[c]):o[u]&&c!==e?.email&&i.push(o[u]);return i.length?i.some(c=>c.toLowerCase()!=="none"):!1}function Tt(t,e,n,r){if(!t.startsWith(C)&&!t.startsWith(I))return!0;const s=t.replace(new RegExp(`^${C}/`),"").replace(new RegExp(`^${I}/`),""),a=s==="."?"":s,i={[A]:{slug:t,fsPath:a},slug:t};return T(i,r,e,n)}function xt(t,e,n,r,s){if(!t.startsWith(N))return!0;const o=t.match(/.*\..{64}\.([A-Fa-f0-9]{8})\.[^\.]+$/)?.[1];if(!o)return!0;const a=r[o];if(!a)return!0;const{base:i,ext:c}=R.parse(t),l=i.split(".")[0],p=c.split(".").join(""),h=a==="."?"":a,m={[A]:{slug:t,fsPath:R.posix.join(h,`${l}.${p}`)},slug:t};return T(m,s,e,n)}async function Ot(t,e){const{isAuthenticated:n=!1,idpAccessToken:r,federatedAccessToken:s,federatedIdToken:o,...a}=await G(t,e),{teams:i=[]}=a;let c;return n?c=i.filter(l=>l!==O):c=[O],{isAuthenticated:n,idpAccessToken:r,teams:c,claims:a}}function F(t,e,n={},r=!1){if(!t)return t;if(Array.isArray(t)){const s=[];for(const o of t){const a=F(o,e,n,r);a!==void 0&&s.push(a)}return s}if(typeof t=="object"){if(!T(t,e,n,r))return;let s=!1;const o={};for(const a in t){if(a===_||a===A)continue;if(Q.has(a)){o[a]=t[a];continue}const i=F(t[a],e,n,r);if(a==="items"&&Array.isArray(i)&&i.length===0&&t[a].length!==0){s=!0;continue}i!==void 0&&(o[a]=i)}return s?void 0:o}return t}function Dt(t){return typeof t=="string"?t.split(" ").filter(Boolean):Array.isArray(t)?t.map(e=>e.toString()):[]}function gt(t,e){if(!e)return;const n=e.content;if(!n)return e;const r=Object.entries(n).flatMap(([o,a])=>o===S?[[o,a]]:[[o,a],...t.localeFolders.map(i=>[o.startsWith("/")?`/${i.toLocaleLowerCase()}${o}`:R.posix.join(t.localizationFolder,i,o),a])]),s=Object.fromEntries(r);return{...e,content:s}}async function Lt(t,e){if(!e)return{};const n={},r=new Set((await t.scan()).flatMap(({relativePath:s})=>{const{versionFolderPath:o}=M(s)||{},a=R.dirname(s);return o?[o,a]:a}));for(const s of r)n[$(s)]=s;return n}const d=t=>typeof t=="object"&&t!==null&&!Array.isArray(t);function X(t){return t?t.split("/").filter(Boolean).some(n=>n.startsWith(".")):!1}const Z=t=>{if(t&&d(t)&&("content"in t&&d(t.content)||"reunite"in t&&d(t.reunite)||"features"in t&&d(t.features)||t.teamFolders&&t.teamNamePatterns)){const e=Object.values(t.content||{});if(e.length===0)return!0;if(e.every(d))return e.every(n=>Object.values(n).every(r=>typeof r=="string"))}return!1},_t=async t=>{if(t){if(Object.keys(t).length===0)return{};if(Z(t))return q(t);await W.panicOnContentError(`You are using an incorrect format of ${U("rbac:")} configuration. See: https://redocly.com/docs/realm/access`)}},q=t=>{const e={...t};if(e.content){const n={};for(const r in e.content)if(e.content[r]!==void 0){const s=B(r);n[s]=e.content[r]}e.content=n}return e};function St(t,e){const n=t.fsPath,r=t.slug,s=[];if(v(e)&&(n||r)){const o=[n,r].filter(b),a=H(e,o);if(a){const i=e?.teamNamePatterns?.map(l=>l.replace("{teamPathSegment}",a.teamPathSegment).replace("{projectRole}","read"))??[];s.push(...i);const c=P({content:{...z(e),...e.content}},t);s.push(...D(c))}else{const i=P(e,t);s.push(...D(i))}}else{const o=P(e,t);s.push(...D(o))}return tt(e,s)}function D(t){if(!t)return[];const e=[],n=u in t?{authenticated:t[u],anonymous:t[u]}:{};for(const[r,s]of Object.entries({...n,...t}))s.toLowerCase()!=="none"&&r!==u&&e.push(r);return e}function tt(t,e){return e.map(r=>K(t,r)??{teamName:r}).map(r=>r.projectRole&&r.projectRole!=="READ"?r.teamName?.toLowerCase().replace(r.projectRole?.toLowerCase?.()??"","read")??"":r.teamName?.toLowerCase()??"")}export{j as PROJECT_ROLES_ORDERED_BY_ACCESS_LEVEL,gt as applyL10nToRbacConfig,xt as canAccessAsset,Et as canAccessFeature,T as canAccessResource,Tt as canDownloadApiDefinition,tt as expandTeamsForRead,D as extractTeamsFromScopeItems,F as filterDataByAccessDeep,Ot as getAuthDetailsFromCookies,yt as getHigherRole,St as getRbacTeamsListForResource,P as getScopeItemsForResource,Z as isRbacConfigValid,Pt as isResourcePubliclyAccessible,q as normalizeRbacConfig,_t as parseRbacConfig,Dt as parseTeamClaimToArray,Lt as resolveDirectoryHashes};
1
+ import y from"path";import T from"picomatch";import"../node-crypto-polyfill.js";import{REDOCLY_TEAMS_RBAC as _,REDOCLY_ROUTE_RBAC as R}from"@redocly/config";import{DEFAULT_ANONYMOUS_VISITOR_TEAM as x,ServerRoutes as w,PUBLIC_RBAC_SCOPE_ITEM as A,RBAC_ALL_OTHER_TEAMS as u,DEFAULT_RBAC_SCOPE as S}from"../../constants/common.js";import{DEPRECATED_PUBLIC_API_DEFINITIONS_FOLDER as j,PUBLIC_API_DEFINITIONS_FOLDER as I,PUBLIC_ASSETS_FOLDER as N}from"../constants/common.js";import{removeTrailingSlash as k}from"../../utils/url/remove-trailing-slash.js";import{removeLeadingSlash as B}from"../../utils/url/remove-leading-slash.js";import{parsePathVersions as b}from"../../utils/path/parse-path-versions.js";import{reporter as M}from"../tools/notifiers/reporter.js";import{bold as W}from"../tools/notifiers/helpers/colors.js";import{shaDirPathShort as U}from"../utils/crypto/sha-dir-path-short.js";import{isTruthy as $}from"../../utils/guards/is-truthy.js";import{canExpandConfig as v,expandRbacConfig as Y,getTeamFolderDefaults as z,parseTeamFoldersTemplate as K,parseTeamNameTemplate as H}from"./rbac-expand.js";import{getUserParamsFromCookies as G}from"../web-server/auth.js";import{getDeeperGlobPattern as V}from"./globs.js";import{EntitlementsProvider as J}from"../entitlements/entitlements-provider.js";const C=["NONE","READ","TRIAGE","WRITE","MAINTAIN","ADMIN"],Q=new Set(["x-parsed-md-description","x-parsed-md-summary"]);function Ot(t,e){const r=C.indexOf(t.toUpperCase()),n=C.indexOf(e.toUpperCase());return r>n?t:e}const E={};function O(t,e){if(!t?.content)return A;const r=t.content,{slug:n,fsPath:s}=e;if(!n&&!s)return A;const o=f=>{const d=`slug:${f}`,p=E[d]??T(f);E[d]=p;const D=`fsPath:${f}`,L=E[D]??T(B(f));return E[D]=L,!!(n&&p(n))||!!(s&&L(s))};if(q(n||s||"")&&Object.keys(r).filter(p=>o(p)).length===0)return r[S]||A;const i=Object.keys(r).filter(f=>o(f));if(i.length==0)return A;const l=i.map(f=>T.scan(f,{tokens:!0,parts:!0}));let h=l[0];for(let f=1;f<l.length;f++)h=V(h,l[f]);return r[h.input]}function Pt(t,e,r={},n=!1){if(n&&Object.keys(r).length===0)return e.isAuthenticated;const s=r.features?.[t];return s?e.teams.some(o=>s[o]&&s[o].toLowerCase()!=="none"):!0}function Tt(t,e){return P(t,{isAuthenticated:!1,teams:[x]},e.access?.rbac||{},e.access?.requiresLogin||!1)}function P(t,e={},r={},n=!1){if(t.slug&&typeof t.slug=="string"&&Object.values(w).some(i=>{const l=i.split(":")[0].replace(/\/$/,"");return t.slug===l||t.slug?.startsWith(i)})||typeof t.slug=="string"&&t.slug?.endsWith("/mcp")&&J.instance().canAccessFeature("mcp"))return!0;if(n&&Object.keys(r).length===0)return!!e.isAuthenticated;const s=Y(r,e.teams||[]),o=t[_]||O(s,t[R]||{});if(Object.keys(o||{}).length===0)return!1;if(Object.keys(o).length===1&&o[u]&&o[u].toLowerCase()!=="none")return!0;const c=(e?.email?[...e?.teams||[],e?.email]:e?.teams)||[],a=[];for(const i of c??[])o[i]?a.push(o[i]):o[u]&&i!==e?.email&&a.push(o[u]);return a.length?a.some(i=>i.toLowerCase()!=="none"):!1}function xt(t,e,r,n){if(!t.startsWith(I)&&!t.startsWith(j))return!0;const s=t.replace(new RegExp(`^${I}/`),"").replace(new RegExp(`^${j}/`),""),c=s==="."?"":s,a={[R]:{slug:t,fsPath:c},slug:t};return P(a,n,e,r)}function gt(t,e,r,n,s){if(!t.startsWith(N))return!0;const o=t.match(/.*\..{64}\.([A-Fa-f0-9]{8})\.[^\.]+$/)?.[1];if(!o)return!0;const c=n[o];if(!c)return!0;const{base:a,ext:i}=y.parse(t),l=a.split(".")[0],h=i.split(".").join(""),d=c==="."?"":c,p={[R]:{slug:t,fsPath:y.posix.join(d,`${l}.${h}`)},slug:t};return P(p,s,e,r)}async function Dt(t,e){const{isAuthenticated:r=!1,idpAccessToken:n,federatedAccessToken:s,federatedIdToken:o,...c}=await G(t,e),{teams:a=[]}=c;let i;return r?i=a.filter(l=>l!==x):i=[x],{isAuthenticated:r,idpAccessToken:n,teams:i,claims:c}}function F(t,e,r={},n=!1){if(!t)return t;if(Array.isArray(t)){const s=[];for(const o of t){const c=F(o,e,r,n);c!==void 0&&s.push(c)}return s}if(typeof t=="object"){if(!P(t,e,r,n))return;let s=!1;const o={};for(const c in t){if(c===_||c===R)continue;if(Q.has(c)){o[c]=t[c];continue}const a=F(t[c],e,r,n);if(c==="items"&&Array.isArray(a)&&a.length===0&&t[c].length!==0){s=!0;continue}a!==void 0&&(o[c]=a),c==="paths"&&X(a)&&Z(a)}return s?void 0:o}return t}function Lt(t){return typeof t=="string"?t.split(" ").filter(Boolean):Array.isArray(t)?t.map(e=>e.toString()):[]}function _t(t,e){if(!e)return;const r=e.content;if(!r)return e;const n=Object.entries(r).flatMap(([o,c])=>o===S?[[o,c]]:[[o,c],...t.localeFolders.map(a=>[o.startsWith("/")?`/${a.toLocaleLowerCase()}${o}`:y.posix.join(t.localizationFolder,a,o),c])]),s=Object.fromEntries(n);return{...e,content:s}}async function St(t,e){if(!e)return{};const r={},n=new Set((await t.scan()).flatMap(({relativePath:s})=>{const{versionFolderPath:o}=b(s)||{},c=y.dirname(s);return o?[o,c]:c}));for(const s of n)r[U(s)]=s;return r}const m=t=>typeof t=="object"&&t!==null&&!Array.isArray(t);function X(t){return m(t)&&Object.keys(t).length>0}function Z(t){for(const e of Object.keys(t)){const r=t[e];m(r)&&Object.keys(r).length===0&&delete t[e]}}function q(t){return t?t.split("/").filter(Boolean).some(r=>r.startsWith(".")):!1}const tt=t=>{if(t&&m(t)&&("content"in t&&m(t.content)||"reunite"in t&&m(t.reunite)||"features"in t&&m(t.features)||t.teamFolders&&t.teamNamePatterns)){const e=Object.values(t.content||{});if(e.length===0)return!0;if(e.every(m))return e.every(r=>Object.values(r).every(n=>typeof n=="string"))}return!1},jt=async t=>{if(t){if(Object.keys(t).length===0)return{};if(tt(t))return et(t);await M.panicOnContentError(`You are using an incorrect format of ${W("rbac:")} configuration. See: https://redocly.com/docs/realm/access`)}},et=t=>{const e={...t};if(e.content){const r={};for(const n in e.content)if(e.content[n]!==void 0){const s=k(n);r[s]=e.content[n]}e.content=r}return e};function It(t,e){const r=t.fsPath,n=t.slug,s=[];if(v(e)&&(r||n)){const o=[r,n].filter($),c=K(e,o);if(c){const a=e?.teamNamePatterns?.map(l=>l.replace("{teamPathSegment}",c.teamPathSegment).replace("{projectRole}","read"))??[];s.push(...a);const i=O({content:{...z(e),...e.content}},t);s.push(...g(i))}else{const a=O(e,t);s.push(...g(a))}}else{const o=O(e,t);s.push(...g(o))}return rt(e,s)}function g(t){if(!t)return[];const e=[],r=u in t?{authenticated:t[u],anonymous:t[u]}:{};for(const[n,s]of Object.entries({...r,...t}))s.toLowerCase()!=="none"&&n!==u&&e.push(n);return e}function rt(t,e){return e.map(n=>H(t,n)??{teamName:n}).map(n=>n.projectRole&&n.projectRole!=="READ"?n.teamName?.toLowerCase().replace(n.projectRole?.toLowerCase?.()??"","read")??"":n.teamName?.toLowerCase()??"")}export{C as PROJECT_ROLES_ORDERED_BY_ACCESS_LEVEL,_t as applyL10nToRbacConfig,gt as canAccessAsset,Pt as canAccessFeature,P as canAccessResource,xt as canDownloadApiDefinition,rt as expandTeamsForRead,g as extractTeamsFromScopeItems,F as filterDataByAccessDeep,Dt as getAuthDetailsFromCookies,Ot as getHigherRole,It as getRbacTeamsListForResource,O as getScopeItemsForResource,tt as isRbacConfigValid,Tt as isResourcePubliclyAccessible,et as normalizeRbacConfig,jt as parseRbacConfig,Lt as parseTeamClaimToArray,St as resolveDirectoryHashes};
@@ -1,39 +1,16 @@
1
- import type { RedirectsConfig, RedirectConfig } from '@redocly/config';
1
+ import type { RedirectConfig, RedirectsConfig } from '@redocly/config';
2
2
  import type { WildcardRedirectsTree } from '../../types';
3
3
  /**
4
- * Finds a matching redirect configuration for a given slug.
4
+ * Looks up a redirect rule for a slug
5
5
  *
6
6
  * **IMPORTANT:** The `slug` parameter must be normalized before passing to this function.
7
- * This function does NOT perform normalization internally.
8
7
  *
9
- * - First checks for a direct match in the `redirects` configuration.
10
- * - If no direct match is found, searches for wildcard redirects (patterns ending with `*`).
11
- * - For wildcard matches, preserves the remaining path after the wildcard prefix if the redirect target also ends with `*`.
8
+ * - For wildcard rules whose target ends with `*`, the remainder of the path is preserved.
9
+ * - `from` is the matched config key (path or pattern); exposed for `followRedirectChain` rule tracking.
12
10
  *
13
- * @param slug - The normalized (lowercased) URL slug to find a redirect for.
14
- * @param redirects - The redirects configuration object.
15
- * @param wildcardRedirectsTree - The wildcard redirects converted to a tree structure to optimize the search.
16
- * @returns An object containing the redirect `to` URL and optional `type`, or `null` if no redirect is found.
17
- *
18
- * @example
19
- * // Direct redirect
20
- * findRedirect('/old-page', { '/old-page': { to: '/new-page', type: 301 } }, {});
21
- * // Returns: { to: '/new-page', type: 301 }
22
- *
23
- * @example
24
- * // Wildcard redirect with path preservation
25
- * findRedirect('/docs/guide/intro', { '/docs/*': { to: '/documentation/*', type: 301 } }, { 'docs': { '*': '/docs/*' } });
26
- * // Returns: { to: '/documentation/guide/intro', type: 301 }
27
- *
28
- * @example
29
- * // Wildcard redirect to fixed destination
30
- * findRedirect('/old/anything', { '/old/*': { to: '/new-home', type: 302 } }, { 'old': { '*': '/old/*' } });
31
- * // Returns: { to: '/new-home', type: 302 }
32
- *
33
- * @example
34
- * // No match found
35
- * findRedirect('/some-page', {}, {});
36
- * // Returns: null
11
+ * @returns Redirect config with resolved `to`, plus `from`, or `null` if no rule matches or the rule would not change the slug.
37
12
  */
38
- export declare function findRedirect(slug: string, redirects: RedirectsConfig, wildcardRedirectsTree: WildcardRedirectsTree): WithRequired<RedirectConfig, 'to'> | null;
13
+ export declare function findRedirect(slug: string, redirects: RedirectsConfig, wildcardRedirectsTree: WildcardRedirectsTree): (WithRequired<RedirectConfig, 'to'> & {
14
+ from: string;
15
+ }) | null;
39
16
  //# sourceMappingURL=find-redirect.d.ts.map
@@ -1 +1 @@
1
- import{removeLeadingSlash as f}from"../../../utils/url/remove-leading-slash.js";function p(e,i,o){e=e.toLowerCase();const t=i[e];if(t&&t.to)return{to:t.to,type:t.type};const r=a(e,o);if(r){let n=i[r]?.to;if(n){if(n.endsWith("*")){const c=r.split("*")[0],d=e.substring(c.length);n=n.replace(/\*$/,d)}return{...i[r],to:n}}}return null}function a(e,i){const o=f(e).split("/");let t=i;for(const r of o){if(!t[r])break;t=t[r]}return t["*"]||null}export{p as findRedirect};
1
+ import{normalizeRouteSlug as a}from"../../../utils/path/normalize-route-slug.js";import{removeLeadingSlash as d}from"../../../utils/url/remove-leading-slash.js";function m(t,o,f){const r=o[t];if(r?.to){const i=r.to;return a(i).toLowerCase()===t?null:{to:i,type:r.type,from:t}}const e=u(t,f);if(!e)return null;const c=o[e],l=c?.to;if(!l)return null;let n=l;if(n.endsWith("*")){const i=e.split("*")[0];n=n.replace(/\*$/,t.substring(i.length))}return a(n).toLowerCase()===t?null:{...c,to:n,from:e}}function u(t,o){const f=d(t).split("/");let r=o;for(const e of f){if(!r[e])break;r=r[e]}return r["*"]||null}export{m as findRedirect};
@@ -0,0 +1,9 @@
1
+ import type { RedirectsConfig } from '@redocly/config';
2
+ import type { FollowRedirectChainResult, WildcardRedirectsTree } from '../../types';
3
+ /**
4
+ * Follows the redirect chain from startSlug. Returns when:
5
+ * - A cycle is detected (revisiting a slug or redirect rule) -> { type: 'cycle', cycle }
6
+ * - No redirect / external / wildcard -> { type: 'no-cycle' }
7
+ */
8
+ export declare function followRedirectChain(startSlug: string, initialChain: string[], redirects: RedirectsConfig, wildcardRedirectsTree: WildcardRedirectsTree, resolveWildcards?: boolean): FollowRedirectChainResult;
9
+ //# sourceMappingURL=follow-redirect-chain.d.ts.map
@@ -0,0 +1 @@
1
+ import{normalizeRouteSlug as a}from"../../../utils/path/normalize-route-slug.js";import{isLocalLink as p}from"../../../utils/path/is-local-link.js";import{findRedirect as u}from"./find-redirect.js";function x(r,n,c,y,d=!0){const f=new Set(n),i=new Set,e=[...n];function l(o){if(f.has(o)){const m=e.indexOf(o);return{type:"cycle",cycle:m>=0?e.slice(m).concat(o):[]}}f.add(o),e.push(o);const t=d?u(o,c,y):c[o]?.to?{to:c[o].to,from:o}:null;if(!t?.to||!p(t.to))return{type:"no-cycle"};if(t.from){if(i.has(t.from))return{type:"cycle",cycle:[...e,t.from,t.to,t.from]};i.add(t.from)}const s=a(t.to).toLowerCase();return s.endsWith("*")?{type:"no-cycle"}:l(s)}return l(r)}export{x as followRedirectChain};
@@ -0,0 +1,8 @@
1
+ import type { Store } from '../../store';
2
+ /**
3
+ * Validates redirects configuration: detects self-redirects, circular redirects,
4
+ * and redirects that point to a non-existent page. Reports each issue
5
+ * via the link checker so they appear in validation output.
6
+ */
7
+ export declare function validateRedirects(store: Store): void;
8
+ //# sourceMappingURL=validate-redirects.d.ts.map
@@ -0,0 +1 @@
1
+ import h from"node:path";import{existsSync as R,lstatSync as w,readdirSync as N}from"node:fs";import{CONFIG_FILE_NAME as y}from"../../../constants/common.js";import{PUBLIC_STATIC_FOLDER as F}from"../../constants/common.js";import{normalizeRouteSlug as s}from"../../../utils/path/normalize-route-slug.js";import{isLocalLink as C}from"../../../utils/path/is-local-link.js";import{reporter as T}from"../../tools/notifiers/reporter.js";import{followRedirectChain as k}from"./follow-redirect-chain.js";function D(e){const i=e.getConfig().redirects;if(!i)return;const o=e.getGlobalConfig("wildcardRedirectsTree")??{},c=e.getGlobalConfig("originalRedirectSources");for(const[r,l]of Object.entries(i)){const t=l?.to;if(!t||c&&!c.includes(r))continue;const d=r.toLowerCase(),L=t.toLowerCase(),m=r.endsWith("*"),f=t.endsWith("*");if(f)continue;const u=a=>{T.reportBrokenLink({type:"BROKEN_LINK",brokenLinkType:"LINK",sourceFileRelativePath:y,sourceFileLocation:{line:0},title:r,link:t,rawLink:t,message:a})};if(z(r,t,m,f)){u(`Redirect from "${r}" points to the same page. This causes an infinite redirect loop.`);continue}if(m&&!f&&C(t)){const a=s(r.split("*")[0]).toLowerCase(),p=s(L);if(a===p){u(`Circular redirect: "${r}" points to the same base path "${t}", causing an infinite redirect loop.`);continue}}if(!m&&!f&&C(t)){const a=s(d),p=s(L),g=k(p,[a],i,o,!1);if(g.type==="cycle"&&g.cycle.length>0){u(`Circular redirect: ${g.cycle.join(" \u2192 ")}.`);continue}}C(t)&&I(t,e)&&u(`Redirect target "${t}" does not exist. Check that the page or route exists.`)}}function z(e,n,i,o){if(!i&&!o){const c=s(e).toLowerCase(),r=s(n).toLowerCase();return c===r}return!1}function I(e,n){const i=s(e).toLowerCase();return n.slugHasRouteOrRedirect(i)?!1:!v(e,n)}function v(e,n){const o=decodeURI(e.split("?")[0].split("#")[0]).replace(/^\/+/,"");if(!o)return!1;const c=n.contentDir;return c?S(c,o)||S(h.join(c,F),o):!1}function S(e,n){const i=x(e,n);return i?P(i):!1}function x(e,n){const i=n.split("/").filter(Boolean);let o=e;for(const c of i){const r=h.join(o,c);if(R(r)){o=r;continue}let l;try{l=N(o)}catch{return null}const t=l.find(d=>d.toLowerCase()===c.toLowerCase());if(!t)return null;o=h.join(o,t)}return o}function P(e){if(!R(e))return!1;try{return w(e).isFile()}catch{return!1}}export{D as validateRedirects};
@@ -1 +1 @@
1
- import{envConfig as c}from"../../../config/env-config.js";import{getClientIp as v}from"../../utils/get-client-ip.js";import{PRODUCT_NAME as d}from"../../../../config/product-gates.js";import{toAttribute as t,getAttributesStringValue as g}from"./otlp.js";const p=c.OTEL_TRACES_URL||"https://otel.cloud.redocly.com/v1/traces";async function T(e){const o=await e.req.json(),r=m(e),s={resourceSpans:o.resourceSpans.map(n=>{const u=g(n.resource.attributes.find(i=>i.key==="session_id"));return u?{...n,resource:{...n.resource,attributes:[...n.resource.attributes,...y(r,u)]},scopeSpans:n.scopeSpans.map(i=>({...i,spans:i.spans.map(a=>({...a,attributes:a.name.startsWith("event.")&&a.name!=="event.undefined"?A(a,r,u):a.attributes}))}))}:n})};return await fetch(p,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s)}),e.newResponse(null,200,{})}function m(e){const o=e.get("auth")?.claims?.id||e.get("auth")?.claims?.sub,r=v(e.req.raw)||e.req.raw.context.remoteAddr?.hostname,s=e.req.raw.headers.get("user-agent"),n=e.req.raw.headers.get("accept-language"),u=n?.split(",")[0];return{userId:o,clientIp:r,userAgent:s||void 0,acceptLanguage:n||void 0,locale:u}}function y(e,o){const r=[t("redocly.organization.id",c.ORGANIZATION_ID),t("redocly.organization.slug",c.ORGANIZATION_SLUG),t("redocly.project.id",c.PROJECT_ID),t("redocly.project.slug",c.PROJECT_SLUG),t("redocly.product.type",d.toLowerCase()),t("redocly.client.ip",e.clientIp),t("redocly.client.userAgent",e.userAgent),t("redocly.client.acceptLanguage",e.acceptLanguage),t("redocly.client.locale",e.locale)];return e.userId?r.push(t("redocly.user.id",e.userId)):r.push(t("redocly.anonymous.id",l(o))),r.filter(s=>s!==void 0)}function f(e,o,r){const s=b(e.userId,o),n=new Date(Math.floor(Number(r.startTimeUnixNano)/1e6)).toISOString(),u=r.attributes.find(_=>_.key==="cloudevents.event_data.uri"),i=u&&"stringValue"in u.value?[t("cloudevents.event_data.page.uri",u.value.stringValue)]:[];return[t("cloudevents.event_spec_version","1.0"),t("cloudevents.event_object","event"),t("cloudevents.event_origin","realm-ui"),t("cloudevents.event_source",s.uri),t("cloudevents.event_source_details.id",s.id),t("cloudevents.event_source_details.object",s.object),t("cloudevents.event_source_details.uri",s.uri),t("cloudevents.event_data_content_type","application/json; charset=utf-8"),t("cloudevents.event_organization_id",c.ORGANIZATION_ID),t("cloudevents.event_organization_slug",c.ORGANIZATION_SLUG),t("cloudevents.event_project_id",c.PROJECT_ID),t("cloudevents.event_project_slug",c.PROJECT_SLUG),t("cloudevents.event_product_type",d.toLowerCase()),t("cloudevents.event_session_id",o),t("cloudevents.event_time",n),t("cloudevents.event_client.ip",e.clientIp),t("cloudevents.event_client.user_agent",e.userAgent),t("cloudevents.event_client.accept_language",e.acceptLanguage),t("cloudevents.event_client.locale",e.locale),...i]}function A(e,o,r){return[...e.attributes.filter(n=>{const u="stringValue"in n.value&&n.value.stringValue==="",i=/cloudevents\.event_source_details\..+/.test(n.key);return!(u||i)}),...f(o,r,e)].filter(n=>n!==void 0)}function b(e,o){return e?{id:e,object:"user",uri:`${c.MAIN_API_URL}/users/${e}`}:{id:l(o),object:"anonymous",uri:`${c.MAIN_API_URL}/anonymous/${l(o)}`}}function l(e){return e.replace("ses_","ann_")}export{T as otelTracesHandler,A as toCloudEventAttributes,b as toSource};
1
+ import{envConfig as c}from"../../../config/env-config.js";import{getClientIp as v}from"../../utils/get-client-ip.js";import{toAttribute as t,getAttributesStringValue as _}from"./otlp.js";const g=c.OTEL_TRACES_URL||"https://otel.cloud.redocly.com/v1/traces";async function h(e){const s=await e.req.json(),u=m(e),o={resourceSpans:s.resourceSpans.map(n=>{const r=_(n.resource.attributes.find(i=>i.key==="session_id"));return r?{...n,resource:{...n.resource,attributes:[...n.resource.attributes]},scopeSpans:n.scopeSpans.map(i=>({...i,spans:i.spans.map(a=>({...a,attributes:a.name.startsWith("event.")&&a.name!=="event.undefined"?b(a,u,r):a.attributes}))}))}:n})};return await fetch(g,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(o)}),e.newResponse(null,200,{})}function m(e){const s=e.get("auth")?.claims?.id||e.get("auth")?.claims?.sub,u=v(e.req.raw)||e.req.raw.context.remoteAddr?.hostname,o=e.req.raw.headers.get("user-agent"),n=e.req.raw.headers.get("accept-language"),r=n?.split(",")[0];return{userId:s,clientIp:u,userAgent:o||void 0,acceptLanguage:n||void 0,locale:r}}function p(e,s,u){const o=f(e.userId,s),n=new Date(Math.floor(Number(u.startTimeUnixNano)/1e6)).toISOString(),r=u.attributes.find(d=>d.key==="cloudevents.event_data.uri"),i=r&&"stringValue"in r.value?[t("cloudevents.event_data.page.uri",r.value.stringValue)]:[];return[t("cloudevents.event_spec_version","1.0"),t("cloudevents.event_object","event"),t("cloudevents.event_origin","realm-ui"),t("cloudevents.event_env",c.redoclyEnv),t("cloudevents.event_source",o.uri),t("cloudevents.event_source_details.id",o.id),t("cloudevents.event_source_details.object",o.object),t("cloudevents.event_source_details.uri",o.uri),t("cloudevents.event_actor.id",o.id),t("cloudevents.event_actor.object",o.object),t("cloudevents.event_actor.uri",o.uri),t("cloudevents.event_data_content_type","application/json; charset=utf-8"),t("cloudevents.event_organization_id",c.ORGANIZATION_ID),t("cloudevents.event_organization_slug",c.ORGANIZATION_SLUG),t("cloudevents.event_project_id",c.PROJECT_ID),t("cloudevents.event_project_slug",c.PROJECT_SLUG),t("cloudevents.event_session_id",s),t("cloudevents.event_time",n),t("cloudevents.event_client_ip",e.clientIp),t("cloudevents.event_user_agent",e.userAgent),...i]}function b(e,s,u){return[...e.attributes.filter(n=>{const r="stringValue"in n.value&&n.value.stringValue==="",i=/cloudevents\.event_source_details\..+/.test(n.key);return!(r||i)}),...p(s,u,e)].filter(n=>n!==void 0)}function f(e,s){return e?{id:e,object:"user",uri:`${c.MAIN_API_URL}/users/${e}`}:{id:l(s),object:"anonymous",uri:`${c.MAIN_API_URL}/anonymous/${l(s)}`}}function l(e){return e.replace("ses_","ann_")}export{h as otelTracesHandler,b as toCloudEventAttributes,f as toSource};
@@ -1,7 +1,7 @@
1
1
  import type { ApiRoutesWorkerParams, ApiRoutesWorkerResponse } from '../types/plugins/api-routes.js';
2
2
  import type { RenderPayload } from '../../types/ssr.js';
3
3
  import type { ScorecardsWorkerParams, ScorecardsWorkerResponse } from '../types/plugins/scorecards.js';
4
- import type { McpToolWorkerParams, McpToolWorkerResponse } from '../plugins/mcp/types.js';
4
+ import type { McpToolExecutionParams, McpToolWorkerResponse } from '../plugins/mcp/types.js';
5
5
  import type { SCORECARDS_WORKER_KEY } from './scorecards-worker-pool.js';
6
6
  import type { API_ROUTES_WORKER_KEY } from './api-routes-worker-pool.js';
7
7
  import type { SSR_WORKER_KEY } from './ssr-worker-pool.js';
@@ -25,7 +25,7 @@ export type WorkerTypeMapping = {
25
25
  response: ScorecardsWorkerResponse;
26
26
  };
27
27
  [MCP_TOOL_WORKER_KEY]: {
28
- params: [McpToolWorkerParams];
28
+ params: [McpToolExecutionParams];
29
29
  response: McpToolWorkerResponse;
30
30
  };
31
31
  };
@@ -1 +1 @@
1
- import s from"workerpool";import{envConfig as l}from"../config/env-config.js";import{fromCurrentDir as n}from"../utils/paths.js";class f{#t=null;#o;constructor(o){this.#o=o,this.#o.lazy||(this.#t=this.#i())}#i(){const{workerScript:o,lazy:e,...i}=this.#o;let t=o;return!t.endsWith(".js")&&!t.endsWith(".mjs")&&(t=n(import.meta.url,`${t}.${l.isDevelopMode?"js":"mjs"}`)),s.pool(t,{...i})}#r(){return this.#t||(this.#t=this.#i()),this.#t}async exec(o,e,i){let r=this.#r().exec(o,e);return i?.timeout&&(r=r.timeout(i.timeout)),await r}async terminate(){this.#t&&(await this.#t.terminate(),this.#t=null)}}export{f as WorkerPool};
1
+ import n from"workerpool";import{basename as a,dirname as s,resolve as l}from"node:path";import{fileURLToPath as h}from"node:url";import{envConfig as m}from"../config/env-config.js";class w{#t=null;#r;constructor(o){this.#r=o,this.#r.lazy||(this.#t=this.#o())}#o(){const{workerScript:o,lazy:t,...r}=this.#r;let e=this.#e(o);return n.pool(e,{...r})}#e(o){let t=o;if(!t.endsWith(".js")&&!t.endsWith(".mjs")&&(t=`${t}.${m.isDevelopMode?"js":"mjs"}`),!t.startsWith("."))return t;const r=s(h(import.meta.url)),e=a(r)==="chunks"?s(r):r;return l(e,t)}#i(){return this.#t||(this.#t=this.#o()),this.#t}async exec(o,t,r){let i=this.#i().exec(o,t);return r?.timeout&&(i=i.timeout(r.timeout)),await i}async terminate(){this.#t&&(await this.#t.terminate(),this.#t=null)}}export{w as WorkerPool};
@@ -1,4 +1,4 @@
1
- import type { AuthProviderType, REDOCLY_TEAMS_RBAC, RbacScopeItems } from '@redocly/config';
1
+ import type { AuthProviderType, REDOCLY_TEAMS_RBAC, REDOCLY_ROUTE_RBAC, RbacScopeItems } from '@redocly/config';
2
2
  import type { UiAccessibleConfig } from '@redocly/config';
3
3
  export type GlobalData = UiAccessibleConfig & {
4
4
  authIdps?: Array<{
@@ -8,7 +8,12 @@ export type GlobalData = UiAccessibleConfig & {
8
8
  rbac?: object;
9
9
  apiProducts?: {
10
10
  [apiProductId: string]: {
11
- slug: string;
11
+ slug?: string;
12
+ [REDOCLY_TEAMS_RBAC]?: RbacScopeItems;
13
+ [REDOCLY_ROUTE_RBAC]?: {
14
+ slug?: string;
15
+ fsPath?: string;
16
+ };
12
17
  };
13
18
  };
14
19
  l10n?: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@redocly/reef",
3
- "version": "0.132.0-next.5",
3
+ "version": "0.132.0-next.7",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "bin": {
@@ -29,7 +29,7 @@
29
29
  "@opentelemetry/sdk-trace-web": "2.0.1",
30
30
  "@opentelemetry/semantic-conventions": "1.34.0",
31
31
  "@redocly/ajv": "8.18.0",
32
- "@redocly/openapi-core": "2.24.0",
32
+ "@redocly/openapi-core": "2.25.2",
33
33
  "@shikijs/transformers": "3.21.0",
34
34
  "@tanstack/react-query": "5.62.3",
35
35
  "@tanstack/react-table": "8.21.3",
@@ -67,7 +67,7 @@
67
67
  "openapi-sampler": "^1.7.2",
68
68
  "os-browserify": "0.3.0",
69
69
  "path-browserify": "1.0.1",
70
- "picomatch": "2.3.1",
70
+ "picomatch": "2.3.2",
71
71
  "react": "^19.2.4",
72
72
  "react-calendar": "5.1.0",
73
73
  "react-date-picker": "11.0.0",
@@ -91,14 +91,14 @@
91
91
  "xpath": "0.0.34",
92
92
  "yaml-ast-parser": "0.0.43",
93
93
  "zod": "^3.25.76",
94
- "@redocly/asyncapi-docs": "1.9.0-next.4",
95
- "@redocly/config": "0.44.2",
96
- "@redocly/graphql-docs": "1.9.0-next.4",
97
- "@redocly/openapi-docs": "3.20.0-next.4",
94
+ "@redocly/asyncapi-docs": "1.9.0-next.6",
95
+ "@redocly/config": "0.46.1",
96
+ "@redocly/graphql-docs": "1.9.0-next.6",
97
+ "@redocly/openapi-docs": "3.20.0-next.6",
98
98
  "@redocly/portal-legacy-ui": "0.15.0-next.0",
99
- "@redocly/portal-plugin-mock-server": "0.17.0-next.4",
100
- "@redocly/realm-asyncapi-sdk": "0.10.0-next.0",
101
- "@redocly/theme": "0.64.0-next.2"
99
+ "@redocly/portal-plugin-mock-server": "0.17.0-next.6",
100
+ "@redocly/realm-asyncapi-sdk": "0.10.0-next.1",
101
+ "@redocly/theme": "0.64.0-next.4"
102
102
  },
103
103
  "peerDependencies": {
104
104
  "react": "^19.2.4",
@@ -1,4 +0,0 @@
1
- export declare const cache: Record<string, string>;
2
- export declare function generateDiagramHash(diagram: string): string;
3
- export declare function renderMermaid(nodes: string[], theme?: string): Promise<string[]>;
4
- //# sourceMappingURL=render-mermaid.d.ts.map
@@ -1 +0,0 @@
1
- import{nanoid as R}from"nanoid";import{envConfig as i}from"../../../../config/env-config.js";import{logger as h}from"../../../../tools/notifiers/logger.js";import{sha as g}from"../../../../utils/crypto/sha.js";const s={};function c(t){if(t.toLowerCase().includes("gantt")&&!t.toLowerCase().includes("todaymarker off")){const o=new Date().toISOString().split("T")[0];return g(t+o)}return g(t)}async function O(t,d="default"){if(t.length===0)return[];const r=[];for(let e=0;e<t.length;e++){const n=c(t[e]);s[n]||r.push(t[e])}if(r.length){const e=i.REDOCLY_MERMAID_MICROSERVICE_URL||"https://api.redocly.com/mermaid",n=h.startTiming(),f=R(),m=await fetch(e,{method:"POST",headers:{"Content-Type":"application/json","x-request-id":i.REQUEST_ID||""},body:JSON.stringify({definitions:r,rayId:f,theme:d,organizationId:i.ORGANIZATION_ID})});if(m.status!==200)throw new Error(`Something went wrong during remote rendering. Please, save this Ray ID: ${f} and contact Redocly team.`);h.verboseTime(n,"Rendered mermaid diagrams (%s)",r.length);const l=await m.json();for(let a=0;a<r.length;a++){const p=c(r[a]);s[p]=l[a]}}const o=[];for(let e=0;e<t.length;e++){const n=c(t[e]);o.push(s[n])}return o}export{s as cache,c as generateDiagramHash,O as renderMermaid};
@@ -1,55 +0,0 @@
1
- import type { JSONSchemaType } from '@redocly/ajv';
2
- import type { McpServer } from '@redocly/mcp-typescript-sdk/server/mcp.js';
3
- import type { OpenAPIDefinition } from '@redocly/openapi-docs';
4
- import type { AccessInfo, ApiDescriptionInfo, McpToolWorkerParams, McpToolWorkerResponse, ToolArgsMap } from '../../types.js';
5
- export type DocsMcpToolRegistrationOptions = {
6
- server: McpServer;
7
- baseUrl: string;
8
- outdir: string;
9
- apiDescriptionsMap: Record<string, ApiDescriptionInfo>;
10
- headers?: Record<string, string | string[] | undefined>;
11
- accessInfo: AccessInfo;
12
- products?: string[];
13
- };
14
- /** Keys that can be passed to the tool context (excludes 'server' which is not serializable) */
15
- export type ContextKey = Exclude<keyof DocsMcpToolRegistrationOptions, 'server'>;
16
- export type ApiDefinitionResult = {
17
- success: true;
18
- definition: OpenAPIDefinition;
19
- } | {
20
- success: false;
21
- response: McpToolWorkerResponse;
22
- };
23
- export declare abstract class DocsMcpTool<TName extends keyof ToolArgsMap> {
24
- abstract readonly name: TName;
25
- abstract readonly description: string;
26
- readonly schema: JSONSchemaType<ToolArgsMap[TName]>;
27
- /**
28
- * Array of context keys that this tool requires.
29
- * The base class will extract these from DocsMcpToolRegistrationOptions
30
- * and pass them to executeAction.
31
- */
32
- abstract readonly requiredContext: readonly ContextKey[];
33
- constructor(schema: JSONSchemaType<ToolArgsMap[TName]>);
34
- /**
35
- * Builds the context object by picking only the required keys from options.
36
- */
37
- protected getContext(options: DocsMcpToolRegistrationOptions): McpToolWorkerParams['context'];
38
- register(options: DocsMcpToolRegistrationOptions): void;
39
- /**
40
- * Wraps the tool execution with telemetry and error handling.
41
- * Subclasses should call this method and implement executeAction for the actual logic.
42
- */
43
- execute(args: ToolArgsMap[TName], context: McpToolWorkerParams['context']): Promise<McpToolWorkerResponse>;
44
- /**
45
- * Implement the actual tool logic here. Called by execute() which handles telemetry.
46
- */
47
- protected abstract executeAction(args: ToolArgsMap[TName], context: McpToolWorkerParams['context']): Promise<McpToolWorkerResponse>;
48
- /**
49
- * Helper method for tools that need to load an API definition.
50
- * Handles finding the API by name and loading the definition from the file system.
51
- * Requires 'outdir' and 'accessInfo' in requiredContext.
52
- */
53
- protected getApiDefinition(name: string, context: McpToolWorkerParams['context']): Promise<ApiDefinitionResult>;
54
- }
55
- //# sourceMappingURL=docs-mcp-tool.d.ts.map
@@ -1 +0,0 @@
1
- import{telemetry as o}from"../../../../telemetry/index.js";import{mcpToolWorkers as n,MCP_TOOL_WORKER_KEY as a}from"../../../../workers/mcp-tool-worker-pool.js";import{findApiDescriptionByName as p}from"../utils.js";import{getApiDescriptionFromFs as m}from"./utils.js";function u(i,t,s){return{toolName:i,args:t,context:s}}class g{schema;constructor(t){this.schema=t}getContext(t){const s={};for(const e of this.requiredContext)s[e]=t[e];return{...s,apiDescriptionsMap:t.apiDescriptionsMap}}register(t){const s=async(e,r)=>{const c=u(this.name,e,this.getContext(t));return await n.exec(a,[c],{timeout:6e4})};t.server.tool(this.name,this.description,this.schema,s)}async execute(t,s){try{const e=await this.executeAction(t,s);return e.isError?o.sendMcpErrorMessage([{object:"mcp_server",server_type:"docs",tool:this.name,message:`${e.content.map(({text:r})=>r).join(" ")}`,stack:""}]):o.sendMcpToolCalledMessage([{object:"mcp_server",server_type:"docs",tool:this.name}]),e}catch(e){throw o.sendMcpErrorMessage([{object:"mcp_server",server_type:"docs",tool:this.name,message:e instanceof Error?e.message:String(e),stack:e instanceof Error&&e.stack||""}]),e}}async getApiDefinition(t,s){if(!s.outdir||!s.accessInfo)throw new Error("Missing required context: outdir and accessInfo");const e=p(s.apiDescriptionsMap,t);if(!e)return{success:!1,response:{content:[{type:"text",text:`No API found matching "${t}".`}]}};const r=await m({relativePath:e.relativePath||"",outdir:s.outdir,accessInfo:s.accessInfo});return r?{success:!0,definition:r}:{success:!1,response:{content:[{type:"text",text:`Spec not found from the file system with "${t}".`}]}}}}export{g as DocsMcpTool};
@@ -1,11 +0,0 @@
1
- import type { ApiFunctionsContext, ApiRoutesHandler, PageStaticData } from '@redocly/config';
2
- import type { McpServerInstance, McpServerType } from '../types.js';
3
- export type McpRequestHandlerDependencies = {
4
- createServerInstance: (context: ApiFunctionsContext, staticData: PageStaticData, headers: Record<string, string | string[] | undefined>, request: Request) => Promise<McpServerInstance>;
5
- serverType: McpServerType;
6
- };
7
- /**
8
- * Creates a standardized MCP request handler
9
- */
10
- export declare function createMcpRequestHandler(dependencies: McpRequestHandlerDependencies): ApiRoutesHandler;
11
- //# sourceMappingURL=mcp-request-handler.d.ts.map
@@ -1 +0,0 @@
1
- import{toFetchResponse as p,toReqRes as h}from"fetch-to-node";import{createMethodNotAllowedError as w,withErrorHandling as y}from"./errors.js";function m(s){const{createServerInstance:a,serverType:c}=s;return async(e,d,i)=>{let r;return y(async()=>{const n={};e.headers.forEach((t,l)=>{n[l]=t});const{req:u,res:o}=h(e);switch(e.method){case"GET":return new Response(JSON.stringify({error:"Method Not Allowed",message:`In order to use this MCP server, you need register it in your MCP Client (VS Code, Cursor, Claude Code, etc.) using that URL: ${e.url}`}),{status:405,headers:{"Content-Type":"application/json"}});case"POST":{r=await a(d,i,n,e);const t=await e.json();return await r.transport.handleRequest(u,o,t),p(o)}default:return w()}},c,async()=>{r&&(await r.cleanup(),r=void 0)})}}export{m as createMcpRequestHandler};
@@ -1,17 +0,0 @@
1
- import { McpServer } from '@redocly/mcp-typescript-sdk/server/mcp.js';
2
- import { StreamableHTTPServerTransport } from '@redocly/mcp-typescript-sdk/server/streamableHttp.js';
3
- import type { Implementation } from '@redocly/mcp-typescript-sdk/types.js';
4
- import type { McpServerInstance, McpServerType } from '../types.js';
5
- export declare abstract class BaseMcpServer {
6
- #private;
7
- protected server: McpServer;
8
- protected transport: StreamableHTTPServerTransport;
9
- constructor(config: Implementation);
10
- protected abstract registerTools(): void;
11
- initialize(): Promise<McpServerInstance>;
12
- clearCleanupTimeout(): void;
13
- cleanup(): Promise<void>;
14
- protected abstract getServerType(): McpServerType;
15
- }
16
- export declare function createMcpServerInstance<T extends BaseMcpServer>(serverClass: new (...args: any[]) => T, ...args: any[]): Promise<McpServerInstance>;
17
- //# sourceMappingURL=base-server.d.ts.map
@@ -1 +0,0 @@
1
- import{McpServer as t}from"@redocly/mcp-typescript-sdk/server/mcp.js";import{StreamableHTTPServerTransport as s}from"@redocly/mcp-typescript-sdk/server/streamableHttp.js";import{telemetry as i}from"../../../telemetry/index.js";class p{server;transport;#r;#t=!1;constructor(e){this.server=new t(e,{capabilities:{logging:{}}}),this.transport=new s({sessionIdGenerator:void 0})}async initialize(){return this.registerTools(),await this.server.connect(this.transport),{server:this.server,transport:this.transport,cleanup:this.cleanup.bind(this)}}clearCleanupTimeout(){this.#r&&(clearTimeout(this.#r),this.#r=void 0)}#e;async cleanup(){return this.#e?this.#e:(this.#e=this.#s(),this.#e)}async#s(){if(!this.#t){this.#t=!0,this.clearCleanupTimeout();try{this.transport.close()}catch(e){throw i.sendMcpErrorMessage([{object:"mcp_server",server_type:this.getServerType(),message:e?.message||"Unknown cleanup error",stack:e?.stack||""}]),e}}}}async function h(r,...e){return await new r(...e).initialize()}export{p as BaseMcpServer,h as createMcpServerInstance};