@redocly/revel 0.139.0-next.10 → 0.139.0-next.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # @redocly/revel
2
2
 
3
+ ## 0.139.0-next.11
4
+
5
+ ### Patch Changes
6
+
7
+ - b4edb142025: Updated `@redocly/openapi-core` to version `2.66.0`.
8
+ - 250163f65ec: Reduced the page actions button to 24px in Markdown pages and API docs, and moved it below the title on mobile devices, so long titles use the full width of the screen.
9
+ - b82ff0e046f: Fixed an issue where a wildcard redirect to a file in the `static` folder returned a 404 error when the file name contained uppercase characters.
10
+ - Updated dependencies [9a8eefed65a]
11
+ - Updated dependencies [b4edb142025]
12
+ - Updated dependencies [250163f65ec]
13
+ - Updated dependencies [d888b826a0c]
14
+ - @redocly/api-docs@0.4.0-next.11
15
+ - @redocly/theme@0.71.0-next.7
16
+ - @redocly/portal-plugin-mock-server@0.24.0-next.3
17
+
3
18
  ## 0.139.0-next.10
4
19
 
5
20
  ### Patch Changes
@@ -1 +1 @@
1
- import{REDOCLY_ROUTE_RBAC as w,REDOCLY_TEAMS_RBAC as v}from"@redocly/config";import{mcpTagSchemas as et,schemaDefinitionTag as ot,markdocParser as U}from"@redocly/api-docs";import{withPathPrefix as q}from"@redocly/theme/core/utils";import{API_DOCS_TEMPLATE_ID as V,GRAPHQL_SPEC_SLUG as rt,PUBLIC_RBAC_SCOPE_ITEM as x}from"../../../constants/common.js";import{DEPRECATED_PUBLIC_API_DEFINITIONS_FOLDER as at,PUBLIC_API_DEFINITIONS_FOLDER as st}from"../../constants/common.js";import{API_DOCS_SHARED_DATA_PREFIX as E}from"../../constants/plugins/api-docs.js";import{fromCurrentDir as it}from"../../utils/paths.js";import{normalizeRouteSlug as nt}from"../../../utils/path/normalize-route-slug.js";import{isTranslationFallback as ct}from"../../fs/utils/is-translation-fallback.js";import{createSlugify as pt}from"../create-slugify.js";import{apiDocLoader as ut,apiDocsLoader as lt}from"./loader.js";import{getTemplatePath as j}from"./get-template-path.js";import{storeDefinitionBundles as dt}from"./store-definition-bundles.js";import{telemetryTraceStep as mt}from"../../../cli/telemetry/helpers/trace-step.js";import{searchResolver as ft}from"./search/search-resolver.js";import{getAiDocumentsStore as ht}from"./search/get-ai-search-documents.js";import{getApiConfigByPath as gt}from"../get-api-config.js";import{getRouteSlugsForPath as Dt}from"../utils.js";import{collectItemRoutes as St}from"./utils/collect-item-routes.js";import{isChunkCurrent as Pt}from"./utils/decorators.js";import{applyNavItemToRoot as yt}from"./utils/apply-nav-item-to-root.js";import{buildRoutesMapping as It}from"./utils/build-routes-mapping.js";import{buildItemPositions as At}from"./utils/build-item-positions.js";import{resolveApiDocTitle as vt}from"./utils/resolve-api-doc-title.js";import{resolveConfigRbac as bt}from"./utils/resolve-config-rbac.js";import{relativePathToBaseSlug as Rt}from"./utils/relative-path-to-base-slug.js";import{normalizeApiVersion as _t}from"./utils/normalize-api-version.js";import{importApiDocsBuilder as W}from"./import-api-docs-builder.js";import{envConfig as $}from"../../config/env-config.js";import{logger as Ct}from"../../tools/notifiers/logger.js";const T="openapi-spec-download",wt={asyncapi:"AsyncAPI Docs",graphql:"GraphQL Docs",openapi:"OpenAPI Docs"};async function ue(){let e=[],r=new Map;const s=new WeakMap;let n=new Set,m={};function k(o,h,A){const y=s.get(o)??new Map;s.set(o,y);const g=h??"";return y.get(g)===A?!1:(y.set(g,A),!0)}return{id:"api-docs",requiredEntitlements:["openapi","asyncapi","graphql"],loaders:{"api-doc":ut,"api-docs":lt},processContent:async(o,h)=>{await mt("com.redocly.build.plugin.apiDocs",async()=>{o.createRequestHandler(T,it(import.meta.url,"./spec-download.api.js")),o.addApiRoute({slug:st+"/*",requestHandlerId:T,httpMethod:"all",[v]:x,getStaticData:async()=>({props:{}})}),o.addApiRoute({slug:at+"/*",requestHandlerId:T,httpMethod:"all",[v]:x,getStaticData:async()=>({props:{}})}),o.addApiRoute({slug:rt+"/*",requestHandlerId:T,httpMethod:"all",[v]:x,getStaticData:async()=>({props:{}})});const A=o.createTemplate(V,j("../../../client/templates/api-docs/template.js")),y=o.registerServerPropsGetter(V,j("./get-server-props.js")),g=await h.getConfig();r=new Map,m={};const I=await o.loadApiDocuments(h);dt(I,o.outdir);const C=!!g.plugins?.some(t=>typeof t=="string"&&t.startsWith("@redocly/portal-plugin-async-api/"));C&&I.some(t=>t.type==="asyncapi")&&Ct.warn("The plugin '@redocly/portal-plugin-async-api' is deprecated. Please remove it from your config to use built-in AsyncAPI docs.");const c=C?I.filter(t=>t.type!=="asyncapi"):I;e=c.map(({markdocChunks:t,relativePath:P,isVirtual:p,customOutputRelativeFile:a,realRelativePath:f})=>({chunks:t??[],relativePath:P,realRelativePath:f,isVirtual:a!=null||p}));const{buildItems:i}=await W(o.serverOutDir),D=(await h.cache.load("content-slugs","content-slugs")).data,S=pt(D),F=t=>nt(S(t));for(const t of c){const P=t.customOutputRelativeFile||t.relativePath,p=F(P);kt(t,p);const{items:a,store:f}=await i({type:t.type,document:t.document,options:t.options,basePath:p,markdownParser:U}),b=`${E}${t.relativePath}`,O=$.isDevelopMode?t.relativePath:void 0,u=Ot(t.document),R=u?.["x-metadata"],_=t.isVirtual?void 0:R?.apiId,N={document:t,basePath:p,sourcePath:O,apiId:_};await o.createSharedData(b,Q(N,a,f));const K=bt(t.config),M=!!t.options.excludeFromSearch,Y=t.type==="openapi",X=St(a,K),J=ct(t),d=X.map(l=>{const B=l.metadata?.seo,H={...Ft(l.link,p),fsPath:P,templateId:A,sharedData:[{key:"apiDocsStore",id:b}],serverPropsGetterIds:[y],excludeFromSearch:M,getStaticData:Tt(l.label,B,J),[v]:l[v]};return Y?{...H,...l.httpVerb?{httpVerb:l.httpVerb,metadata:{subType:"openapi-operation"}}:{}}:H});if(!d.length)continue;const G=vt(u,t.type,a),Z=_t(u?.version),L={type:t.type,title:G,version:Z,description:typeof u?.description=="string"?u.description:void 0,summary:typeof u?.summary=="string"?u.summary:void 0,...u?.["x-metadata"]&&typeof u["x-metadata"]=="object"?u["x-metadata"]:{}};d[0]={...d[0],metadata:L,hasClientRoutes:!0,getSidebar:(l,B)=>yt(z(a),p,B),getNavText:()=>G??wt[t.type]??"API Docs",getSearchDocuments:ft(a,L,o.getSearchFacets,o.setSearchFacets,M,f,t.document),getAiDocumentsStore:ht({items:a,metadata:L,store:f,document:t.document,specType:t.type,excludeFromSearch:M,basePath:p,getSearchFacets:o.getSearchFacets,markdocTags:{...et,schemaDefinition:ot}})};const tt=d[0];d[0]=d[d.length-1],d[d.length-1]=tt;for(const l of d)o.addRoute(l);if(_){const l=gt(t.config?.apis,t.realRelativePath);m[_]={[v]:l.rbac,[w]:{fsPath:P}}}r.set(b,N)}})},afterRoutesCreated:async(o,h)=>{const{buildItems:A,simplifyAstStructure:y}=await W(o.serverOutDir),g=new Set,I=new Set;for(const{chunks:c,relativePath:i,isVirtual:D}of e){const S=`${E}${i}`,F=Dt(o.getAllRoutes(),i);for(const{node:t,markdown:P,pointer:p,key:a,relativePath:f}of c){const{ast:b,compoundHash:O}=await o.parseMarkdoc({input:{content:P,relativePath:f,isVirtual:D},resource:p,context:h,deps:{sharedDataIds:[`${E}${f}`],routeSlugs:F}});if(g.add(p),!(a==="graphql-docs"?t?.description?.value!==void 0:!!a&&Pt(t,a,P))||!k(t,a,O))continue;I.add(S);const R=y(b);if(a==="graphql-docs"){t.description&&(t.description.value=R);const _=`${E}${f}`;Et(r.get(_),R)}else a&&(t[a]=R)}}const C=n.difference(g);for(const c of C)h.cache.delete(c);n=g,Object.entries(m).forEach(([c,i])=>{const D=i[w]?.fsPath;if(!D)return;const S=o.getRouteByFsPath(D)?.baseSlug;m[c]={...i,[w]:{...i[w],slug:S},slug:S}}),o.setGlobalData({apiProducts:m});for(const[c,i]of r){if(!I.has(c))continue;const{items:D,store:S}=await A({type:i.document.type,document:i.document.document,options:i.document.options,basePath:i.basePath,markdownParser:U});await o.createSharedData(c,Q(i,D,S))}}}}function Q({document:e,basePath:r,sourcePath:s,apiId:n},m,k){return{items:m,store:k,options:e.options,baseSlug:r,routesMapping:$.isDevelopMode?It(m,r):{},graphqlPositions:$.isDevelopMode&&e.type==="graphql"?At(m,r):void 0,sourcePath:s,apiId:n}}function Et(e,r){e?.document.type!=="graphql"||!e.document.options||(e.document.options.info={...e.document.options.info||{},description:r})}function Tt(e,r,s){return async function(n){return{...s?{isTranslationFallback:!0}:{},props:{settings:{baseUrlPath:q(n.baseSlug)},disableAutoScroll:!0,seo:{title:e,...r}}}}}function kt(e,r){const s=e.options?.mockServer,n=q(`/_mock${Rt(e.relativePath)}`);s?.url===n&&(e.options={...e.options,mockServer:{...s,url:q(`/_mock${r}`)}})}function Ft(e,r){if(e===r)return{};const s=r==="/"?"/":`${r}/`;if(e.startsWith(s)){const n=e.slice(s.length);return n?{slugSuffix:n}:{}}return{slug:e}}function Ot(e){if(e&&typeof e=="object"&&"info"in e)return e.info}function z(e){return e.map(({content:r,items:s,...n})=>({...n,...s&&{items:z(s)}}))}export{ue as apiDocsPlugin,Ft as toRouteSlugFields};
1
+ import{REDOCLY_ROUTE_RBAC as C,REDOCLY_TEAMS_RBAC as A}from"@redocly/config";import{mcpTagSchemas as ot,schemaDefinitionTag as rt,markdocParser as U}from"@redocly/api-docs";import{withPathPrefix as $}from"@redocly/theme/core/utils";import{API_DOCS_TEMPLATE_ID as j,GRAPHQL_SPEC_SLUG as at,PUBLIC_RBAC_SCOPE_ITEM as N}from"../../../constants/common.js";import{DEPRECATED_PUBLIC_API_DEFINITIONS_FOLDER as st,PUBLIC_API_DEFINITIONS_FOLDER as it}from"../../constants/common.js";import{API_DOCS_SHARED_DATA_PREFIX as E}from"../../constants/plugins/api-docs.js";import{fromCurrentDir as nt}from"../../utils/paths.js";import{normalizeRouteSlug as ct}from"../../../utils/path/normalize-route-slug.js";import{removeTrailingSlash as pt}from"../../../utils/url/remove-trailing-slash.js";import{isTranslationFallback as ut}from"../../fs/utils/is-translation-fallback.js";import{createSlugify as lt}from"../create-slugify.js";import{apiDocLoader as dt,apiDocsLoader as mt}from"./loader.js";import{getTemplatePath as V}from"./get-template-path.js";import{storeDefinitionBundles as ft}from"./store-definition-bundles.js";import{telemetryTraceStep as gt}from"../../../cli/telemetry/helpers/trace-step.js";import{searchResolver as ht}from"./search/search-resolver.js";import{getAiDocumentsStore as Dt}from"./search/get-ai-search-documents.js";import{getApiConfigByPath as St}from"../get-api-config.js";import{getRouteSlugsForPath as Pt}from"../utils.js";import{collectItemRoutes as yt}from"./utils/collect-item-routes.js";import{isChunkCurrent as It}from"./utils/decorators.js";import{applyNavItemToRoot as At}from"./utils/apply-nav-item-to-root.js";import{buildRoutesMapping as vt}from"./utils/build-routes-mapping.js";import{buildItemPositions as bt}from"./utils/build-item-positions.js";import{resolveApiDocTitle as Rt}from"./utils/resolve-api-doc-title.js";import{resolveConfigRbac as W}from"./utils/resolve-config-rbac.js";import{relativePathToBaseSlug as _t}from"./utils/relative-path-to-base-slug.js";import{normalizeApiVersion as Ct}from"./utils/normalize-api-version.js";import{importApiDocsBuilder as Q}from"./import-api-docs-builder.js";import{envConfig as G}from"../../config/env-config.js";import{logger as Tt}from"../../tools/notifiers/logger.js";const k="openapi-spec-download",wt={asyncapi:"AsyncAPI Docs",graphql:"GraphQL Docs",openapi:"OpenAPI Docs"};async function de(){let e=[],r=new Map;const s=new WeakMap;let n=new Set,m={};function O(o,D,v){const y=s.get(o)??new Map;s.set(o,y);const S=D??"";return y.get(S)===v?!1:(y.set(S,v),!0)}return{id:"api-docs",requiredEntitlements:["openapi","asyncapi","graphql"],loaders:{"api-doc":dt,"api-docs":mt},processContent:async(o,D)=>{await gt("com.redocly.build.plugin.apiDocs",async()=>{o.createRequestHandler(k,nt(import.meta.url,"./spec-download.api.js")),o.addApiRoute({slug:it+"/*",requestHandlerId:k,httpMethod:"all",[A]:N,getStaticData:async()=>({props:{}})}),o.addApiRoute({slug:st+"/*",requestHandlerId:k,httpMethod:"all",[A]:N,getStaticData:async()=>({props:{}})}),o.addApiRoute({slug:at+"/*",requestHandlerId:k,httpMethod:"all",[A]:N,getStaticData:async()=>({props:{}})});const v=o.createTemplate(j,V("../../../client/templates/api-docs/template.js")),y=o.registerServerPropsGetter(j,V("./get-server-props.js")),S=await D.getConfig();r=new Map,m={};const I=await o.loadApiDocuments(D);ft(I,o.outdir);const T=!!S.plugins?.some(t=>typeof t=="string"&&t.startsWith("@redocly/portal-plugin-async-api/"));T&&I.some(t=>t.type==="asyncapi")&&Tt.warn("The plugin '@redocly/portal-plugin-async-api' is deprecated. Please remove it from your config to use built-in AsyncAPI docs.");const c=T?I.filter(t=>t.type!=="asyncapi"):I;e=c.map(({markdocChunks:t,relativePath:P,isVirtual:p,customOutputRelativeFile:a,realRelativePath:h})=>({chunks:t??[],relativePath:P,realRelativePath:h,isVirtual:a!=null||p}));const{buildItems:i}=await Q(o.serverOutDir),f=(await D.cache.load("content-slugs","content-slugs")).data,g=lt(f),F=t=>ct(g(t));for(const t of c){const P=t.customOutputRelativeFile||t.relativePath,p=F(P);Ot(t,p);const{items:a,store:h}=await i({type:t.type,document:t.document,options:t.options,basePath:p,markdownParser:U}),b=`${E}${t.relativePath}`,M=G.isDevelopMode?t.relativePath:void 0,u=Mt(t.document),R=u?.["x-metadata"],_=t.isVirtual?void 0:R?.apiId,L={document:t,basePath:p,sourcePath:M,apiId:_,build:{items:a,store:h}};await o.createSharedData(b,z(L,a,h));const Y=W(t.config),B=!!t.options.excludeFromSearch,X=t.type==="openapi",J=yt(a,Y),Z=ut(t),d=J.map(l=>{const x=l.metadata?.seo,w={fsPath:P,templateId:v,sharedData:[{key:"apiDocsStore",id:b}],serverPropsGetterIds:[y],excludeFromSearch:B,getStaticData:kt(l.label,x,Z),[A]:l[A]};return Object.assign(w,Ft(l.link,p)),X&&l.httpVerb&&(w.httpVerb=l.httpVerb,w.metadata={subType:"openapi-operation"}),w});if(!d.length)continue;const H=Rt(u,t.type,a),tt=Ct(u?.version),q={type:t.type,title:H,version:tt,description:typeof u?.description=="string"?u.description:void 0,summary:typeof u?.summary=="string"?u.summary:void 0,...u?.["x-metadata"]&&typeof u["x-metadata"]=="object"?u["x-metadata"]:{}};d[0]={...d[0],metadata:q,hasClientRoutes:!0,getSidebar:(l,x)=>At(K(a),p,x),getNavText:()=>H??wt[t.type]??"API Docs",getSearchDocuments:ht(a,q,o.getSearchFacets,o.setSearchFacets,B,h,t.document),getAiDocumentsStore:Dt({getBuild:()=>L.build,metadata:q,document:t.document,specType:t.type,excludeFromSearch:B,basePath:p,getSearchFacets:o.getSearchFacets,markdocTags:{...ot,schemaDefinition:rt}})};const et=d[0];d[0]=d[d.length-1],d[d.length-1]=et;for(const l of d)o.addRoute(l);if(_){const l=St(t.config?.apis,t.realRelativePath);m[_]={[A]:l.rbac,[C]:{fsPath:P}}}r.set(b,L)}})},afterRoutesCreated:async(o,D)=>{const{buildItems:v,simplifyAstStructure:y}=await Q(o.serverOutDir),S=new Set,I=new Set;for(const{chunks:c,relativePath:i,isVirtual:f}of e){const g=`${E}${i}`,F=Pt(o.getAllRoutes(),i);for(const{node:t,markdown:P,pointer:p,key:a,relativePath:h}of c){const{ast:b,compoundHash:M}=await o.parseMarkdoc({input:{content:P,relativePath:h,isVirtual:f},resource:p,context:D,deps:{sharedDataIds:[`${E}${h}`],routeSlugs:F}});if(S.add(p),!(a==="graphql-docs"?t?.description?.value!==void 0:!!a&&It(t,a,P))||!O(t,a,M))continue;I.add(g);const R=y(b);if(a==="graphql-docs"){t.description&&(t.description.value=R);const _=`${E}${h}`;Et(r.get(_),R)}else a&&(t[a]=R)}}const T=n.difference(S);for(const c of T)D.cache.delete(c);n=S,Object.entries(m).forEach(([c,i])=>{const f=i[C]?.fsPath;if(!f)return;const g=o.getRouteByFsPath(f)?.baseSlug;m[c]={...i,[C]:{...i[C],slug:g},slug:g}}),o.setGlobalData({apiProducts:m});for(const[c,i]of r){if(!I.has(c))continue;const{items:f,store:g}=await v({type:i.document.type,document:i.document.document,options:i.document.options,basePath:i.basePath,markdownParser:U});i.build={items:f,store:g},await o.createSharedData(c,z(i,f,g))}}}}function z({document:e,basePath:r,sourcePath:s,apiId:n},m,O){return{[A]:W(e.config),[C]:{slug:pt(r),fsPath:e.customOutputRelativeFile||e.relativePath},items:m,store:O,options:e.options,baseSlug:r,routesMapping:G.isDevelopMode?vt(m,r):{},graphqlPositions:G.isDevelopMode&&e.type==="graphql"?bt(m,r):void 0,sourcePath:s,apiId:n}}function Et(e,r){e?.document.type!=="graphql"||!e.document.options||(e.document.options.info={...e.document.options.info||{},description:r})}function kt(e,r,s){return async function(n){return{...s?{isTranslationFallback:!0}:{},props:{settings:{baseUrlPath:$(n.baseSlug)},disableAutoScroll:!0,seo:{title:e,...r}}}}}function Ot(e,r){const s=e.options?.mockServer,n=$(`/_mock${_t(e.relativePath)}`);s?.url===n&&(e.options={...e.options,mockServer:{...s,url:$(`/_mock${r}`)}})}function Ft(e,r){if(e===r)return{};const s=r==="/"?"/":`${r}/`;if(e.startsWith(s)){const n=e.slice(s.length);return n?{slugSuffix:n}:{}}return{slug:e}}function Mt(e){if(e&&typeof e=="object"&&"info"in e)return e.info}function K(e){return e.map(({content:r,items:s,...n})=>({...n,...s&&{items:K(s)}}))}export{de as apiDocsPlugin,Ft as toRouteSlugFields};
@@ -1,3 +1,3 @@
1
- import*as l from"node:path";import{parse as x,visit as D}from"graphql";import{Source as N,bundle as _,createConfig as M,getTotals as V,resolvePlugins as j}from"@redocly/openapi-core";import{convertSwaggerToOpenApi as S}from"@redocly/api-docs/lib/services/spec-convert/swagger.js";import{normalizeAsyncApiDefinition as F}from"@redocly/api-docs/lib/services/spec-convert/asyncapi.js";import{CONFIG_FILE_NAME as b}from"../../../constants/common.js";import{MAX_BUNDLING_ERRORS_TO_PRINT as G}from"../../constants/plugins/api-docs.js";import{unique as L}from"../../../utils/array/unique.js";import{deepMerge as z}from"../../../utils/object/deep-merge.js";import{pluralize as E}from"../../../utils/string/pluralize.js";import{replaceEnvVariablesDeep as H}from"../../utils/envs/replace-env-variables-deep.js";import{logger as q}from"../../tools/notifiers/logger.js";import{reporter as h}from"../../tools/notifiers/reporter.js";import{ExternalResolver as O}from"../../fs/utils/external-ref-resolver.js";import{collectCopiedDescriptionChunks as J,injectDecoratorIntoConfig as Q,isPlainNonMarkdownText as U}from"./utils/decorators.js";import{getAllApiConfigsByPath as X,getApiConfigByPath as K}from"../get-api-config.js";import{formatBundleError as W}from"./utils/format-bundle-error.js";import{createOptions as P}from"./options.js";const Y=/(\.ya?ml|\.json|\.gql|\.graphql)$/,$=/(\.gql|\.graphql)$/;async function Pn(n,o){if(l.posix.basename(n)===b)return[];if($.test(n)){if(await o.isPathIgnored(n))return[];const u=await sn(n,o);return u?[u]:[]}let r;try{r=(await o.cache.load(n,"yaml")).data}catch{return[]}const t=on(n,r);if(!t||!r||t==="graphql")return t===null&&q.verbose(`${n} file is not a recognized API spec. Skipping`),[];const{fs:s,getConfig:a,isPathIgnored:c}=o,e=t==="openapi"?await a("."):null,i=s.getFileInfo(n),f=await a(l.posix.dirname(n)),p=X(f?.apis,n,f.configPath),w=await c(n),d=[];for(const u of p){if(!u.output&&w)continue;const y=f.configPath?l.posix.dirname(f.configPath):".",g=u.output?l.posix.join(y,u.output):n;if(!await c(g)){i&&u.output&&!s.exists(g)&&s.addVirtualFile(g,i);try{const m=await an({relativePath:n,outputRelativePath:g,loaded:r,specType:t,rootConfig:e,config:f,apiConfig:u,fileRecord:i,fs:s});m&&d.push(m)}catch(m){await h.panicOnBuildContentError(m)}}}return d}async function $n(n,o){const{fs:r,cache:t}=o,s=[];for(const a of r.scan(Y)){let c;try{c=await t.load(a.relativePath,"api-doc")}catch{continue}if(c.data?.length)for(const e of c.data)s.push({...e,isVirtual:a.isVirtual||e.isVirtual,hash:c.compoundHash})}return s}function Z(n){const o=[];return D(n,{leave:r=>{!("description"in r)||!r.description?.value||!("name"in r)||U(r.description.value)||o.push({node:r,pointer:`#/types/${r?.name?.value}`,markdown:r.description.value,relativePath:"",key:"graphql-docs"})}}),o}async function nn(n){try{const o=x(n);return{document:o,markdocChunks:Z(o)}}catch(o){await h.panicOnBuildContentError(o);return}}function on(n,o){return $.test(n)?"graphql":o?.openapi||o?.swagger?"openapi":o?.asyncapi?"asyncapi":null}function v(n,o){return o?{...n,info:{...n.info,"x-metadata":{...n.info?.["x-metadata"],...o}}}:n}async function rn(n,o,r){if(n==="openapi"){const t=o.swagger!==void 0?S(o):o;return v(t,r)}return v(F(o),r)}async function tn(n){const{outputRelativePath:o,rootConfig:r,config:t,apiConfig:s,fs:a}=n,c=z({decorators:r?.decorators},t,{rbac:void 0},s),{resolvedObj:e}=H(c);if(e.decorators&&typeof e.decorators!="object"){await h.panicOnBuildContentError(`'decorators' must be an object at redocly.yaml, got '${typeof e.decorators}'`);return}if(e.plugins&&!Array.isArray(e.plugins)){await h.panicOnBuildContentError(`'plugins' must be an array at redocly.yaml, got '${typeof e.plugins}'`);return}const i=l.resolve(a.cwd,t.realConfigPath||b),f=new O(a),p=await M(Q(e,o,a.cwd),{configPath:i,externalRefResolver:f});return r?.plugins&&r.configPath!==t.configPath&&(p.plugins=L([...p.plugins||[],...await j(r.plugins,a.cwd)],w=>w.id)),{coreConfig:p,mergedConfig:e}}async function en(n,o,r){const t=V(n),s=[t.errors&&`${t.errors} ${E(t.errors,"error","errors")}`,t.warnings&&`${t.warnings} ${E(t.warnings,"warning","warnings")}`,t.ignored&&`${t.ignored} ignored`].filter(Boolean).join(", ");if(t.errors){const a=n.filter(i=>i.severity==="error");let c=`${s} while bundling ${o} definition:
2
- `;const e=Math.min(a.length,G);for(let i=0;i<e;i++){const f=await W(a[i],r);c+=`${f}
3
- `}if(a.length>e){const i=a.length-e;c+=`... and ${i} more ${E(i,"error","errors")}`}return await h.panicOnBuild(c),!0}return t.warnings&&q.warn(`${s} while bundling %rp definition`,o),!1}async function an(n){const{relativePath:o,outputRelativePath:r,loaded:t,specType:s,rootConfig:a,config:c,apiConfig:e,fileRecord:i,fs:f}=n,p=await tn(n);if(!p)return;const{coreConfig:w,mergedConfig:d}=p,u=l.resolve(f.cwd,o),y=new O(f),g={config:w,base:l.dirname(u),doc:{source:new N(u,await f.read(o)),parsed:JSON.parse(JSON.stringify(t))},externalRefResolver:y},{bundle:{parsed:C},problems:m,visitorsData:A}=await _(g);if(await en(m,r,f.cwd))return;const R=A["markdown/markdown"]?.markdocChunks??[],I=d.metadata,T=s==="asyncapi"||C.swagger!==void 0,k=await rn(s,C,I);T&&R.push(...J(k,R));const B=P(s,k,{rootConfig:a,config:c,apiConfig:e,mergedConfig:d,relativePath:r});return{type:s,document:k,config:d,relativePath:r,realRelativePath:i?.realRelativePath||r,customOutputRelativeFile:e.output?r:void 0,markdocChunks:R,isVirtual:i?.isVirtual,options:B}}async function sn(n,o){const{fs:r,getConfig:t}=o,s=await r.read(n),a=r.getFileInfo(n),{document:c,markdocChunks:e}=await nn(s)||{};if(!c){await h.panicOnBuildContentError(new Error("Failed to build GraphQL document"));return}const i=await t(),f=K(i.apis,n);i.graphql?.info?.description&&e?.unshift({node:{description:{value:i.graphql?.info?.description}},pointer:"#/info",markdown:i.graphql?.info?.description,relativePath:"",key:"graphql-docs"});const p=P("graphql",c,{rootConfig:null,config:i,apiConfig:f??{},mergedConfig:{graphql:{...i.graphql??{},...f?.graphql??{}}},relativePath:n});return{type:"graphql",document:c,config:{...i,...f},relativePath:n,realRelativePath:a?.realRelativePath||n,markdocChunks:e,isVirtual:a?.isVirtual,options:p}}export{Pn as apiDocLoader,$n as apiDocsLoader,Z as collectGraphqlMarkdocChunks};
1
+ import*as l from"node:path";import{parse as D,visit as N}from"graphql";import{Source as S,bundle as _,createConfig as x,getTotals as M,resolvePlugins as V}from"@redocly/openapi-core";import{convertSwaggerToOpenApi as j}from"@redocly/api-docs/lib/services/spec-convert/swagger.js";import{normalizeAsyncApiDefinition as F}from"@redocly/api-docs/lib/services/spec-convert/asyncapi.js";import{CONFIG_FILE_NAME as E}from"../../../constants/common.js";import{MAX_BUNDLING_ERRORS_TO_PRINT as G}from"../../constants/plugins/api-docs.js";import{unique as L}from"../../../utils/array/unique.js";import{deepMerge as z}from"../../../utils/object/deep-merge.js";import{pluralize as k}from"../../../utils/string/pluralize.js";import{replaceEnvVariablesDeep as H}from"../../utils/envs/replace-env-variables-deep.js";import{logger as q}from"../../tools/notifiers/logger.js";import{reporter as h}from"../../tools/notifiers/reporter.js";import{ExternalResolver as O}from"../../fs/utils/external-ref-resolver.js";import{collectCopiedDescriptionChunks as J,injectDecoratorIntoConfig as Q,isPlainNonMarkdownText as U}from"./utils/decorators.js";import{getAllApiConfigsByPath as X,getApiConfigByPath as K}from"../get-api-config.js";import{formatBundleError as W}from"./utils/format-bundle-error.js";import{injectMetadata as P}from"./utils/inject-metadata.js";import{createOptions as $}from"./options.js";const Y=/(\.ya?ml|\.json|\.gql|\.graphql)$/,v=/(\.gql|\.graphql)$/;async function $n(n,o){if(l.posix.basename(n)===E)return[];if(v.test(n)){if(await o.isPathIgnored(n))return[];const f=await sn(n,o);return f?[f]:[]}let r;try{r=(await o.cache.load(n,"yaml")).data}catch{return[]}const t=on(n,r);if(!t||!r||t==="graphql")return t===null&&q.verbose(`${n} file is not a recognized API spec. Skipping`),[];const{fs:s,getConfig:a,isPathIgnored:c}=o,e=t==="openapi"?await a("."):null,i=s.getFileInfo(n),u=await a(l.posix.dirname(n)),p=X(u?.apis,n,u.configPath),w=await c(n),d=[];for(const f of p){if(!f.output&&w)continue;const y=u.configPath?l.posix.dirname(u.configPath):".",g=f.output?l.posix.join(y,f.output):n;if(!await c(g)){i&&f.output&&!s.exists(g)&&s.addVirtualFile(g,i);try{const m=await an({relativePath:n,outputRelativePath:g,loaded:r,specType:t,rootConfig:e,config:u,apiConfig:f,fileRecord:i,fs:s});m&&d.push(m)}catch(m){await h.panicOnBuildContentError(m)}}}return d}async function vn(n,o){const{fs:r,cache:t}=o,s=[];for(const a of r.scan(Y)){let c;try{c=await t.load(a.relativePath,"api-doc")}catch{continue}if(c.data?.length)for(const e of c.data)s.push({...e,isVirtual:a.isVirtual||e.isVirtual,hash:c.compoundHash})}return s}function Z(n){const o=[];return N(n,{leave:r=>{!("description"in r)||!r.description?.value||!("name"in r)||U(r.description.value)||o.push({node:r,pointer:`#/types/${r?.name?.value}`,markdown:r.description.value,relativePath:"",key:"graphql-docs"})}}),o}async function nn(n){try{const o=D(n);return{document:o,markdocChunks:Z(o)}}catch(o){await h.panicOnBuildContentError(o);return}}function on(n,o){return v.test(n)?"graphql":o?.openapi||o?.swagger?"openapi":o?.asyncapi?"asyncapi":null}async function rn(n,o,r){if(n==="openapi"){const t=o.swagger!==void 0?j(o):o;return P(t,r)}return P(F(o),r)}async function tn(n){const{outputRelativePath:o,rootConfig:r,config:t,apiConfig:s,fs:a}=n,c=z({decorators:r?.decorators},t,{rbac:void 0},s),{resolvedObj:e}=H(c);if(e.decorators&&typeof e.decorators!="object"){await h.panicOnBuildContentError(`'decorators' must be an object at redocly.yaml, got '${typeof e.decorators}'`);return}if(e.plugins&&!Array.isArray(e.plugins)){await h.panicOnBuildContentError(`'plugins' must be an array at redocly.yaml, got '${typeof e.plugins}'`);return}const i=l.resolve(a.cwd,t.realConfigPath||E),u=new O(a),p=await x(Q(e,o,a.cwd),{configPath:i,externalRefResolver:u});return r?.plugins&&r.configPath!==t.configPath&&(p.plugins=L([...p.plugins||[],...await V(r.plugins,a.cwd)],w=>w.id)),{coreConfig:p,mergedConfig:e}}async function en(n,o,r){const t=M(n),s=[t.errors&&`${t.errors} ${k(t.errors,"error","errors")}`,t.warnings&&`${t.warnings} ${k(t.warnings,"warning","warnings")}`,t.ignored&&`${t.ignored} ignored`].filter(Boolean).join(", ");if(t.errors){const a=n.filter(i=>i.severity==="error");let c=`${s} while bundling ${o} definition:
2
+ `;const e=Math.min(a.length,G);for(let i=0;i<e;i++){const u=await W(a[i],r);c+=`${u}
3
+ `}if(a.length>e){const i=a.length-e;c+=`... and ${i} more ${k(i,"error","errors")}`}return await h.panicOnBuild(c),!0}return t.warnings&&q.warn(`${s} while bundling %rp definition`,o),!1}async function an(n){const{relativePath:o,outputRelativePath:r,loaded:t,specType:s,rootConfig:a,config:c,apiConfig:e,fileRecord:i,fs:u}=n,p=await tn(n);if(!p)return;const{coreConfig:w,mergedConfig:d}=p,f=l.resolve(u.cwd,o),y=new O(u),g={config:w,base:l.dirname(f),doc:{source:new S(f,await u.read(o)),parsed:JSON.parse(JSON.stringify(t))},externalRefResolver:y},{bundle:{parsed:C},problems:m,visitorsData:A}=await _(g);if(await en(m,r,u.cwd))return;const b=A["markdown/markdown"]?.markdocChunks??[],I=d.metadata,T=s==="asyncapi"||C.swagger!==void 0,R=await rn(s,C,I);T&&b.push(...J(R,b));const B=$(s,R,{rootConfig:a,config:c,apiConfig:e,mergedConfig:d,relativePath:r});return{type:s,document:R,config:d,relativePath:r,realRelativePath:i?.realRelativePath||r,customOutputRelativeFile:e.output?r:void 0,markdocChunks:b,isVirtual:i?.isVirtual,options:B}}async function sn(n,o){const{fs:r,getConfig:t}=o,s=await r.read(n),a=r.getFileInfo(n),{document:c,markdocChunks:e}=await nn(s)||{};if(!c){await h.panicOnBuildContentError(new Error("Failed to build GraphQL document"));return}const i=await t(),u=K(i.apis,n);i.graphql?.info?.description&&e?.unshift({node:{description:{value:i.graphql?.info?.description}},pointer:"#/info",markdown:i.graphql?.info?.description,relativePath:"",key:"graphql-docs"});const p=$("graphql",c,{rootConfig:null,config:i,apiConfig:u??{},mergedConfig:{graphql:{...i.graphql??{},...u?.graphql??{}}},relativePath:n});return{type:"graphql",document:c,config:{...i,...u},relativePath:n,realRelativePath:a?.realRelativePath||n,markdocChunks:e,isVirtual:a?.isVirtual,options:p}}export{$n as apiDocLoader,vn as apiDocsLoader,Z as collectGraphqlMarkdocChunks};
@@ -5,9 +5,12 @@ import type { MarkdocTagSchema } from '@redocly/theme/markdoc/tags/types';
5
5
  import type { AiDocumentsStore } from '../../../plugins/search/types.js';
6
6
  type ApiDocument = OpenAPIDefinition | AsyncApiDefinition | Record<string, unknown>;
7
7
  type AiDocumentsStoreParams = {
8
- items: ApiItem[];
8
+ /** Read when the store runs: the markdoc rebuild in `afterRoutesCreated` replaces the items and the store built at route creation. */
9
+ getBuild: () => {
10
+ items: ApiItem[];
11
+ store?: ApiStore;
12
+ };
9
13
  metadata: ApiDocsMetadata;
10
- store?: ApiStore;
11
14
  document?: ApiDocument;
12
15
  specType: ApiSpecType;
13
16
  excludeFromSearch?: boolean;
@@ -15,6 +18,6 @@ type AiDocumentsStoreParams = {
15
18
  getSearchFacets: () => Map<string, SearchFacet>;
16
19
  markdocTags?: Record<string, MarkdocTagSchema>;
17
20
  };
18
- export declare function getAiDocumentsStore({ items, metadata, store, document, specType, excludeFromSearch, basePath, getSearchFacets, markdocTags, }: AiDocumentsStoreParams): (route: PageRouteDetails, _staticData: unknown, _context: AfterRoutesCreatedLifecycleContext, actions: AfterRoutesCreatedActions) => Promise<AiDocumentsStore | undefined>;
21
+ export declare function getAiDocumentsStore({ getBuild, metadata, document, specType, excludeFromSearch, basePath, getSearchFacets, markdocTags, }: AiDocumentsStoreParams): (route: PageRouteDetails, _staticData: unknown, _context: AfterRoutesCreatedLifecycleContext, actions: AfterRoutesCreatedActions) => Promise<AiDocumentsStore | undefined>;
19
22
  export {};
20
23
  //# sourceMappingURL=get-ai-search-documents.d.ts.map
@@ -1,34 +1,34 @@
1
- import C from"node:path";import{REDOCLY_TEAMS_RBAC as x}from"@redocly/config";import{nodeTypes as m,contentType as g,isGraphqlFieldsNode as ln,resolveGraphqlItemFields as fn}from"@redocly/api-docs";import{normalizeApiVersion as an}from"../utils/normalize-api-version.js";import{replaceFileExtension as v}from"../utils/replace-file-extension.js";import{isResourcePubliclyAccessible as pn,canDownloadApiDefinition as un,extractTeamsFromScopeItems as dn}from"../../../utils/rbac.js";import{getLlmsTxtMdPathBySlug as H}from"../../../utils/llmstxt/get-llms-txt-md-path-by-slug.js";import{PUBLIC_API_DEFINITIONS_FOLDER as Y}from"../../../constants/common.js";import{GRAPHQL_SPEC_SLUG as hn}from"../../../../constants/common.js";import{ANONYMOUS_AUTH_DETAILS as mn}from"../../../constants/rbac.js";import{toMarkdown as N}from"../../markdown/search/to-markdown.js";import{createRenderTagFn as $n}from"../../markdown/search/create-render-tag-fn.js";import{getLocaleFromRelativePath as yn}from"../../../fs/utils/get-locale-from-relative-path.js";import{getBuildTranslateContext as gn}from"../../../utils/l10n/get-build-translate-context.js";import{llmsTxtLink as w}from"../../search/llmstxt/index.js";import{formatDocumentMetadata as bn}from"../../search/utils.js";import{extractDocumentSearchFacets as In}from"./search-facets.js";import{createApiDocsSearchIndexer as Pn,createLlmDescriptionFormatter as Sn}from"./create-indexer.js";function P(e,s){return s==="openapi"&&"openapi"in e}function K(e,s){return s==="asyncapi"&&"asyncapi"in e}function Xn({items:e,metadata:s,store:c,document:r,specType:n,excludeFromSearch:l,basePath:t,getSearchFacets:i,markdocTags:f}){return async(o,d,p,u)=>{if(l)return;const h={...u.markdocOptions?.tags,...f},{locale:$,translate:nn}=await gn(o.slug,u.getGlobalData?.().l10n),S=$n(h,$,nn),L=u.getConfig(),R=yn(o.fsPath),D=Sn(S),j=Pn(t,D,c?.schemaStore,r,c?.exampleStore,c?.graphqlMeta),V=b=>{for(const a of b)j.addItem(a),a.items?.length&&V(a.items)};V(e);const tn=j.getResult(),F=new Map;for(const b of tn)F.set(b.url,b);const E=typeof s.title=="string"?s.title:void 0,_=an(s.version),k=In(o.metadata||{},E,_,i),A=[],O=[],q=typeof s.description=="string"&&s.description?D(s.description):void 0,G=An(s,q,r,n,D),z=On(n,s,o.fsPath,L),en=Tn(e,L,S),on=G+z+`
2
- `+en,sn=G+z;O.push({title:E||"API Overview",description:q,content:on,slug:t,fsPath:o.fsPath,includeInLLMsTxt:!0}),A.push({title:E||"API Overview",content:sn,url:t,fsPath:o.fsPath,locale:R,product:o.product?.name,facets:k});const rn=r&&P(r,n)?r.security:void 0,U=b=>{for(const a of b){if(!a.content||!a.link){a.items?.length&&U(a.items);continue}const cn=F.get(a.link),W=a.content.contentType,B=a[x],J=B?dn(B):void 0,Q=J?.length?J:void 0;if(W===g.ITEM){const y=Ln(a,r,n)??X(a,cn,n,_,rn,S,c);if(y){const I=a.label||"";O.push({title:I,description:void 0,content:y,slug:a.link,fsPath:o.fsPath,includeInLLMsTxt:!1}),A.push({title:I,content:y,url:a.link,fsPath:o.fsPath,locale:R,product:o.product?.name,facets:k,rbacTeams:Q})}}else if(W===g.GROUP){const y=Rn(a,L,n,S,c);if(y){const I=a.label||"";O.push({title:I,description:void 0,content:y.llmstxt,slug:a.link,fsPath:o.fsPath,includeInLLMsTxt:!1}),A.push({title:I,content:y.aiSearch,url:a.link,fsPath:o.fsPath,locale:R,product:o.product?.name,facets:k,rbacTeams:Q})}}a.items?.length&&U(a.items)}};return U(e),{async getLLMsTxts(){return O},async getSearchDocuments(){return A}}}}function An(e,s,c,r,n){const l=typeof e.title=="string"?e.title:"",t=typeof e.summary=="string"?e.summary:"",i=typeof e.version=="string"?e.version:"";let f=l?`# ${l}
1
+ import x from"node:path";import{REDOCLY_TEAMS_RBAC as C}from"@redocly/config";import{nodeTypes as $,contentType as g,isGraphqlFieldsNode as pn,resolveGraphqlItemFields as un}from"@redocly/api-docs";import{normalizeApiVersion as dn}from"../utils/normalize-api-version.js";import{replaceFileExtension as v}from"../utils/replace-file-extension.js";import{isResourcePubliclyAccessible as mn,canDownloadApiDefinition as hn,extractTeamsFromScopeItems as $n}from"../../../utils/rbac.js";import{getLlmsTxtMdPathBySlug as K}from"../../../utils/llmstxt/get-llms-txt-md-path-by-slug.js";import{PUBLIC_API_DEFINITIONS_FOLDER as X}from"../../../constants/common.js";import{GRAPHQL_SPEC_SLUG as yn}from"../../../../constants/common.js";import{isPlainObject as N}from"../../../../utils/guards/is-plain-object.js";import{ANONYMOUS_AUTH_DETAILS as gn}from"../../../constants/rbac.js";import{toMarkdown as j}from"../../markdown/search/to-markdown.js";import{createRenderTagFn as bn}from"../../markdown/search/create-render-tag-fn.js";import{getLocaleFromRelativePath as In}from"../../../fs/utils/get-locale-from-relative-path.js";import{getBuildTranslateContext as On}from"../../../utils/l10n/get-build-translate-context.js";import{llmsTxtLink as w}from"../../search/llmstxt/index.js";import{formatDocumentMetadata as Pn}from"../../search/utils.js";import{extractDocumentSearchFacets as Sn}from"./search-facets.js";import{createApiDocsSearchIndexer as An,createLlmDescriptionFormatter as xn}from"./create-indexer.js";function O(e,s){return s==="openapi"&&"openapi"in e}function Z(e,s){return s==="asyncapi"&&"asyncapi"in e}function it({getBuild:e,metadata:s,document:c,specType:o,excludeFromSearch:n,basePath:r,getSearchFacets:t,markdocTags:i}){return async(l,f,d,p)=>{if(n)return;const{items:a,store:m}=e(),h={...p.markdocOptions?.tags,...i},{locale:en,translate:on}=await On(l.slug,p.getGlobalData?.().l10n),P=bn(h,en,on),L=p.getConfig(),D=In(l.fsPath),R=xn(P),V=An(r,R,m?.schemaStore,c,m?.exampleStore,m?.graphqlMeta),F=b=>{for(const u of b)V.addItem(u),u.items?.length&&F(u.items)};F(a);const sn=V.getResult(),_=new Map;for(const b of sn)_.set(b.url,b);const E=typeof s.title=="string"?s.title:void 0,q=dn(s.version),k=Sn(l.metadata||{},E,q,t),S=[],A=[],G=Cn(c,s),z=G?R(G):void 0,W=Tn(s,z,c,o,R),B=Ln(o,s,l.fsPath,L),rn=En(a,L,P),cn=W+B+`
2
+ `+rn,ln=W+B;A.push({title:E||"API Overview",description:z,content:cn,slug:r,fsPath:l.fsPath,includeInLLMsTxt:!0}),S.push({title:E||"API Overview",content:ln,url:r,fsPath:l.fsPath,locale:D,product:l.product?.name,facets:k});const fn=c&&O(c,o)?c.security:void 0,U=b=>{for(const u of b){if(!u.content||!u.link){u.items?.length&&U(u.items);continue}const an=_.get(u.link),J=u.content.contentType,Q=u[C],H=Q?$n(Q):void 0,Y=H?.length?H:void 0;if(J===g.ITEM){const y=kn(u,c,o)??nn(u,an,o,q,fn,P,m);if(y){const I=u.label||"";A.push({title:I,description:void 0,content:y,slug:u.link,fsPath:l.fsPath,includeInLLMsTxt:!1}),S.push({title:I,content:y,url:u.link,fsPath:l.fsPath,locale:D,product:l.product?.name,facets:k,rbacTeams:Y})}}else if(J===g.GROUP){const y=Un(u,L,o,P,m);if(y){const I=u.label||"";A.push({title:I,description:void 0,content:y.llmstxt,slug:u.link,fsPath:l.fsPath,includeInLLMsTxt:!1}),S.push({title:I,content:y.aiSearch,url:u.link,fsPath:l.fsPath,locale:D,product:l.product?.name,facets:k,rbacTeams:Y})}}u.items?.length&&U(u.items)}};return U(a),{async getLLMsTxts(){return A},async getSearchDocuments(){return S}}}}function Cn(e,s){const c=N(e?.info)?e.info:void 0,o=N(c?.["x-metadata"])?c["x-metadata"]:{},r=(typeof o.description=="string"?o.description:void 0)??c?.description??s.description;return typeof r=="string"?r||void 0:r&&typeof r=="object"?r:void 0}function Tn(e,s,c,o,n){const r=typeof e.title=="string"?e.title:"",t=typeof e.summary=="string"?e.summary:"",i=typeof e.version=="string"?e.version:"";let l=r?`# ${r}
3
3
 
4
- `:"";if(f+=s?`${s}
4
+ `:"";if(l+=s?`${s}
5
5
 
6
- `:"",f+=t?`${t}
6
+ `:"",l+=t?`${t}
7
7
 
8
- `:"",f+=i?`Version: ${i}
9
- `:"",c){if(P(c,r)){const{info:o}=c;o?.license?.name&&(f+=`License: ${o.license.name}
10
- `);const d=o["x-metadata"],p=bn(d);p&&(f+=`
8
+ `:"",l+=i?`Version: ${i}
9
+ `:"",c){if(O(c,o)){const{info:f}=c;f?.license?.name&&(l+=`License: ${f.license.name}
10
+ `);const d=f["x-metadata"],p=Object.entries(N(d)?d:{}).filter(([m,h])=>m!=="description"||typeof h!="string"),a=Pn(Object.fromEntries(p));a&&(l+=`
11
11
  Metadata:
12
- ${p}
13
- `)}else if(K(c,r)){const{info:o}=c;o?.license?.name&&(f+=`License: ${o.license.name}
14
- `)}}return f+=`
15
- `,f+=Cn(c,r,n),f+=xn(c,r,n),f}function On(e,s,c,r){if(!c)return"";let n,l,t;if(e==="openapi")n=C.posix.join(Y,v(c,".yaml")),l="## Download OpenAPI description",t="OpenAPI definition";else if(e==="asyncapi")n=C.posix.join(Y,v(c,".yaml")),l="## Download AsyncAPI description",t="AsyncAPI definition";else if(e==="graphql"){const o=C.posix.extname(c)||".graphql";n=C.posix.join(hn,v(c,o)),l="## Download GraphQL schema",t="GraphQL schema"}else return"";if(!un(n,r.access?.rbac??{},r.access?.requiresLogin??!1,mn))return"";const f=typeof s.title=="string"&&s.title||t;return`${l}
12
+ ${a}
13
+ `)}else if(Z(c,o)){const{info:f}=c;f?.license?.name&&(l+=`License: ${f.license.name}
14
+ `)}}return l+=`
15
+ `,l+=Dn(c,o,n),l+=Rn(c,o,n),l}function Ln(e,s,c,o){if(!c)return"";let n,r,t;if(e==="openapi")n=x.posix.join(X,v(c,".yaml")),r="## Download OpenAPI description",t="OpenAPI definition";else if(e==="asyncapi")n=x.posix.join(X,v(c,".yaml")),r="## Download AsyncAPI description",t="AsyncAPI definition";else if(e==="graphql"){const f=x.posix.extname(c)||".graphql";n=x.posix.join(yn,v(c,f)),r="## Download GraphQL schema",t="GraphQL schema"}else return"";if(!hn(n,o.access?.rbac??{},o.access?.requiresLogin??!1,gn))return"";const l=typeof s.title=="string"&&s.title||t;return`${r}
16
16
 
17
- - ${w({title:f,description:void 0,slug:n,siteUrl:r.seo?.siteUrl})}`}function Cn(e,s,c){if(!e)return"";if(P(e,s)){const{servers:r}=e;if(!r?.length)return"";let n=`## Servers
17
+ - ${w({title:l,description:void 0,slug:n,siteUrl:o.seo?.siteUrl})}`}function Dn(e,s,c){if(!e)return"";if(O(e,s)){const{servers:o}=e;if(!o?.length)return"";let n=`## Servers
18
18
 
19
- `;for(const l of r)if(l.description&&(n+=`${c(l.description)}
19
+ `;for(const r of o)if(r.description&&(n+=`${c(r.description)}
20
20
  `),n+=`\`\`\`
21
- ${l.url}
21
+ ${r.url}
22
22
  \`\`\`
23
23
 
24
- `,l.variables){n+=`Variables:
25
- `;for(const[t,i]of Object.entries(l.variables))n+=`- \`${t}\`${i.description?`: ${c(i.description).replace(/\s+/g," ")}`:""}
24
+ `,r.variables){n+=`Variables:
25
+ `;for(const[t,i]of Object.entries(r.variables))n+=`- \`${t}\`${i.description?`: ${c(i.description).replace(/\s+/g," ")}`:""}
26
26
  `,i.default&&(n+=` Default: ${JSON.stringify(i.default)}
27
- `),i.enum&&(n+=` Enum: ${i.enum.map(f=>JSON.stringify(f)).join(", ")}
27
+ `),i.enum&&(n+=` Enum: ${i.enum.map(l=>JSON.stringify(l)).join(", ")}
28
28
  `);n+=`
29
- `}return n}if(K(e,s)){const{servers:r}=e;if(!r||!Object.keys(r).length)return"";let n=`## Servers
29
+ `}return n}if(Z(e,s)){const{servers:o}=e;if(!o||!Object.keys(o).length)return"";let n=`## Servers
30
30
 
31
- `;for(const[l,t]of Object.entries(r))n+=`### ${l}
31
+ `;for(const[r,t]of Object.entries(o))n+=`### ${r}
32
32
 
33
33
  `,t.description&&(n+=`${c(t.description)}
34
34
  `),t.host&&(n+=`Host: ${t.host}
@@ -36,9 +36,9 @@ ${l.url}
36
36
  `),t.protocolVersion&&(n+=`Protocol Version: ${t.protocolVersion}
37
37
  `),t.pathname&&(n+=`Pathname: ${t.pathname}
38
38
  `),n+=`
39
- `;return n}return""}function xn(e,s,c){if(!e||!P(e,s))return"";const r=e.components?.securitySchemes;if(!r)return"";let n=`## Security
39
+ `;return n}return""}function Rn(e,s,c){if(!e||!O(e,s))return"";const o=e.components?.securitySchemes;if(!o)return"";let n=`## Security
40
40
 
41
- `;for(const[l,t]of Object.entries(r)){if(!t||"$ref"in t)continue;const i=t;n+=`### ${l}
41
+ `;for(const[r,t]of Object.entries(o)){if(!t||"$ref"in t)continue;const i=t;n+=`### ${r}
42
42
 
43
43
  `,i.description&&(n+=`${c(i.description)}
44
44
 
@@ -48,58 +48,58 @@ ${l.url}
48
48
  `),i.scheme&&(n+=`Scheme: ${i.scheme}
49
49
  `),i.bearerFormat&&(n+=`Bearer Format: ${i.bearerFormat}
50
50
  `),i.openIdConnectUrl&&(n+=`OpenID Connect URL: ${i.openIdConnectUrl}
51
- `);const f=i.flows,o=f?.implicit||f?.password||f?.clientCredentials||f?.authorizationCode;if(o&&("authorizationUrl"in o&&o.authorizationUrl&&(n+=`Authorization URL: ${o.authorizationUrl}
52
- `),"tokenUrl"in o&&o.tokenUrl&&(n+=`Token URL: ${o.tokenUrl}
53
- `),o.scopes)){n+=`Scopes:
54
- `;for(const[d,p]of Object.entries(o.scopes))n+=`- \`${d}\`: ${p}
51
+ `);const l=i.flows,f=l?.implicit||l?.password||l?.clientCredentials||l?.authorizationCode;if(f&&("authorizationUrl"in f&&f.authorizationUrl&&(n+=`Authorization URL: ${f.authorizationUrl}
52
+ `),"tokenUrl"in f&&f.tokenUrl&&(n+=`Token URL: ${f.tokenUrl}
53
+ `),f.scopes)){n+=`Scopes:
54
+ `;for(const[d,p]of Object.entries(f.scopes))n+=`- \`${d}\`: ${p}
55
55
  `}n+=`
56
- `}return n}function Tn(e,s,c){let r="";const n=(l,t)=>{for(const i of l)if(i.link){if(i.content?.contentType===g.GROUP)r+=`${t} ${i.label||""}
56
+ `}return n}function En(e,s,c){let o="";const n=(r,t)=>{for(const i of r)if(i.link){if(i.content?.contentType===g.GROUP)o+=`${t} ${i.label||""}
57
57
 
58
- `,i.items?.length&&n(i.items,t+"#");else if(i.content?.contentType===g.ITEM){if(!M(i,s))continue;const f=i,o=f.httpVerb,d=f.httpPath,p=o&&d?`${o.toUpperCase()} ${d}`:i.label||"",u=i.content?T(i.content.children,c):void 0;r+=` - ${w({title:p,description:u?u.slice(0,200):void 0,slug:H(i.link),siteUrl:s.seo?.siteUrl})}`}}};return n(e,"##"),r}function X(e,s,c,r,n,l,t){if(!e.content)return;const i=e,f=e.label||"",o=T(e.content.children,l),d=e.content.meta?.deprecated;let p=`# ${f}${d?" (deprecated)":""}
58
+ `,i.items?.length&&n(i.items,t+"#");else if(i.content?.contentType===g.ITEM){if(!M(i,s))continue;const l=i,f=l.httpVerb,d=l.httpPath,p=f&&d?`${f.toUpperCase()} ${d}`:i.label||"",a=i.content?T(i.content.children,c):void 0;o+=` - ${w({title:p,description:a?a.slice(0,200):void 0,slug:K(i.link),siteUrl:s.seo?.siteUrl})}`}}};return n(e,"##"),o}function nn(e,s,c,o,n,r,t){if(!e.content)return;const i=e,l=e.label||"",f=T(e.content.children,r),d=e.content.meta?.deprecated;let p=`# ${l}${d?" (deprecated)":""}
59
59
 
60
- `;if(o&&(p+=`${o}
60
+ `;if(f&&(p+=`${f}
61
61
 
62
- `),c==="openapi"||c==="asyncapi"){const u=i.httpVerb,h=i.httpPath;u&&h?p+=`Endpoint: ${u.toUpperCase()} ${h}
63
- `:u&&(p+=`Method: ${u.toUpperCase()}
64
- `),r&&(p+=`Version: ${r}
65
- `);const $=Dn(e.content.children,n);$&&(p+=`Security: ${$}
62
+ `),c==="openapi"||c==="asyncapi"){const a=i.httpVerb,m=i.httpPath;a&&m?p+=`Endpoint: ${a.toUpperCase()} ${m}
63
+ `:a&&(p+=`Method: ${a.toUpperCase()}
64
+ `),o&&(p+=`Version: ${o}
65
+ `);const h=vn(e.content.children,n);h&&(p+=`Security: ${h}
66
66
  `)}return s?.parameters?.length&&c!=="graphql"&&(p+=`
67
- `+En(s.parameters)+`
68
- `),c==="graphql"&&(p+=kn(e.content.children,t,l)),p}function Ln(e,s,c){if(e.httpVerb!=="tool"||!s||!P(s,c))return;const r=e.content?.meta?.name,n=r?s["x-mcp"]?.tools?.find(t=>t.name===r):void 0;if(!n)return;let l=`# ${e.label||n.name}
67
+ `+Nn(s.parameters)+`
68
+ `),c==="graphql"&&(p+=jn(e.content.children,t,r)),p}function kn(e,s,c){if(e.httpVerb!=="tool"||!s||!O(s,c))return;const o=e.content?.meta?.name,n=o?s["x-mcp"]?.tools?.find(t=>t.name===o):void 0;if(!n)return;let r=`# ${e.label||n.name}
69
69
 
70
- `;return typeof n.description=="string"&&n.description&&(l+=`${n.description}
70
+ `;return typeof n.description=="string"&&n.description&&(r+=`${n.description}
71
71
 
72
- `),l+=`## Input schema:
72
+ `),r+=`## Input schema:
73
73
 
74
- `,l+=`\`\`\`json
74
+ `,r+=`\`\`\`json
75
75
  ${JSON.stringify(n.inputSchema,null,2)}
76
76
  \`\`\`
77
77
 
78
- `,n.outputSchema&&(l+=`## Output schema:
78
+ `,n.outputSchema&&(r+=`## Output schema:
79
79
 
80
- `,l+=`\`\`\`json
80
+ `,r+=`\`\`\`json
81
81
  ${JSON.stringify(n.outputSchema,null,2)}
82
82
  \`\`\`
83
83
 
84
- `),l}function Rn(e,s,c,r,n){if(!e.content)return;const l=e.label||"",t=T(e.content.children,r);let i=`# ${l}
84
+ `),r}function Un(e,s,c,o,n){if(!e.content)return;const r=e.label||"",t=T(e.content.children,o);let i=`# ${r}
85
85
 
86
86
  `;if(t&&(i+=`${t}
87
87
 
88
- `),c==="graphql"){let o="";const d=p=>{for(const u of p??[])if(!(!u.content||!M(u,s)))if(u.content.contentType===g.ITEM){const h=X(u,void 0,c,void 0,void 0,r,n);h&&(o+=`${h}
88
+ `),c==="graphql"){let f="";const d=p=>{for(const a of p??[])if(!(!a.content||!M(a,s)))if(a.content.contentType===g.ITEM){const m=nn(a,void 0,c,void 0,void 0,o,n);m&&(f+=`${m}
89
89
 
90
90
  ---
91
91
 
92
- `)}else u.content.contentType===g.GROUP&&d(u.items)};return d(e.items),{llmstxt:i+o,aiSearch:i}}let f="";if(e.items?.length)for(const o of e.items){if(!o.link||!o.content||o.content.contentType!==g.ITEM||!M(o,s))continue;const d=o,p=d.httpVerb,u=d.httpPath,h=p&&u?`${p.toUpperCase()} ${u}`:o.label||"",$=o.content?T(o.content.children,r):void 0;f+=` - ${w({title:h,description:$?$.slice(0,200):void 0,slug:H(o.link),siteUrl:s.seo?.siteUrl})}`}return{llmstxt:i+f,aiSearch:i}}function Dn(e,s){const c=[],r=n=>{for(const l of n)if(l.nodeType===m.SECURITY){const t=l;for(const i of t.requirements)for(const f of i.schemes)f[x]||f.name&&!c.includes(f.name)&&c.push(f.name)}else(l.nodeType===m.CONTAINER||l.nodeType===m.OVERVIEW_SECTION_WRAPPER)&&r(l.children)};if(r(e),c.length)return c.join(", ");if(s?.length){const n=s.flatMap(l=>Object.keys(l));if(n.length)return[...new Set(n)].join(", ")}}function En(e){const s={};for(const r of e){const n=`${r.place}${r.mediaType?` (${r.mediaType})`:""}`;s[n]||(s[n]=[]),s[n].push(r)}return Object.entries(s).map(([r,n])=>{const l=n.map(t=>{const i=[...t.path||[],t.name],f=Array.isArray(t.description)?t.description.join(" "):t.description;let o=` - \`${i.join(".")}\` (${t.type}${t.required?", required":""})
93
- `;return f&&(o+=` ${f.trim()}
94
- `),t.enum?o+=` Enum: ${t.enum.map(d=>JSON.stringify(d)).join(", ")}
95
- `:t.example&&(o+=` Example: ${t.example}
96
- `),o});return`## ${Z(r)}:
92
+ `)}else a.content.contentType===g.GROUP&&d(a.items)};return d(e.items),{llmstxt:i+f,aiSearch:i}}let l="";if(e.items?.length)for(const f of e.items){if(!f.link||!f.content||f.content.contentType!==g.ITEM||!M(f,s))continue;const d=f,p=d.httpVerb,a=d.httpPath,m=p&&a?`${p.toUpperCase()} ${a}`:f.label||"",h=f.content?T(f.content.children,o):void 0;l+=` - ${w({title:m,description:h?h.slice(0,200):void 0,slug:K(f.link),siteUrl:s.seo?.siteUrl})}`}return{llmstxt:i+l,aiSearch:i}}function vn(e,s){const c=[],o=n=>{for(const r of n)if(r.nodeType===$.SECURITY){const t=r;for(const i of t.requirements)for(const l of i.schemes)l[C]||l.name&&!c.includes(l.name)&&c.push(l.name)}else(r.nodeType===$.CONTAINER||r.nodeType===$.OVERVIEW_SECTION_WRAPPER)&&o(r.children)};if(o(e),c.length)return c.join(", ");if(s?.length){const n=s.flatMap(r=>Object.keys(r));if(n.length)return[...new Set(n)].join(", ")}}function Nn(e){const s={};for(const o of e){const n=`${o.place}${o.mediaType?` (${o.mediaType})`:""}`;s[n]||(s[n]=[]),s[n].push(o)}return Object.entries(s).map(([o,n])=>{const r=n.map(t=>{const i=[...t.path||[],t.name],l=Array.isArray(t.description)?t.description.join(" "):t.description;let f=` - \`${i.join(".")}\` (${t.type}${t.required?", required":""})
93
+ `;return l&&(f+=` ${l.trim()}
94
+ `),t.enum?f+=` Enum: ${t.enum.map(d=>JSON.stringify(d)).join(", ")}
95
+ `:t.example&&(f+=` Example: ${t.example}
96
+ `),f});return`## ${tn(o)}:
97
97
 
98
- ${l.join(`
98
+ ${r.join(`
99
99
  `)}`}).join(`
100
- `)}function kn(e,s,c){let r="";const n=l=>{for(const t of l)if(t.nodeType===m.ITEM){const i=ln(t)?fn(t,s??{}):void 0;i&&(r+=Un(i,t.variant,c))}else(t.nodeType===m.CONTAINER||t.nodeType===m.OVERVIEW_SECTION_WRAPPER)&&n(t.children)};return n(e),r}function Un(e,s,c){let n=`
101
- ## ${Z(s==="return-type"?"Return type":s==="graphql-args"||s==="arguments"?"Arguments":s==="graphql-fields"?"Fields":s)}:
100
+ `)}function jn(e,s,c){let o="";const n=r=>{for(const t of r)if(t.nodeType===$.ITEM){const i=pn(t)?un(t,s??{}):void 0;i&&(o+=wn(i,t.variant,c))}else(t.nodeType===$.CONTAINER||t.nodeType===$.OVERVIEW_SECTION_WRAPPER)&&n(t.children)};return n(e),o}function wn(e,s,c){let n=`
101
+ ## ${tn(s==="return-type"?"Return type":s==="graphql-args"||s==="arguments"?"Arguments":s==="graphql-fields"?"Fields":s)}:
102
102
 
103
- `;const l=t=>{const i=t.description?N(Array.isArray(t.description)?t.description:[t.description],{renderTag:c}).trim():"";return` - \`${t.name}\` (${t.type.display})${i?`: ${i}`:""}
104
- `};if(e.type){const t=e.type.description?N(Array.isArray(e.type.description)?e.type.description:[e.type.description],{renderTag:c}).trim():"";n+=` Type: ${e.type.display}`,t&&(n+=` - ${t}`),n+=`
105
- `}else if(!e.fields.length)return"";for(const t of e.fields)n+=l(t);return n}function T(e,s){const c=[],r=l=>{for(const t of l)if(t.nodeType===m.MARKDOC){const i=t.content,f=Array.isArray(i)?i:[i],o=N(f,{renderTag:s}).trim();o&&c.push(o)}else(t.nodeType===m.CONTAINER||t.nodeType===m.OVERVIEW_SECTION_WRAPPER)&&r(t.children)};return r(e),c.join(" ").trim()||void 0}function Z(e){return e.charAt(0).toUpperCase()+e.slice(1)}function M(e,s){return s.access?.requiresLogin?!0:pn({slug:e.link||"",[x]:e[x]},s)}export{Xn as getAiDocumentsStore};
103
+ `;const r=t=>{const i=t.description?j(Array.isArray(t.description)?t.description:[t.description],{renderTag:c}).trim():"";return` - \`${t.name}\` (${t.type.display})${i?`: ${i}`:""}
104
+ `};if(e.type){const t=e.type.description?j(Array.isArray(e.type.description)?e.type.description:[e.type.description],{renderTag:c}).trim():"";n+=` Type: ${e.type.display}`,t&&(n+=` - ${t}`),n+=`
105
+ `}else if(!e.fields.length)return"";for(const t of e.fields)n+=r(t);return n}function T(e,s){const c=[],o=r=>{for(const t of r)if(t.nodeType===$.MARKDOC){const i=t.content,l=Array.isArray(i)?i:[i],f=j(l,{renderTag:s}).trim();f&&c.push(f)}else(t.nodeType===$.CONTAINER||t.nodeType===$.OVERVIEW_SECTION_WRAPPER)&&o(t.children)};return o(e),c.join(" ").trim()||void 0}function tn(e){return e.charAt(0).toUpperCase()+e.slice(1)}function M(e,s){return s.access?.requiresLogin?!0:mn({slug:e.link||"",[C]:e[C]},s)}export{it as getAiDocumentsStore};
@@ -0,0 +1,19 @@
1
+ type WithInfo = {
2
+ info?: {
3
+ 'x-metadata'?: Record<string, unknown>;
4
+ };
5
+ };
6
+ /**
7
+ * Merges the API config `metadata` into `info.x-metadata`, the config winning over the spec.
8
+ *
9
+ * Mutates `document` and its `info` in place and returns the same object. The bundle
10
+ * decorators collect the `#/info/description` chunk as a reference to the `info` object, so
11
+ * a copy would leave the resolved Markdoc AST on an orphan and the document with the raw string.
12
+ *
13
+ * @param document - the bundled document
14
+ * @param metadata - the config `metadata`, or none
15
+ * @returns the same document
16
+ */
17
+ export declare function injectMetadata<T extends WithInfo>(document: T, metadata: Record<string, unknown> | undefined): T;
18
+ export {};
19
+ //# sourceMappingURL=inject-metadata.d.ts.map
@@ -0,0 +1 @@
1
+ function n(t,i){if(!i)return t;const a=t.info??{};return t.info=a,a["x-metadata"]={...a["x-metadata"],...i},t}export{n as injectMetadata};
@@ -1,7 +1,7 @@
1
1
  import { type Node } from '@markdoc/markdoc';
2
2
  import type { JSX } from 'react';
3
3
  import type { CommonError, GlobalData } from '../types/index.js';
4
- import type { MiddlewareDetails, PageRouteInit, PageRouteDetails, RouteDetails, LifecycleContext, ApiRoute, ParseMarkdocOpts, WildcardRedirectsTree, RedirectOptions, McpToolRegistration, McpToolSchema, MarkdocOptions } from './types';
4
+ import type { MiddlewareDetails, PageRouteInit, PageRouteDetails, RouteDetails, LifecycleContext, ApiRoute, ParseMarkdocOpts, WildcardRedirectsTree, StaticFilePaths, RedirectOptions, McpToolRegistration, McpToolSchema, MarkdocOptions } from './types';
5
5
  import type { Skill } from './types/plugins/skills.js';
6
6
  import type { RedoclyConfig, RedirectConfig, CompilationError, PageStaticData } from '@redocly/config';
7
7
  import type { SearchFacet } from '@redocly/theme/core/types';
@@ -28,6 +28,7 @@ export type ComputedRedoclyConfig = {
28
28
  export declare class Store {
29
29
  #private;
30
30
  routesBySlug: Map<string, PageRouteDetails>;
31
+ staticFilePaths: StaticFilePaths;
31
32
  replacedEnvVars: Record<string, {
32
33
  original: string;
33
34
  replaced: string;
@@ -112,6 +113,7 @@ export declare class Store {
112
113
  loadApiDocuments(context: LifecycleContext): Promise<BundledApiDefinition[]>;
113
114
  setSearchEngine(engine: SearchEngine): void;
114
115
  setSearchFacets: (searchFacets: Map<string, SearchFacet>) => void;
116
+ setStaticFilePaths: (staticFilePaths: StaticFilePaths) => void;
115
117
  setGlobalConfig: (data: Partial<RedoclyConfig>) => void;
116
118
  getConfig: () => RedoclyConfig;
117
119
  getGlobalConfig: <T = unknown>(key: string) => T;
@@ -1 +1 @@
1
- import A from"@markdoc/markdoc";import{parseAndResolveMarkdoc as T}from"./plugins/markdown/compiler.js";import{getPathnameForLocale as M}from"@redocly/theme/core/utils";import{DEFAULT_LOCALE_PLACEHOLDER as g}from"../constants/common.js";import{DEFAULT_TITLE as O,MARKDOC_PARTIALS_DATA_KEY as m,MARKDOC_PARTIALS_DEPS_KEY as k}from"./constants/common.js";import{GATED_MARKDOC_TAGS as R}from"./constants/entitlements.js";import{isObject as L}from"../utils/guards/is-object.js";import{mapObject as H}from"../utils/object/map-object.js";import{getValueDeep as y}from"../utils/object/get-value-deep.js";import{removeTrailingSlash as D}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 G}from"./utils/crypto/sha1.js";import{envConfig as _,setEnv as B}from"./config/env-config.js";import{KvService as F}from"./persistence/kv/services/kv-service.js";import{SandboxContext as I}from"./utils/sandbox-context.js";import{writeSharedData as N}from"./utils/index.js";import{renderComponents as V}from"./ssr/render.js";import{readStaticData as q,writeStaticData as U}from"./utils/static-data.js";import{getMarkdocOptions as j}from"./plugins/markdown/markdoc/markdoc-options.js";import{EntitlementsProvider as v}from"./entitlements/entitlements-provider.js";import{isRouteReserved as x}from"./plugins/get-reserved-routes.js";import{isL10nPath as K}from"./fs/utils/is-l10n-path.js";import{resolveGlobMapValue as J}from"./utils/globs.js";import{replaceEnvVariablesDeep as W}from"./utils/envs/replace-env-variables-deep.js";import{findRedirect as $}from"./utils/redirects/find-redirect.js";import{followRedirectChain as z}from"./utils/redirects/follow-redirect-chain.js";import{addWildcardRedirectToTree as Y}from"./utils/redirects/add-wildcard-redirect-to-tree.js";import{telemetryTraceStep as Z}from"../cli/telemetry/helpers/trace-step.js";const E={routesBySlug:"map",apiRoutes:"object",middleware:"object",routesByFsPath:"map",routesSharedData:"map",globalData:"object",config:"object",ssr:"object",searchFacets:"map",routesPartials:"map",mcpToolHandlers:"map",skills:"map",devLogin:"object"},P="PLAN_GATES",Q=["OAUTH_CLIENT_ID","OAUTH_CLIENT_SECRET","ORGANIZATION_SLUG","ORGANIZATION_ID","ORG_ID"],ke="userDefinedApiFunctions";class b{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;skills=new Map;serverPropsGetters=new Map;pagePropsGetters=new Map;listeners=new Map;globalData={};devLogin=!1;#a=void 0;config={configFilePath:"",redirects:{},wildcardRedirectsTree:{},access:{rbac:{},requiresLogin:!1},directoryPermissions:{},devLogin:!1,ssoDirect:{}};#i;serverMode;serverOutDir;outdir;buildRevision=0;hasSitemap=!1;compilationErrors=[];#n;userCodeReady;#s=Promise.resolve();#c;#l=Promise.resolve();#d;#u=Promise.resolve();#h;#e=!1;#r=0;#f=0;#o=new Map;constructor({outdir:e,contentDir:s,serverMode:t=!1,serverOutDir:r}){this.#i=s,this.outdir=e,this.serverMode=t,this.serverOutDir=r,I.register({serverOutDir:r,readRoots:[e,process.cwd()]}),this.userCodeReady=new Promise(o=>{this.#n=o})}on(e,s){const t=this.listeners.get(e);t?t.add(s):this.listeners.set(e,new Set([s]))}queueEvent=(e,s,...t)=>{this.#o.set(e+String(s),[e,s,...t])};runListeners=(e,s,...t)=>{for(const r of this.listeners.get(e)||new Set)s?r(s,...t):r(...t)};startPluginsRun(){this.clear(),this.#s=new Promise(e=>{this.#c=e})}waitForPluginsLifecycle(){return Promise.all([this.#s,this.#l,this.#u])}waitForPluginsRun(){return this.#s}finishPluginsRun(){this.#c?.();for(const e of this.#o.values())this.runListeners(...e);this.#o.clear()}startEsbuildRun(){this.#l=new Promise(e=>{this.#d=e})}finishEsbuildRun(){this.#d?.()}markRequestHandlersEntryOutdated(){this.#r++,!this.#e&&(this.#e=!0,this.#u=new Promise(e=>{this.#h=e}))}noteRequestHandlersEntryBuildStart(){this.#f=this.#r}markRequestHandlersEntryUpdated(){this.#e&&(this.#r>this.#f||(this.#e=!1,this.#h?.()))}get contentDir(){if(this.serverMode)throw new Error("contentDir should not be used in server mode");return this.#i}markUserCodeReady(){this.#n?.(!0)}async reloadMarkdocOptions(){await Z("com.redocly.build.reloadMarkdocOptions",async()=>{const e=v.instance(),s=await j(this.serverOutDir),t=Object.fromEntries(Object.entries(s.tags).filter(([r])=>R[r]!=null?e.canAccessFeature(R[r]):!0));this.#a={...s,tags:t}})}get markdocOptions(){return{...this.#a,partials:this.getGlobalConfig(m),themeConfig:this.config.markdown}}setGlobalData=e=>{const s=this.globalData,t={...this.globalData,...e};this.globalData=t,JSON.stringify(t)!==JSON.stringify(s)&&this.queueEvent("global-data-updated",void 0,t)};getGlobalData=()=>this.globalData;getKv=async()=>F.getInstance({baseDbDir:this.serverOutDir});parseMarkdoc=async({input:e,context:s,deps:t,resource:r})=>{const{data:{info:o,ast:i},compoundHash:l}=await T(e,this.markdocOptions,{actions:this,context:s},r);for(const a of o.sharedDataDeps||[]){for(const n of t?.routeSlugs||[])this.addRouteSharedData(n,a,a);for(const n of t?.sharedDataIds||[]){const c=this.sharedDataDeps.get(n)||new Set;c.add(a),this.sharedDataDeps.set(n,c)}}for(const a of o.dynamicMarkdocComponents||[]){for(const n of t?.routeSlugs||[]){const c=this.routesDynamicComponents.get(n)||new Set;c.add(a),this.routesDynamicComponents.set(n,c)}for(const n of t?.sharedDataIds||[]){const c=this.sharedDataMarkdocComponents.get(n)||new Set;c.add(a),this.sharedDataMarkdocComponents.set(n,c)}}if(t?.routeSlugs&&o.partials?.length)for(const a of t.routeSlugs){const n=this.routesPartials.get(a)||[];for(const c of o.partials)n.includes(c)||n.push(c);this.routesPartials.set(a,n)}return{info:o,ast:i,compoundHash:l}};async loadApiDocuments(e){return(await e.cache.load(".","api-docs")).data}setSearchEngine(e){this.searchEngine=e}setSearchFacets=e=>{this.searchFacets=e};setGlobalConfig=e=>{const s=Object.keys(e);for(const l of s)for(const a in this.replacedEnvVars)if(a===l||a.startsWith(`${l}:`)){const n=a.split(":"),{error:c,value:d}=y(e,n);(c||d!==this.replacedEnvVars[a].replaced)&&delete this.replacedEnvVars[a]}const{resolvedObj:t,unsetEnvVars:r,replacedValues:o}=W(e);for(const l of r)this.unsetEnvVars.add(l);Object.assign(this.replacedEnvVars,o);const i=t.seo?.siteUrl?.trim();i&&(t.seo={...t.seo,siteUrl:URL.canParse(i)?new URL(i).origin:D(i)}),Object.assign(this.config,t)};getConfig=()=>this.config;getGlobalConfig=e=>this.config[e];getSearchFacets=()=>this.searchFacets;addRedirect=(e,s,t={})=>{if(!v.instance().canAccessFeature("redirects")&&e!=="/")return;this.config.redirects||(this.config.redirects={});const i=h(e).toLowerCase();this.config.redirects[i]=s;const{trackOriginalSource:l=!0}=t,a=this.getGlobalConfig("originalRedirectSources");l&&Array.isArray(a)&&!a.includes(i)&&a.push(i),i.endsWith("*")&&Y(this.config.wildcardRedirectsTree,i)};getRedirect=e=>{const s=h(e).toLowerCase(),t=$(s,this.config.redirects,this.config.wildcardRedirectsTree);if(!t)return null;if(S(t.to)){const r=h(t.to).toLowerCase();if(!r.endsWith("*")&&z(r,[s],this.config.redirects,this.config.wildcardRedirectsTree).type==="cycle")return null}return{to:t.to,type:t.type}};createSharedData=async(e,s,t)=>{if(t&&this.#t[e]===t)return e;const r=JSON.stringify(s),o=t??G(r);return this.#t[e]===o||(this.#t[e]=o,await N(e,r,this.outdir),this.queueEvent("shared-data-updated",e)),e};addRouteSharedData=(e,s,t)=>{const r=D(e),o=this.routesSharedData.get(r)||{};o[s]=t,this.routesSharedData.set(r,o),u.verbose(`Adding shared data to ${e}, ${s}, ${t}`)};getRouteSharedDataByFsPath=e=>{const s=this.routesByFsPath.get(e);return s?this.routesSharedData.get(s)||{}:{}};getPartialsForRoute=e=>{const s=this.getGlobalConfig(m)||{},t=this.routesPartials.get(e);if(!t||t.length===0)return{};const r=this.getGlobalConfig(k)||{},o=new Set(t),i=Array.from(t);for(let a=0;a<i.length;a++){const n=i[a],c=r[n]?.partials??[];for(const d of c)o.has(d)||(o.add(d),i.push(d))}const l={};for(const a of o)s[a]&&(l[a]=s[a]);return l};addRoute=e=>{const t={...J(e.fsPath,this.config.metadataGlobs),...e.metadata||{}};this.newRoutes.push({...e,metadata:t}),u.verbose("Created route %s",e.slug)};addRouteSharedDataToAllLocales=(e,s,t)=>{const r=[g,...this.lifecycleContext?.fs.localeFolders||[]].map(o=>({code:o,name:o}));for(const o of r){const i=M(e,g,o.code,r);this.addRouteSharedData(i,s,t)}};addApiRoute=e=>{this.apiRoutes.push(e),u.verbose("Created API route %s",e.slug)};addMcpTools=(e,s)=>{for(const t of s){const r=this.mcpToolHandlers.get(t.name);r&&r.importPath!==e&&u.warn('MCP tool "%s" from %s overwrites the tool registered from %s',t.name,e,r.importPath),this.mcpToolHandlers.set(t.name,{...t,importPath:e}),u.verbose("Created MCP tool %s",t.name)}};getMcpTools=()=>Array.from(this.mcpToolHandlers.values());markGatedMcpTools=e=>{for(const s of e){const t=this.mcpToolHandlers.get(s);t&&this.mcpToolHandlers.set(s,{...t,hasAvailabilityGate:!0})}};addSkills=e=>{for(const s of e)this.skills.set(s.slug,s),u.verbose("Discovered skill %s",s.slug)};getSkills=()=>Array.from(this.skills.values());removeMcpTools=e=>{for(const s of e)this.mcpToolHandlers.delete(s)};addMiddleware=e=>{this.middleware.push(e),u.verbose("Created middleware %s",e.id)};setResourceResponseHeaders=(e,s)=>{this.config.responseHeaders||(this.config.responseHeaders={});const t=new Set(s.map(i=>i.name.toLowerCase())),o=[...(this.config.responseHeaders[e]??[]).filter(i=>!t.has(i.name.toLowerCase())),...s];this.config.responseHeaders[e]=o};getRouteByFsPath=e=>{const s=this.routesByFsPath.get(e);return s?this.getRouteBySlug(s):void 0};getRouteBySlug=(e,s={})=>{const{followRedirect:t=!0}=s,r=this.getRedirect(e);return t&&r?this.routesBySlug.get(h(r.to)):this.routesBySlug.get(e)};hasRouteOrRedirectBySlug=e=>{if(this.routesBySlug.has(e)||x(e,this.getConfig()))return!0;const s=this.getRedirect(e);if(!s)return!1;if(!S(s.to))return!0;const t=h(s.to);return this.routesBySlug.has(t)};getRoutesByTemplateId=e=>this.newRoutes.filter(s=>s.templateId===e);getAllRoutesForLocale=(e=g)=>{const s=Array.from(this.routesBySlug.values()),t=e.toLowerCase();return s.filter(r=>e===g?!K(r.fsPath):r.slug.startsWith(`/${t}`))};getAllRoutes=()=>Array.from(this.routesBySlug.values());getAllApiRoutes=()=>this.apiRoutes;getAllMiddleware=()=>this.middleware;getTemplate=e=>this.templates.get(e);getRequestHandler=e=>this.apiRoutesRequestHandlers.get(e);createTemplate=(e,s)=>(this.templates.set(e,s),e);addBrowserPlugin=e=>{this.browserPlugins.add(e)};createRequestHandler=(e,s)=>(this.apiRoutesRequestHandlers.set(e,s),e);clearRequestHandlersByPrefix=e=>{for(const s of this.apiRoutesRequestHandlers.keys())s.startsWith(e)&&this.apiRoutesRequestHandlers.delete(s)};registerServerPropsGetter=(e,s)=>(this.serverPropsGetters.set(e,s),e);registerPagePropsGetter=(e,s)=>{this.pagePropsGetters.set(e,s)};async writeRouteStaticData(e,s){const t=await this.resolveRouteStaticData(e,s,!1);t&&U(e.slug,t,this.outdir)}async resolveRouteStaticData(e,s,t){if(this.serverMode)return q(e.slug,this.outdir);const r={...this,contentDir:this.contentDir,parseMarkdoc:({input:c,context:d,resource:f})=>this.parseMarkdoc({input:c,context:d,deps:{routeSlugs:[e.slug]},resource:f})},o=await e.getStaticData?.(e,r)||{},i=new Set(this.routesDynamicComponents.get(e.slug)),l=this.routesSharedData.get(e.slug)||{};for(const c of Object.values(l)){const d=this.sharedDataMarkdocComponents.get(c);d&&d.forEach(p=>i.add(p));const f=this.sharedDataDeps.get(c);f&&f.forEach(p=>this.addRouteSharedData(e.slug,p,p))}const a=this.getGlobalConfig("seo"),n=o?.frontmatter||{};return{...o,frontmatter:{...n,seo:{...n?.seo,title:n?.seo?.title||await e.getNavText?.()}},props:{...o.props,dynamicMarkdocComponents:Array.from(i),metadata:{...o?.props?.metadata,...e.metadata},seo:{title:O,...a,...o.props?.seo,siteUrl:a?.siteUrl},compilationErrors:this.compilationErrors},lastModified:t||!e.fsPath?null:await this.lifecycleContext?.fs.getLastModified(e.fsPath)}}addSsrComponents(e,s){if(!e?.length)return;const t=typeof e[0]=="string"?e.join(""):V(e);t&&(s==="head"?this.ssr.headTags.push(t):s==="preBody"?this.ssr.preBodyTags.push(t):this.ssr.postBodyTags.push(t))}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.skills.clear(),this.config.redirects={},this.config.wildcardRedirectsTree={},this.config.directoryPermissions={},this.ssr={preBodyTags:[],postBodyTags:[],headTags:[]}};async toJson(){const e=[];for(const[t,r]of Object.entries(E))switch(r){case"map":{const o=Array.from(this[t].entries());e.push([t,o]);break}case"object":if(t==="config"){e.push([t,await this.getConfigWithEnvPlaceholders()]);break}e.push([t,this[t]]);break;default:throw new Error("Invalid format")}const s=Object.fromEntries(e);return s[P]=_.PLAN_GATES,s}static fromJson(e,s){const t=new b(s);for(const[o,i]of Object.entries(E))switch(i){case"map":t[o]=new Map(e[o]);break;case"object":if(o==="config"){t.setGlobalConfig(e[o]);break}t[o]=e[o];break;default:throw new Error("Invalid format")}t.config[m]=X(t.config[m]||{});const r=e[P];return r&&B("PLAN_GATES",r),t}async getConfigWithEnvPlaceholders(){const e=JSON.parse(JSON.stringify(this.config));for(const s in this.replacedEnvVars){const{original:t}=this.replacedEnvVars[s],r=s.split(":"),o=r.pop(),{error:i,value:l}=y(e,r);if(i||!L(l)&&!Array.isArray(l)){await w.panicOnBuild(`Failed to replace env var with env name for ${s}`);continue}l[o]=t}return e}async reportUnsetEnvVars(){if(this.unsetEnvVars.size===0)return;const e=Array.from(this.unsetEnvVars).filter(t=>!Q.includes(t));if(e.length===0)return;const s=`Failed to resolve config. The following environment variables are not set: ${e.join(", ")}`;await w.panicOnBuildContentError(s)}}function X(C){return H(C,e=>A.Ast.fromJSON(JSON.stringify(e)))}export{b as Store,ke as USER_DEFINED_API_FUNCTIONS_COUNTER_KEY};
1
+ import A from"@markdoc/markdoc";import{parseAndResolveMarkdoc as T}from"./plugins/markdown/compiler.js";import{getPathnameForLocale as M}from"@redocly/theme/core/utils";import{DEFAULT_LOCALE_PLACEHOLDER as g}from"../constants/common.js";import{DEFAULT_TITLE as O,MARKDOC_PARTIALS_DATA_KEY as m,MARKDOC_PARTIALS_DEPS_KEY as k}from"./constants/common.js";import{GATED_MARKDOC_TAGS as R}from"./constants/entitlements.js";import{isObject as L}from"../utils/guards/is-object.js";import{mapObject as H}from"../utils/object/map-object.js";import{getValueDeep as y}from"../utils/object/get-value-deep.js";import{removeTrailingSlash as D}from"../utils/url/remove-trailing-slash.js";import{normalizeRouteSlug as u}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 h}from"./tools/notifiers/logger.js";import{sha1 as F}from"./utils/crypto/sha1.js";import{envConfig as G,setEnv as _}from"./config/env-config.js";import{KvService as B}from"./persistence/kv/services/kv-service.js";import{SandboxContext as I}from"./utils/sandbox-context.js";import{writeSharedData as N}from"./utils/index.js";import{renderComponents as V}from"./ssr/render.js";import{readStaticData as q,writeStaticData as j}from"./utils/static-data.js";import{getMarkdocOptions as U}from"./plugins/markdown/markdoc/markdoc-options.js";import{EntitlementsProvider as v}from"./entitlements/entitlements-provider.js";import{isRouteReserved as x}from"./plugins/get-reserved-routes.js";import{isL10nPath as K}from"./fs/utils/is-l10n-path.js";import{resolveGlobMapValue as J}from"./utils/globs.js";import{replaceEnvVariablesDeep as W}from"./utils/envs/replace-env-variables-deep.js";import{findRedirect as $}from"./utils/redirects/find-redirect.js";import{followRedirectChain as z}from"./utils/redirects/follow-redirect-chain.js";import{addWildcardRedirectToTree as Y}from"./utils/redirects/add-wildcard-redirect-to-tree.js";import{telemetryTraceStep as Z}from"../cli/telemetry/helpers/trace-step.js";const E={routesBySlug:"map",staticFilePaths:"object",apiRoutes:"object",middleware:"object",routesByFsPath:"map",routesSharedData:"map",globalData:"object",config:"object",ssr:"object",searchFacets:"map",routesPartials:"map",mcpToolHandlers:"map",skills:"map",devLogin:"object"},P="PLAN_GATES",Q=["OAUTH_CLIENT_ID","OAUTH_CLIENT_SECRET","ORGANIZATION_SLUG","ORGANIZATION_ID","ORG_ID"],ke="userDefinedApiFunctions";class b{routesBySlug=new Map;staticFilePaths={};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;skills=new Map;serverPropsGetters=new Map;pagePropsGetters=new Map;listeners=new Map;globalData={};devLogin=!1;#o=void 0;config={configFilePath:"",redirects:{},wildcardRedirectsTree:{},access:{rbac:{},requiresLogin:!1},directoryPermissions:{},devLogin:!1,ssoDirect:{}};#i;serverMode;serverOutDir;outdir;buildRevision=0;hasSitemap=!1;compilationErrors=[];#n;userCodeReady;#s=Promise.resolve();#c;#l=Promise.resolve();#d;#h=Promise.resolve();#u;#e=!1;#r=0;#f=0;#a=new Map;constructor({outdir:e,contentDir:s,serverMode:t=!1,serverOutDir:r}){this.#i=s,this.outdir=e,this.serverMode=t,this.serverOutDir=r,I.register({serverOutDir:r,readRoots:[e,process.cwd()]}),this.userCodeReady=new Promise(a=>{this.#n=a})}on(e,s){const t=this.listeners.get(e);t?t.add(s):this.listeners.set(e,new Set([s]))}queueEvent=(e,s,...t)=>{this.#a.set(e+String(s),[e,s,...t])};runListeners=(e,s,...t)=>{for(const r of this.listeners.get(e)||new Set)s?r(s,...t):r(...t)};startPluginsRun(){this.clear(),this.#s=new Promise(e=>{this.#c=e})}waitForPluginsLifecycle(){return Promise.all([this.#s,this.#l,this.#h])}waitForPluginsRun(){return this.#s}finishPluginsRun(){this.#c?.();for(const e of this.#a.values())this.runListeners(...e);this.#a.clear()}startEsbuildRun(){this.#l=new Promise(e=>{this.#d=e})}finishEsbuildRun(){this.#d?.()}markRequestHandlersEntryOutdated(){this.#r++,!this.#e&&(this.#e=!0,this.#h=new Promise(e=>{this.#u=e}))}noteRequestHandlersEntryBuildStart(){this.#f=this.#r}markRequestHandlersEntryUpdated(){this.#e&&(this.#r>this.#f||(this.#e=!1,this.#u?.()))}get contentDir(){if(this.serverMode)throw new Error("contentDir should not be used in server mode");return this.#i}markUserCodeReady(){this.#n?.(!0)}async reloadMarkdocOptions(){await Z("com.redocly.build.reloadMarkdocOptions",async()=>{const e=v.instance(),s=await U(this.serverOutDir),t=Object.fromEntries(Object.entries(s.tags).filter(([r])=>R[r]!=null?e.canAccessFeature(R[r]):!0));this.#o={...s,tags:t}})}get markdocOptions(){return{...this.#o,partials:this.getGlobalConfig(m),themeConfig:this.config.markdown}}setGlobalData=e=>{const s=this.globalData,t={...this.globalData,...e};this.globalData=t,JSON.stringify(t)!==JSON.stringify(s)&&this.queueEvent("global-data-updated",void 0,t)};getGlobalData=()=>this.globalData;getKv=async()=>B.getInstance({baseDbDir:this.serverOutDir});parseMarkdoc=async({input:e,context:s,deps:t,resource:r})=>{const{data:{info:a,ast:i},compoundHash:l}=await T(e,this.markdocOptions,{actions:this,context:s},r);for(const o of a.sharedDataDeps||[]){for(const n of t?.routeSlugs||[])this.addRouteSharedData(n,o,o);for(const n of t?.sharedDataIds||[]){const c=this.sharedDataDeps.get(n)||new Set;c.add(o),this.sharedDataDeps.set(n,c)}}for(const o of a.dynamicMarkdocComponents||[]){for(const n of t?.routeSlugs||[]){const c=this.routesDynamicComponents.get(n)||new Set;c.add(o),this.routesDynamicComponents.set(n,c)}for(const n of t?.sharedDataIds||[]){const c=this.sharedDataMarkdocComponents.get(n)||new Set;c.add(o),this.sharedDataMarkdocComponents.set(n,c)}}if(t?.routeSlugs&&a.partials?.length)for(const o of t.routeSlugs){const n=this.routesPartials.get(o)||[];for(const c of a.partials)n.includes(c)||n.push(c);this.routesPartials.set(o,n)}return{info:a,ast:i,compoundHash:l}};async loadApiDocuments(e){return(await e.cache.load(".","api-docs")).data}setSearchEngine(e){this.searchEngine=e}setSearchFacets=e=>{this.searchFacets=e};setStaticFilePaths=e=>{this.staticFilePaths=e};setGlobalConfig=e=>{const s=Object.keys(e);for(const l of s)for(const o in this.replacedEnvVars)if(o===l||o.startsWith(`${l}:`)){const n=o.split(":"),{error:c,value:d}=y(e,n);(c||d!==this.replacedEnvVars[o].replaced)&&delete this.replacedEnvVars[o]}const{resolvedObj:t,unsetEnvVars:r,replacedValues:a}=W(e);for(const l of r)this.unsetEnvVars.add(l);Object.assign(this.replacedEnvVars,a);const i=t.seo?.siteUrl?.trim();i&&(t.seo={...t.seo,siteUrl:URL.canParse(i)?new URL(i).origin:D(i)}),Object.assign(this.config,t)};getConfig=()=>this.config;getGlobalConfig=e=>this.config[e];getSearchFacets=()=>this.searchFacets;addRedirect=(e,s,t={})=>{if(!v.instance().canAccessFeature("redirects")&&e!=="/")return;this.config.redirects||(this.config.redirects={});const i=u(e).toLowerCase();this.config.redirects[i]=s;const{trackOriginalSource:l=!0}=t,o=this.getGlobalConfig("originalRedirectSources");l&&Array.isArray(o)&&!o.includes(i)&&o.push(i),i.endsWith("*")&&Y(this.config.wildcardRedirectsTree,i)};getRedirect=e=>{const s=u(e).toLowerCase(),t=$(s,this.config.redirects,this.config.wildcardRedirectsTree,this.staticFilePaths);if(!t)return null;if(S(t.to)){const r=u(t.to).toLowerCase();if(!r.endsWith("*")&&z(r,[s],this.config.redirects,this.config.wildcardRedirectsTree).type==="cycle")return null}return{to:t.to,type:t.type}};createSharedData=async(e,s,t)=>{if(t&&this.#t[e]===t)return e;const r=JSON.stringify(s),a=t??F(r);return this.#t[e]===a||(this.#t[e]=a,await N(e,r,this.outdir),this.queueEvent("shared-data-updated",e)),e};addRouteSharedData=(e,s,t)=>{const r=D(e),a=this.routesSharedData.get(r)||{};a[s]=t,this.routesSharedData.set(r,a),h.verbose(`Adding shared data to ${e}, ${s}, ${t}`)};getRouteSharedDataByFsPath=e=>{const s=this.routesByFsPath.get(e);return s?this.routesSharedData.get(s)||{}:{}};getPartialsForRoute=e=>{const s=this.getGlobalConfig(m)||{},t=this.routesPartials.get(e);if(!t||t.length===0)return{};const r=this.getGlobalConfig(k)||{},a=new Set(t),i=Array.from(t);for(let o=0;o<i.length;o++){const n=i[o],c=r[n]?.partials??[];for(const d of c)a.has(d)||(a.add(d),i.push(d))}const l={};for(const o of a)s[o]&&(l[o]=s[o]);return l};addRoute=e=>{const t={...J(e.fsPath,this.config.metadataGlobs),...e.metadata||{}};this.newRoutes.push({...e,metadata:t}),h.verbose("Created route %s",e.slug)};addRouteSharedDataToAllLocales=(e,s,t)=>{const r=[g,...this.lifecycleContext?.fs.localeFolders||[]].map(a=>({code:a,name:a}));for(const a of r){const i=M(e,g,a.code,r);this.addRouteSharedData(i,s,t)}};addApiRoute=e=>{this.apiRoutes.push(e),h.verbose("Created API route %s",e.slug)};addMcpTools=(e,s)=>{for(const t of s){const r=this.mcpToolHandlers.get(t.name);r&&r.importPath!==e&&h.warn('MCP tool "%s" from %s overwrites the tool registered from %s',t.name,e,r.importPath),this.mcpToolHandlers.set(t.name,{...t,importPath:e}),h.verbose("Created MCP tool %s",t.name)}};getMcpTools=()=>Array.from(this.mcpToolHandlers.values());markGatedMcpTools=e=>{for(const s of e){const t=this.mcpToolHandlers.get(s);t&&this.mcpToolHandlers.set(s,{...t,hasAvailabilityGate:!0})}};addSkills=e=>{for(const s of e)this.skills.set(s.slug,s),h.verbose("Discovered skill %s",s.slug)};getSkills=()=>Array.from(this.skills.values());removeMcpTools=e=>{for(const s of e)this.mcpToolHandlers.delete(s)};addMiddleware=e=>{this.middleware.push(e),h.verbose("Created middleware %s",e.id)};setResourceResponseHeaders=(e,s)=>{this.config.responseHeaders||(this.config.responseHeaders={});const t=new Set(s.map(i=>i.name.toLowerCase())),a=[...(this.config.responseHeaders[e]??[]).filter(i=>!t.has(i.name.toLowerCase())),...s];this.config.responseHeaders[e]=a};getRouteByFsPath=e=>{const s=this.routesByFsPath.get(e);return s?this.getRouteBySlug(s):void 0};getRouteBySlug=(e,s={})=>{const{followRedirect:t=!0}=s,r=this.getRedirect(e);return t&&r?this.routesBySlug.get(u(r.to)):this.routesBySlug.get(e)};hasRouteOrRedirectBySlug=e=>{if(this.routesBySlug.has(e)||x(e,this.getConfig()))return!0;const s=this.getRedirect(e);if(!s)return!1;if(!S(s.to))return!0;const t=u(s.to);return this.routesBySlug.has(t)};getRoutesByTemplateId=e=>this.newRoutes.filter(s=>s.templateId===e);getAllRoutesForLocale=(e=g)=>{const s=Array.from(this.routesBySlug.values()),t=e.toLowerCase();return s.filter(r=>e===g?!K(r.fsPath):r.slug.startsWith(`/${t}`))};getAllRoutes=()=>Array.from(this.routesBySlug.values());getAllApiRoutes=()=>this.apiRoutes;getAllMiddleware=()=>this.middleware;getTemplate=e=>this.templates.get(e);getRequestHandler=e=>this.apiRoutesRequestHandlers.get(e);createTemplate=(e,s)=>(this.templates.set(e,s),e);addBrowserPlugin=e=>{this.browserPlugins.add(e)};createRequestHandler=(e,s)=>(this.apiRoutesRequestHandlers.set(e,s),e);clearRequestHandlersByPrefix=e=>{for(const s of this.apiRoutesRequestHandlers.keys())s.startsWith(e)&&this.apiRoutesRequestHandlers.delete(s)};registerServerPropsGetter=(e,s)=>(this.serverPropsGetters.set(e,s),e);registerPagePropsGetter=(e,s)=>{this.pagePropsGetters.set(e,s)};async writeRouteStaticData(e,s){const t=await this.resolveRouteStaticData(e,s,!1);t&&j(e.slug,t,this.outdir)}async resolveRouteStaticData(e,s,t){if(this.serverMode)return q(e.slug,this.outdir);const r={...this,contentDir:this.contentDir,parseMarkdoc:({input:c,context:d,resource:f})=>this.parseMarkdoc({input:c,context:d,deps:{routeSlugs:[e.slug]},resource:f})},a=await e.getStaticData?.(e,r)||{},i=new Set(this.routesDynamicComponents.get(e.slug)),l=this.routesSharedData.get(e.slug)||{};for(const c of Object.values(l)){const d=this.sharedDataMarkdocComponents.get(c);d&&d.forEach(p=>i.add(p));const f=this.sharedDataDeps.get(c);f&&f.forEach(p=>this.addRouteSharedData(e.slug,p,p))}const o=this.getGlobalConfig("seo"),n=a?.frontmatter||{};return{...a,frontmatter:{...n,seo:{...n?.seo,title:n?.seo?.title||await e.getNavText?.()}},props:{...a.props,dynamicMarkdocComponents:Array.from(i),metadata:{...a?.props?.metadata,...e.metadata},seo:{title:O,...o,...a.props?.seo,siteUrl:o?.siteUrl},compilationErrors:this.compilationErrors},lastModified:t||!e.fsPath?null:await this.lifecycleContext?.fs.getLastModified(e.fsPath)}}addSsrComponents(e,s){if(!e?.length)return;const t=typeof e[0]=="string"?e.join(""):V(e);t&&(s==="head"?this.ssr.headTags.push(t):s==="preBody"?this.ssr.preBodyTags.push(t):this.ssr.postBodyTags.push(t))}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.skills.clear(),this.config.redirects={},this.config.wildcardRedirectsTree={},this.config.directoryPermissions={},this.ssr={preBodyTags:[],postBodyTags:[],headTags:[]}};async toJson(){const e=[];for(const[t,r]of Object.entries(E))switch(r){case"map":{const a=Array.from(this[t].entries());e.push([t,a]);break}case"object":if(t==="config"){e.push([t,await this.getConfigWithEnvPlaceholders()]);break}e.push([t,this[t]]);break;default:throw new Error("Invalid format")}const s=Object.fromEntries(e);return s[P]=G.PLAN_GATES,s}static fromJson(e,s){const t=new b(s);for(const[a,i]of Object.entries(E))switch(i){case"map":t[a]=new Map(e[a]);break;case"object":if(a==="config"){t.setGlobalConfig(e[a]);break}t[a]=e[a];break;default:throw new Error("Invalid format")}t.config[m]=X(t.config[m]||{});const r=e[P];return r&&_("PLAN_GATES",r),t}async getConfigWithEnvPlaceholders(){const e=JSON.parse(JSON.stringify(this.config));for(const s in this.replacedEnvVars){const{original:t}=this.replacedEnvVars[s],r=s.split(":"),a=r.pop(),{error:i,value:l}=y(e,r);if(i||!L(l)&&!Array.isArray(l)){await w.panicOnBuild(`Failed to replace env var with env name for ${s}`);continue}l[a]=t}return e}async reportUnsetEnvVars(){if(this.unsetEnvVars.size===0)return;const e=Array.from(this.unsetEnvVars).filter(t=>!Q.includes(t));if(e.length===0)return;const s=`Failed to resolve config. The following environment variables are not set: ${e.join(", ")}`;await w.panicOnBuildContentError(s)}}function X(C){return H(C,e=>A.Ast.fromJSON(JSON.stringify(e)))}export{b as Store,ke as USER_DEFINED_API_FUNCTIONS_COUNTER_KEY};
@@ -3,5 +3,6 @@ export type * from './plugin-hooks';
3
3
  export type * from './plugins';
4
4
  export type * from './web-server';
5
5
  export type * from './redirects';
6
+ export type * from './static-files';
6
7
  export type * from './tools';
7
8
  //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Every file of the `static` folder, keyed by its lowercased URL path with the real URL path as the value.
3
+ * Built once per build; files added while developing appear after a restart.
4
+ */
5
+ export type StaticFilePaths = Record<string, string>;
6
+ //# sourceMappingURL=static-files.d.ts.map
File without changes
@@ -0,0 +1,15 @@
1
+ import type { StaticFilePaths } from '../../types';
2
+ /**
3
+ * Indexes the files of the `static` folder by their lowercased URL path,
4
+ * so a path can be looked up regardless of its casing.
5
+ *
6
+ * @param contentDir - The project content directory that holds the `static` folder.
7
+ * @returns The index, empty when the folder is missing.
8
+ *
9
+ * @example
10
+ * // static/1.0.7/Tags.yaml and static/robots.txt
11
+ * buildStaticFilePaths(contentDir);
12
+ * // Returns: { '/1.0.7/tags.yaml': '/1.0.7/Tags.yaml', '/robots.txt': '/robots.txt' }
13
+ */
14
+ export declare function buildStaticFilePaths(contentDir: string): StaticFilePaths;
15
+ //# sourceMappingURL=build-static-file-paths.d.ts.map
@@ -0,0 +1 @@
1
+ import i from"path";import{PUBLIC_STATIC_FOLDER as s}from"../../constants/common.js";import{slash as m}from"../../../utils/path/slash.js";import{readFileNames as c}from"../fs.js";function h(a){const t=i.join(a,s),o={};for(const e of c(t)){const r="/"+m(i.relative(t,e));o[r.toLowerCase()]=r}return o}export{h as buildStaticFilePaths};
@@ -1 +1 @@
1
- import*as t from"path";import{cliCommandNames as r}from"../../constants/common.js";import{PUBLIC_STATIC_FOLDER as i}from"../constants/common.js";import{logger as n}from"../tools/notifiers/logger.js";import{blue as f,gray as l}from"../tools/notifiers/helpers/colors.js";import{loadEnvVariables as p}from"./envs/load-env-variables.js";import{copyFolderRecursiveSync as c}from"./fs.js";import{validateInstalledVersion as s}from"./validate-installed-version.js";import{PACKAGE_NAME as E}from"../../config/product-gates.js";import{PORTAL_VERSION as P}from"../version.js";import{setEnv as u}from"../config/env-config.js";function L(o){return o?"true":"false"}function d(o){const e={};o["log-level"]&&(e.REDOCLY_LOG_LEVEL=String(o["log-level"])),e.INSPECT_MODE="inspect"in o?L(o.inspect):"false",o.pathPrefix&&(e.REDOCLY_PREFIX_PATHS=o.pathPrefix),u(e)}function v({contentDir:o,outdir:e}){c(t.join(o,i),t.join(e,i))}async function S(o,e,m){await p(e["project-dir"]);const a=o===r.DEVELOP?" Previewing with":"Building with";switch(n.logInFooter("product",`${a} ${f(`${E}@${P}`)}`),n.logInFooter("server",` \u{1F310} Preview URL: ${l("server starting...")}`),o){case r.DEVELOP:case r.BUILD:case r.PREPARE:d(e);break;default:break}await s(),v(m)}export{S as beforeCommand};
1
+ import*as r from"path";import{cliCommandNames as e}from"../../constants/common.js";import{PUBLIC_STATIC_FOLDER as n}from"../constants/common.js";import{logger as m}from"../tools/notifiers/logger.js";import{blue as l,gray as f}from"../tools/notifiers/helpers/colors.js";import{loadEnvVariables as c}from"./envs/load-env-variables.js";import{buildStaticFilePaths as p}from"./content/build-static-file-paths.js";import{copyFolderRecursiveSync as s}from"./fs.js";import{validateInstalledVersion as E}from"./validate-installed-version.js";import{PACKAGE_NAME as P}from"../../config/product-gates.js";import{PORTAL_VERSION as u}from"../version.js";import{setEnv as d}from"../config/env-config.js";function L(o){return o?"true":"false"}function v(o){const t={};o["log-level"]&&(t.REDOCLY_LOG_LEVEL=String(o["log-level"])),t.INSPECT_MODE="inspect"in o?L(o.inspect):"false",o.pathPrefix&&(t.REDOCLY_PREFIX_PATHS=o.pathPrefix),d(t)}function C({contentDir:o,outdir:t}){s(r.join(o,n),r.join(t,n))}async function b(o,t,i){await c(t["project-dir"]);const a=o===e.DEVELOP?" Previewing with":"Building with";switch(m.logInFooter("product",`${a} ${l(`${P}@${u}`)}`),m.logInFooter("server",` \u{1F310} Preview URL: ${f("server starting...")}`),o){case e.DEVELOP:case e.BUILD:case e.PREPARE:v(t);break;default:break}await E(),C(i),i.setStaticFilePaths(p(i.contentDir))}export{b as beforeCommand};
@@ -1,16 +1,17 @@
1
1
  import type { RedirectConfig, RedirectsConfig } from '@redocly/config';
2
- import type { WildcardRedirectsTree } from '../../types';
2
+ import type { StaticFilePaths, WildcardRedirectsTree } from '../../types';
3
3
  /**
4
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
7
  *
8
- * - For wildcard rules whose target ends with `*`, the remainder of the path is preserved.
8
+ * - For wildcard rules whose target ends with `*`, the remainder of the path is preserved;
9
+ * a target found in `staticFilePaths` is replaced by that file path, with its real casing.
9
10
  * - `from` is the matched config key (path or pattern); exposed for `followRedirectChain` rule tracking.
10
11
  *
11
12
  * @returns Redirect config with resolved `to`, plus `from`, or `null` if no rule matches or the rule would not change the slug.
12
13
  */
13
- export declare function findRedirect(slug: string, redirects: RedirectsConfig, wildcardRedirectsTree: WildcardRedirectsTree): (WithRequired<RedirectConfig, 'to'> & {
14
+ export declare function findRedirect(slug: string, redirects: RedirectsConfig, wildcardRedirectsTree: WildcardRedirectsTree, staticFilePaths?: StaticFilePaths): (WithRequired<RedirectConfig, 'to'> & {
14
15
  from: string;
15
16
  }) | null;
16
17
  //# sourceMappingURL=find-redirect.d.ts.map
@@ -1 +1 @@
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};
1
+ import{normalizeRouteSlug as l}from"../../../utils/path/normalize-route-slug.js";import{removeLeadingSlash as u}from"../../../utils/url/remove-leading-slash.js";function w(t,n,c,e={}){const o=n[t];if(o?.to){const f=o.to;return l(f).toLowerCase()===t?null:{to:f,type:o.type,from:t}}const i=p(t,c);if(!i)return null;const a=n[i],d=a?.to;if(!d)return null;let r=d;if(r.endsWith("*")){const f=i.split("*")[0];r=r.replace(/\*$/,t.substring(f.length)),r=e[l(r).toLowerCase()]??r}return l(r).toLowerCase()===t?null:{...a,to:r,from:i}}function p(t,n){const c=u(t).split("/");let e=n;for(const o of c){if(!e[o])break;e=e[o]}return e["*"]||null}export{w as findRedirect};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@redocly/revel",
3
- "version": "0.139.0-next.10",
3
+ "version": "0.139.0-next.11",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "bin": {
@@ -33,13 +33,13 @@
33
33
  "@opentelemetry/sdk-trace-web": "2.8.0",
34
34
  "@opentelemetry/semantic-conventions": "1.40.0",
35
35
  "@redocly/ajv": "8.18.0",
36
- "@redocly/api-docs": "0.4.0-next.10",
36
+ "@redocly/api-docs": "0.4.0-next.11",
37
37
  "@redocly/config": "0.67.0",
38
- "@redocly/openapi-core": "2.64.0",
38
+ "@redocly/openapi-core": "2.66.0",
39
39
  "@redocly/portal-legacy-ui": "0.19.0",
40
- "@redocly/portal-plugin-mock-server": "0.24.0-next.2",
40
+ "@redocly/portal-plugin-mock-server": "0.24.0-next.3",
41
41
  "@redocly/realm-asyncapi-sdk": "0.17.0-next.1",
42
- "@redocly/theme": "0.71.0-next.6",
42
+ "@redocly/theme": "0.71.0-next.7",
43
43
  "@shikijs/transformers": "3.21.0",
44
44
  "@tanstack/react-query": "5.62.3",
45
45
  "@tanstack/react-table": "8.21.3",