@redocly/reef 0.133.0-next.6 → 0.134.0-next.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/CHANGELOG.md +114 -22
  2. package/dist/client/app/hooks/useBanner.js +1 -1
  3. package/dist/client/app/hooks/utils/match-banner-target.d.ts +7 -1
  4. package/dist/client/app/hooks/utils/match-banner-target.js +1 -1
  5. package/dist/client/app/markdoc/custom-components/openapi/json-schema.js +1 -1
  6. package/dist/client/app/markdoc/custom-components/openapi/replay-openapi.js +1 -1
  7. package/dist/constants/l10n/langs/ar.js +1 -1
  8. package/dist/constants/l10n/langs/de.js +1 -1
  9. package/dist/constants/l10n/langs/en.js +1 -1
  10. package/dist/constants/l10n/langs/es.js +1 -1
  11. package/dist/constants/l10n/langs/fr.js +1 -1
  12. package/dist/constants/l10n/langs/hi.js +1 -1
  13. package/dist/constants/l10n/langs/it.js +1 -1
  14. package/dist/constants/l10n/langs/ja.js +1 -1
  15. package/dist/constants/l10n/langs/ko.js +1 -1
  16. package/dist/constants/l10n/langs/pl.js +1 -1
  17. package/dist/constants/l10n/langs/pt-BR.js +1 -1
  18. package/dist/constants/l10n/langs/pt.js +1 -1
  19. package/dist/constants/l10n/langs/ru.js +1 -1
  20. package/dist/constants/l10n/langs/uk.js +1 -1
  21. package/dist/constants/l10n/langs/zh.js +1 -1
  22. package/dist/server/api-routes/execute-api-route.js +1 -1
  23. package/dist/server/plugins/api-functions/index.js +1 -1
  24. package/dist/server/plugins/asyncapi-docs/get-server-props.js +1 -1
  25. package/dist/server/plugins/catalog-entities/database/catalog-entities-publisher.d.ts +2 -2
  26. package/dist/server/plugins/catalog-entities/database/catalog-entities-publisher.js +6 -6
  27. package/dist/server/plugins/catalog-entities/database/remote-publish-lock-service.d.ts +22 -0
  28. package/dist/server/plugins/catalog-entities/database/remote-publish-lock-service.js +1 -0
  29. package/dist/server/plugins/catalog-entities/database/types.d.ts +1 -0
  30. package/dist/server/plugins/catalog-entities/plugin.js +1 -1
  31. package/dist/server/plugins/markdown/markdown-frontmatter-loader.js +1 -1
  32. package/dist/server/plugins/mcp/handlers/docs-mcp-handler.js +1 -1
  33. package/dist/server/plugins/mcp/servers/docs-server.js +1 -1
  34. package/dist/server/plugins/mcp/types.d.ts +1 -0
  35. package/dist/server/plugins/openapi-docs/get-server-props.js +1 -1
  36. package/dist/server/utils/rbac.js +1 -1
  37. package/package.json +9 -9
@@ -8,6 +8,7 @@ export type PublishCatalogEntitiesParams = {
8
8
  export type PublishCatalogEntitiesRunResult = {
9
9
  runId: string;
10
10
  published: boolean;
11
+ shouldFinalizeFileHashes: boolean;
11
12
  };
12
13
  export type PublishRowsResult = {
13
14
  upserted: number;
@@ -1 +1 @@
1
- import{FileHashStatus as A,FileType as f}from"../../persistence/file-hashes/types.js";import{envConfig as F}from"../../config/env-config.js";import{CATALOG_BASE_SLUG as h}from"../../../constants/catalog-entities.js";import{telemetryTraceStep as N}from"../../../cli/telemetry/helpers/trace-step.js";import{catalogDataCollector as m}from"./utils/catalog-data-collector.js";import{CATALOG_FILTERS_CACHE_NAMESPACE as H,ENTITIES_MAP_GLOBAL_DATA_KEY as L}from"../../constants/plugins/catalog-entities.js";import{CacheService as G}from"../../persistence/cache/services/cache-service.js";import{getTemplatePath as b}from"./utils/get-template-path.js";import{getCompleteCatalogConfig as y}from"./get-complete-catalog-config.js";import{AsyncApiEntitiesExtractor as x}from"./extensions/extractors/api-description/asyncapi-entities-extractor.js";import{GraphqlEntitiesExtractor as B}from"./extensions/extractors/api-description/graphql-entities-extractor.js";import{FileHashesService as M}from"../../persistence/file-hashes/services/file-hashes-service.js";import{CatalogEntitiesService as k}from"./database/catalog-entities-service.js";import{CatalogEntitiesPublisher as Y}from"./database/catalog-entities-publisher.js";import{ArazzoEntitiesExtractor as j}from"./extensions/extractors/api-description/arazzo-entities-extractor.js";import{FsEntitiesExtractor as q}from"./extensions/extractors/fs-entities-extractor.js";import{HashManager as z}from"./utils/hash-manager.js";import{RbacConfigHashCache as U}from"./utils/rbac-config-hash-cache.js";import{OpenApiEntitiesExtractor as W}from"./extensions/extractors/api-description/openapi-entities-extractor.js";const J="catalog-entity-template",Z="catalog-entity";let D=!0;async function $(){return{id:"CatalogEntities",requiredEntitlements:["catalog"],async processContent(t,e){const i=await e.getConfig(),r=y(i.entitiesCatalog);if(!r.show)return;const{logger:o}=e,s=t.registerServerPropsGetter(Z,b("../get-server-props.js")),g=t.createTemplate(J,b("../template/index.js"));t.addRoute({duplicateInAllLocales:!0,slug:h,fsPath:"",templateId:g,excludeFromSidebar:!0,hasClientRoutes:!0,serverPropsGetterIds:[s],getNavText:()=>Promise.resolve("Catalog"),getStaticData:async()=>({props:{catalogConfig:r}})});const[n]=Object.entries(r.catalogs??{}).find(([T,p])=>!p?.hide)||[];n&&t.addRedirect(h,{type:302,to:`${h}/${n}`},{trackOriginalSource:!1}),o.info("Catalog Entities plugin finished")},async afterRoutesCreated(t,e){await N("build.plugin.catalog_entities",async i=>{const r=await e.getConfig(),o=y(r.entitiesCatalog);if(i?.setAttribute("config",JSON.stringify(o)),!o.show)return;const{logger:s}=e;m.resetForRun();const g=D&&F.isDevelopMode,n=await G.getInstance({baseDbDir:t.serverOutDir,databaseType:"local"}),T=new U(n),{rbacConfigChanged:p}=await T.syncAndDetectChange(r.access?.rbac??null),l=g||p,a=await k.getInstance({baseDbDir:t.serverOutDir,removeExisting:g,databaseType:"local",runWithPragmaWalWriteOptimization:!0}),E=await M.getInstance({baseDbDir:t.serverOutDir,databaseType:"local"}),c=new z(E),S=[new q({fileHashManager:c,context:e,catalogEntitiesService:a,catalogConfig:o,shouldCalculateEntities:l}),new W({actions:t,context:e,catalogEntitiesService:a,fileHashManager:c,fileType:f.OPENAPI_DESCRIPTION,shouldCalculateEntities:l}),new x({actions:t,context:e,catalogEntitiesService:a,fileHashManager:c,fileType:f.ASYNCAPI_DESCRIPTION,shouldCalculateEntities:l}),new B({actions:t,context:e,catalogEntitiesService:a,fileHashManager:c,fileType:f.GRAPHQL_DESCRIPTION,shouldCalculateEntities:l}),new j({actions:t,context:e,catalogEntitiesService:a,fileHashManager:c,fileType:f.ARAZZO_DESCRIPTION,shouldCalculateEntities:l})];s.info("Starting entities extractors...");const P=s.startTiming();await a.transaction(async()=>{await Promise.all(S.map(async d=>d.extract()))});const O=a.getEntitySources();t.setGlobalData({[L]:O}),await n.deleteByNamespace(H),s.infoTime(P,"Entities extractors finished");const{changedSourceFiles:I,removedSourceFiles:C}=m.getPublishDelta(),_=s.startTiming();await Y.publishFromLocalToRemote(p?{baseDbDir:t.serverOutDir}:{baseDbDir:t.serverOutDir,changedSourceFiles:I,removedSourceFiles:C})&&s.infoTime(_,"Entities published to the database"),C.length&&await E.deleteFileHashes({op:"AND",conditions:[{field:"status",operator:"equal",value:A.OUTDATED},{field:"file_path",operator:"in",value:C}]});const v=m.getFileHashConfirmations();for(const{fileType:d,filePath:w,hash:R}of v)await E.upsertFileHash({fileType:d,filePath:w,hash:R,status:A.UP_TO_DATE});const u=await m.getCatalogEntitiesData(a);i?.setAttribute("totalEntities",u.totalEntitiesCount),i?.setAttribute("entitiesCountByType",JSON.stringify(u.countOfEntitiesByType)),i?.setAttribute("totalFilesSkippedByHash",u.totalFilesSkippedByHash),i?.setAttribute("totalProcessedFiles",u.totalProcessedFiles),i?.setAttribute("extractors",u.extractors),D=!1})}}}var Ct=$;export{$ as catalogEntitiesPlugin,Ct as default};
1
+ import{FileHashStatus as A,FileType as f}from"../../persistence/file-hashes/types.js";import{envConfig as H}from"../../config/env-config.js";import{CATALOG_BASE_SLUG as C}from"../../../constants/catalog-entities.js";import{telemetryTraceStep as N}from"../../../cli/telemetry/helpers/trace-step.js";import{catalogDataCollector as m}from"./utils/catalog-data-collector.js";import{CATALOG_FILTERS_CACHE_NAMESPACE as L,ENTITIES_MAP_GLOBAL_DATA_KEY as x}from"../../constants/plugins/catalog-entities.js";import{CacheService as G}from"../../persistence/cache/services/cache-service.js";import{getTemplatePath as y}from"./utils/get-template-path.js";import{getCompleteCatalogConfig as D}from"./get-complete-catalog-config.js";import{AsyncApiEntitiesExtractor as B}from"./extensions/extractors/api-description/asyncapi-entities-extractor.js";import{GraphqlEntitiesExtractor as M}from"./extensions/extractors/api-description/graphql-entities-extractor.js";import{FileHashesService as k}from"../../persistence/file-hashes/services/file-hashes-service.js";import{CatalogEntitiesService as z}from"./database/catalog-entities-service.js";import{CatalogEntitiesPublisher as Y}from"./database/catalog-entities-publisher.js";import{ArazzoEntitiesExtractor as j}from"./extensions/extractors/api-description/arazzo-entities-extractor.js";import{FsEntitiesExtractor as q}from"./extensions/extractors/fs-entities-extractor.js";import{HashManager as U}from"./utils/hash-manager.js";import{RbacConfigHashCache as W}from"./utils/rbac-config-hash-cache.js";import{OpenApiEntitiesExtractor as J}from"./extensions/extractors/api-description/openapi-entities-extractor.js";const Z="catalog-entity-template",$="catalog-entity";let S=!0;async function K(){return{id:"CatalogEntities",requiredEntitlements:["catalog"],async processContent(t,e){const i=await e.getConfig(),r=D(i.entitiesCatalog);if(!r.show)return;const{logger:o}=e,a=t.registerServerPropsGetter($,y("../get-server-props.js")),g=t.createTemplate(Z,y("../template/index.js"));t.addRoute({duplicateInAllLocales:!0,slug:C,fsPath:"",templateId:g,excludeFromSidebar:!0,hasClientRoutes:!0,serverPropsGetterIds:[a],getNavText:()=>Promise.resolve("Catalog"),getStaticData:async()=>({props:{catalogConfig:r}})});const[l]=Object.entries(r.catalogs??{}).find(([T,p])=>!p?.hide)||[];l&&t.addRedirect(C,{type:302,to:`${C}/${l}`},{trackOriginalSource:!1}),o.info("Catalog Entities plugin finished")},async afterRoutesCreated(t,e){await N("build.plugin.catalog_entities",async i=>{const r=await e.getConfig(),o=D(r.entitiesCatalog);if(i?.setAttribute("config",JSON.stringify(o)),!o.show)return;const{logger:a}=e;m.resetForRun();const g=S&&H.isDevelopMode,l=await G.getInstance({baseDbDir:t.serverOutDir,databaseType:"local"}),T=new W(l),{rbacConfigChanged:p}=await T.syncAndDetectChange(r.access?.rbac??null),n=g||p,s=await z.getInstance({baseDbDir:t.serverOutDir,removeExisting:g,databaseType:"local",runWithPragmaWalWriteOptimization:!0}),h=await k.getInstance({baseDbDir:t.serverOutDir,databaseType:"local"}),c=new U(h),P=[new q({fileHashManager:c,context:e,catalogEntitiesService:s,catalogConfig:o,shouldCalculateEntities:n}),new J({actions:t,context:e,catalogEntitiesService:s,fileHashManager:c,fileType:f.OPENAPI_DESCRIPTION,shouldCalculateEntities:n}),new B({actions:t,context:e,catalogEntitiesService:s,fileHashManager:c,fileType:f.ASYNCAPI_DESCRIPTION,shouldCalculateEntities:n}),new M({actions:t,context:e,catalogEntitiesService:s,fileHashManager:c,fileType:f.GRAPHQL_DESCRIPTION,shouldCalculateEntities:n}),new j({actions:t,context:e,catalogEntitiesService:s,fileHashManager:c,fileType:f.ARAZZO_DESCRIPTION,shouldCalculateEntities:n})];a.info("Starting entities extractors...");const O=a.startTiming();await s.transaction(async()=>{await Promise.all(P.map(async d=>d.extract()))});const w=s.getEntitySources();t.setGlobalData({[x]:w}),await l.deleteByNamespace(L),a.infoTime(O,"Entities extractors finished");const{changedSourceFiles:_,removedSourceFiles:E}=m.getPublishDelta(),v=a.startTiming(),b=await Y.publishFromLocalToRemote(p?{baseDbDir:t.serverOutDir}:{baseDbDir:t.serverOutDir,changedSourceFiles:_,removedSourceFiles:E});if(b.published&&a.infoTime(v,"Entities published to the database"),b.shouldFinalizeFileHashes){E.length&&await h.deleteFileHashes({op:"AND",conditions:[{field:"status",operator:"equal",value:A.OUTDATED},{field:"file_path",operator:"in",value:E}]});const d=m.getFileHashConfirmations();for(const{fileType:I,filePath:F,hash:R}of d)await h.upsertFileHash({fileType:I,filePath:F,hash:R,status:A.UP_TO_DATE})}else a.warn("Skipped file_hashes finalization because remote catalog publish connection is unavailable; next build will retry.");const u=await m.getCatalogEntitiesData(s);i?.setAttribute("totalEntities",u.totalEntitiesCount),i?.setAttribute("entitiesCountByType",JSON.stringify(u.countOfEntitiesByType)),i?.setAttribute("totalFilesSkippedByHash",u.totalFilesSkippedByHash),i?.setAttribute("totalProcessedFiles",u.totalProcessedFiles),i?.setAttribute("extractors",u.extractors),S=!1})}}}var Et=K;export{K as catalogEntitiesPlugin,Et as default};
@@ -1 +1 @@
1
- import*as e from"gray-matter";import{ensureFrontmatterThemeCompatibility as m}from"../ensure-frontmatter-theme-compatibility.js";const s=async(t,r)=>{const a=await r.fs.read(t),{data:o}=e.default(a);return{frontmatter:await m(o,t,r.fs)}};export{s as markdownFrontmatterLoader};
1
+ import*as e from"gray-matter";import{ensureFrontmatterThemeCompatibility as m}from"../ensure-frontmatter-theme-compatibility.js";const s=async(t,r)=>{const a=await r.fs.read(t),{data:o}=e.default(a,{});return{frontmatter:await m(o,t,r.fs)}};export{s as markdownFrontmatterLoader};
@@ -1 +1 @@
1
- import{toFetchResponse as w,toReqRes as y}from"fetch-to-node";import{createDocsMcpServer as C}from"../servers/docs-server.js";import{filterApiDescriptionsByRbac as D}from"../utils.js";import{createMethodNotAllowedError as T,withErrorHandling as v}from"./errors.js";import{McpServerType as A}from"../constants.js";import{constructInvalidTokenResponse as S,constructUnauthorizedResponse as U,handleMcpAuth as b,shouldHandleMcpAuth as k}from"../auth/auth-handlers.js";const L=async(o,e,u)=>{const c=!!e?.config?.access?.requiresLogin,a=e?.config?.access?.rbac||{};let p;if(k(c,a)){const{isAuthenticated:s,isTokenValid:t,currentUser:n,accessToken:i}=await b(o,e);if(!s)return U(new URL(o.url).origin);if(!t)return S();n&&(e.user=n),p=i}let r;const l=async()=>{r&&(await r.cleanup(),r=void 0)};return await v(async()=>{if(o.method==="GET")return new Response(JSON.stringify({error:"Method Not Allowed",message:`In order to use this MCP server, you need register it in your MCP Client (VS Code, Cursor, Claude Code, etc.) using that URL: ${o.url}`}),{status:405,headers:{"Content-Type":"application/json"}});if(o.method!=="POST")return T();const s=u,t=s?.props?.config?.apiDescriptionsMap||{},n=s?.props?.config?.mcpDocsServerName||"Docs MCP server",{config:{mcp:i={}}}=e,f=D(t,e.user,a,c),m=e.config.products?Object.values(e.config.products).map(R=>R?.name):[],g=i.docs?.name||n;r=await C({name:g,tools:s?.props?.tools||[],context:{...e,accessToken:p,outdir:e.outdir||"",baseUrl:e.baseUrl||new URL(o.url).origin,apiDescriptionsMap:f,products:m}});const h=await o.json(),{req:M,res:d}=y(o);return await r.transport.handleRequest(M,d,h),w(d)},A.Docs,l)};var O=L;export{O as default};
1
+ import{toFetchResponse as D,toReqRes as T}from"fetch-to-node";import{logger as l}from"../../../tools/notifiers/logger.js";import{isObject as C}from"../../../../utils/guards/is-object.js";import{createDocsMcpServer as v}from"../servers/docs-server.js";import{filterApiDescriptionsByRbac as S}from"../utils.js";import{createMethodNotAllowedError as b,withErrorHandling as N}from"./errors.js";import{McpServerType as O}from"../constants.js";import{constructInvalidTokenResponse as U,constructUnauthorizedResponse as E,handleMcpAuth as I,shouldHandleMcpAuth as j}from"../auth/auth-handlers.js";const i="X-Redocly-AI-Metadata";function k(r){if(r)try{const e=JSON.parse(r);if(C(e))return e;l.warn(`Ignoring ${i} header: not a JSON object.`)}catch{l.warn(`Ignoring ${i} header: invalid JSON.`)}}const L=async(r,e,f)=>{const c=!!e?.config?.access?.requiresLogin,p=e?.config?.access?.rbac||{};let d;if(j(c,p)){const{isAuthenticated:n,isTokenValid:t,currentUser:s,accessToken:a}=await I(r,e);if(!n)return E(new URL(r.url).origin);if(!t)return U();s&&(e.user=s),d=a}let o;const m=async()=>{o&&(await o.cleanup(),o=void 0)};return await N(async()=>{if(r.method==="GET")return new Response(JSON.stringify({error:"Method Not Allowed",message:`In order to use this MCP server, you need register it in your MCP Client (VS Code, Cursor, Claude Code, etc.) using that URL: ${r.url}`}),{status:405,headers:{"Content-Type":"application/json"}});if(r.method!=="POST")return b();const n=f,t=n?.props?.config?.apiDescriptionsMap||{},s=n?.props?.config?.mcpDocsServerName||"Docs MCP server",{config:{mcp:a={}}}=e,g=S(t,e.user,p,c),h=e.config.products?Object.values(e.config.products).map(A=>A?.name):[],M=a.docs?.name||s,R=k(r.headers.get(i));o=await v({name:M,tools:n?.props?.tools||[],context:{...e,accessToken:d,outdir:e.outdir||"",baseUrl:e.baseUrl||new URL(r.url).origin,apiDescriptionsMap:g,products:h,metadata:R}});const w=await r.json(),{req:y,res:u}=T(r);return await o.transport.handleRequest(y,u,w),D(u)},O.Docs,m)};var G=L;export{G as default};
@@ -1 +1 @@
1
- import{McpServer as b}from"@redocly/mcp-typescript-sdk/server/mcp.js";import{StreamableHTTPServerTransport as g}from"@redocly/mcp-typescript-sdk/server/streamableHttp.js";import{logger as n}from"../../../tools/notifiers/logger.js";import{mcpToolWorkers as c,MCP_TOOL_WORKER_KEY as S,MCP_TOOL_IS_AVAILABLE_KEY as _}from"../../../workers/mcp-tool-worker-pool.js";async function w({name:e,tools:l,context:u}){const a=new b({name:e,version:new Date().toISOString().slice(0,10)},{capabilities:{logging:{}}}),s=new g({sessionIdGenerator:void 0}),i=M(u);for(const o of l){const m=async(r,d)=>{n.info(`MCP tool called: ${o.name}`);const I={toolName:o.name,args:r,context:i,extra:q(d)};return await c.exec(S,[I],{timeout:6e4})},f=a.tool(o.name,o.description,o.schema,m),p={toolName:o.name,context:i};let t=!1;try{t=await c.exec(_,[p],{timeout:1e4})}catch(r){n.error(`Failed to check MCP tool availability for "${o.name}": ${r instanceof Error?r.message:String(r)}`),t=!1}t||f.disable()}return await a.connect(s),{server:a,transport:s,cleanup:async()=>{s.close()}}}function q(e){return{sessionId:e.sessionId,authInfo:e.authInfo,requestId:e.requestId,requestInfo:e.requestInfo,_meta:e._meta}}function M(e){return{user:e.user,config:e.config,outdir:e.outdir,baseUrl:e.baseUrl,params:e.params,query:e.query,cookies:e.cookies,apiDescriptionsMap:e.apiDescriptionsMap,products:e.products,accessToken:e.accessToken}}export{w as createDocsMcpServer};
1
+ import{McpServer as b}from"@redocly/mcp-typescript-sdk/server/mcp.js";import{StreamableHTTPServerTransport as g}from"@redocly/mcp-typescript-sdk/server/streamableHttp.js";import{logger as n}from"../../../tools/notifiers/logger.js";import{mcpToolWorkers as c,MCP_TOOL_WORKER_KEY as S,MCP_TOOL_IS_AVAILABLE_KEY as _}from"../../../workers/mcp-tool-worker-pool.js";async function w({name:e,tools:l,context:m}){const a=new b({name:e,version:new Date().toISOString().slice(0,10)},{capabilities:{logging:{}}}),t=new g({sessionIdGenerator:void 0}),i=M(m);for(const o of l){const u=async(r,d)=>{n.info(`MCP tool called: ${o.name}`);const I={toolName:o.name,args:r,context:i,extra:q(d)};return await c.exec(S,[I],{timeout:6e4})},f=a.tool(o.name,o.description,o.schema,u),p={toolName:o.name,context:i};let s=!1;try{s=await c.exec(_,[p],{timeout:1e4})}catch(r){n.error(`Failed to check MCP tool availability for "${o.name}": ${r instanceof Error?r.message:String(r)}`),s=!1}s||f.disable()}return await a.connect(t),{server:a,transport:t,cleanup:async()=>{t.close()}}}function q(e){return{sessionId:e.sessionId,authInfo:e.authInfo,requestId:e.requestId,requestInfo:e.requestInfo,_meta:e._meta}}function M(e){return{user:e.user,config:e.config,outdir:e.outdir,baseUrl:e.baseUrl,params:e.params,query:e.query,cookies:e.cookies,apiDescriptionsMap:e.apiDescriptionsMap,products:e.products,accessToken:e.accessToken,metadata:e.metadata}}export{w as createDocsMcpServer};
@@ -78,6 +78,7 @@ export type McpToolContext = Omit<ApiFunctionsContext, 'telemetry' | 'getKv' | k
78
78
  apiDescriptionsMap: Record<string, ApiDescriptionInfo>;
79
79
  products?: string[];
80
80
  accessToken?: string;
81
+ metadata?: Record<string, unknown>;
81
82
  };
82
83
  export type McpToolHandler<TArgs extends Record<string, unknown> = Record<string, unknown>> = (args: TArgs, context: McpToolContext, extra: McpToolExtra) => Promise<McpToolWorkerResponse>;
83
84
  export type McpToolIsAvailable = (context: McpToolContext) => boolean | Promise<boolean>;
@@ -1 +1 @@
1
- import{getPublicEnvVariables as n}from"../../utils/envs/get-public-env-variables.js";const l=async({fsPath:r,slug:t},a,{variables:i,partials:o},s)=>{const e=s.getPartialsForRoute?.(t);return{definitionId:r,...a.props,markdown:{partials:e&&Object.keys(e).length>0?e:o,variables:{...i,env:n()}}}};var c=l;export{c as default};
1
+ import{getPublicEnvVariables as n}from"../../utils/envs/get-public-env-variables.js";const l=async({fsPath:r,slug:e},t,{variables:a,partials:i},o)=>{const s=o.getPartialsForRoute?.(e)||i;return{definitionId:r,...t.props,markdown:{partials:s,variables:{...a,env:n()}}}};var d=l;export{d as default};
@@ -1 +1 @@
1
- import y from"path";import T from"picomatch";import"../node-crypto-polyfill.js";import{REDOCLY_TEAMS_RBAC as _,REDOCLY_ROUTE_RBAC as R}from"@redocly/config";import{DEFAULT_ANONYMOUS_VISITOR_TEAM as x,ServerRoutes as w,PUBLIC_RBAC_SCOPE_ITEM as A,RBAC_ALL_OTHER_TEAMS as u,DEFAULT_RBAC_SCOPE as S}from"../../constants/common.js";import{DEPRECATED_PUBLIC_API_DEFINITIONS_FOLDER as j,PUBLIC_API_DEFINITIONS_FOLDER as I,PUBLIC_ASSETS_FOLDER as N}from"../constants/common.js";import{removeTrailingSlash as k}from"../../utils/url/remove-trailing-slash.js";import{removeLeadingSlash as B}from"../../utils/url/remove-leading-slash.js";import{parsePathVersions as b}from"../../utils/path/parse-path-versions.js";import{reporter as M}from"../tools/notifiers/reporter.js";import{bold as W}from"../tools/notifiers/helpers/colors.js";import{shaDirPathShort as U}from"../utils/crypto/sha-dir-path-short.js";import{isTruthy as $}from"../../utils/guards/is-truthy.js";import{canExpandConfig as v,expandRbacConfig as Y,getTeamFolderDefaults as z,parseTeamFoldersTemplate as K,parseTeamNameTemplate as H}from"./rbac-expand.js";import{getUserParamsFromCookies as G}from"../web-server/auth.js";import{getDeeperGlobPattern as V}from"./globs.js";import{EntitlementsProvider as J}from"../entitlements/entitlements-provider.js";const C=["NONE","READ","TRIAGE","WRITE","MAINTAIN","ADMIN"],Q=new Set(["x-parsed-md-description","x-parsed-md-summary"]);function Ot(t,e){const r=C.indexOf(t.toUpperCase()),n=C.indexOf(e.toUpperCase());return r>n?t:e}const E={};function O(t,e){if(!t?.content)return A;const r=t.content,{slug:n,fsPath:s}=e;if(!n&&!s)return A;const o=f=>{const d=`slug:${f}`,p=E[d]??T(f);E[d]=p;const D=`fsPath:${f}`,L=E[D]??T(B(f));return E[D]=L,!!(n&&p(n))||!!(s&&L(s))};if(q(n||s||"")&&Object.keys(r).filter(p=>o(p)).length===0)return r[S]||A;const i=Object.keys(r).filter(f=>o(f));if(i.length==0)return A;const l=i.map(f=>T.scan(f,{tokens:!0,parts:!0}));let h=l[0];for(let f=1;f<l.length;f++)h=V(h,l[f]);return r[h.input]}function Pt(t,e,r={},n=!1){if(n&&Object.keys(r).length===0)return e.isAuthenticated;const s=r.features?.[t];return s?e.teams.some(o=>s[o]&&s[o].toLowerCase()!=="none"):!0}function Tt(t,e){return P(t,{isAuthenticated:!1,teams:[x]},e.access?.rbac||{},e.access?.requiresLogin||!1)}function P(t,e={},r={},n=!1){if(t.slug&&typeof t.slug=="string"&&Object.values(w).some(i=>{const l=i.split(":")[0].replace(/\/$/,"");return t.slug===l||t.slug?.startsWith(i)})||typeof t.slug=="string"&&t.slug?.endsWith("/mcp")&&J.instance().canAccessFeature("mcp"))return!0;if(n&&Object.keys(r).length===0)return!!e.isAuthenticated;const s=Y(r,e.teams||[]),o=t[_]||O(s,t[R]||{});if(Object.keys(o||{}).length===0)return!1;if(Object.keys(o).length===1&&o[u]&&o[u].toLowerCase()!=="none")return!0;const c=(e?.email?[...e?.teams||[],e?.email]:e?.teams)||[],a=[];for(const i of c??[])o[i]?a.push(o[i]):o[u]&&i!==e?.email&&a.push(o[u]);return a.length?a.some(i=>i.toLowerCase()!=="none"):!1}function xt(t,e,r,n){if(!t.startsWith(I)&&!t.startsWith(j))return!0;const s=t.replace(new RegExp(`^${I}/`),"").replace(new RegExp(`^${j}/`),""),c=s==="."?"":s,a={[R]:{slug:t,fsPath:c},slug:t};return P(a,n,e,r)}function gt(t,e,r,n,s){if(!t.startsWith(N))return!0;const o=t.match(/.*\..{64}\.([A-Fa-f0-9]{8})\.[^\.]+$/)?.[1];if(!o)return!0;const c=n[o];if(!c)return!0;const{base:a,ext:i}=y.parse(t),l=a.split(".")[0],h=i.split(".").join(""),d=c==="."?"":c,p={[R]:{slug:t,fsPath:y.posix.join(d,`${l}.${h}`)},slug:t};return P(p,s,e,r)}async function Dt(t,e){const{isAuthenticated:r=!1,idpAccessToken:n,federatedAccessToken:s,federatedIdToken:o,...c}=await G(t,e),{teams:a=[]}=c;let i;return r?i=a.filter(l=>l!==x):i=[x],{isAuthenticated:r,idpAccessToken:n,teams:i,claims:c}}function F(t,e,r={},n=!1){if(!t)return t;if(Array.isArray(t)){const s=[];for(const o of t){const c=F(o,e,r,n);c!==void 0&&s.push(c)}return s}if(typeof t=="object"){if(!P(t,e,r,n))return;let s=!1;const o={};for(const c in t){if(c===_||c===R)continue;if(Q.has(c)){o[c]=t[c];continue}const a=F(t[c],e,r,n);if(c==="items"&&Array.isArray(a)&&a.length===0&&t[c].length!==0){s=!0;continue}a!==void 0&&(o[c]=a),c==="paths"&&X(a)&&Z(a)}return s?void 0:o}return t}function Lt(t){return typeof t=="string"?t.split(" ").filter(Boolean):Array.isArray(t)?t.map(e=>e.toString()):[]}function _t(t,e){if(!e)return;const r=e.content;if(!r)return e;const n=Object.entries(r).flatMap(([o,c])=>o===S?[[o,c]]:[[o,c],...t.localeFolders.map(a=>[o.startsWith("/")?`/${a.toLocaleLowerCase()}${o}`:y.posix.join(t.localizationFolder,a,o),c])]),s=Object.fromEntries(n);return{...e,content:s}}async function St(t,e){if(!e)return{};const r={},n=new Set((await t.scan()).flatMap(({relativePath:s})=>{const{versionFolderPath:o}=b(s)||{},c=y.dirname(s);return o?[o,c]:c}));for(const s of n)r[U(s)]=s;return r}const m=t=>typeof t=="object"&&t!==null&&!Array.isArray(t);function X(t){return m(t)&&Object.keys(t).length>0}function Z(t){for(const e of Object.keys(t)){const r=t[e];m(r)&&Object.keys(r).length===0&&delete t[e]}}function q(t){return t?t.split("/").filter(Boolean).some(r=>r.startsWith(".")):!1}const tt=t=>{if(t&&m(t)&&("content"in t&&m(t.content)||"reunite"in t&&m(t.reunite)||"features"in t&&m(t.features)||t.teamFolders&&t.teamNamePatterns)){const e=Object.values(t.content||{});if(e.length===0)return!0;if(e.every(m))return e.every(r=>Object.values(r).every(n=>typeof n=="string"))}return!1},jt=async t=>{if(t){if(Object.keys(t).length===0)return{};if(tt(t))return et(t);await M.panicOnContentError(`You are using an incorrect format of ${W("rbac:")} configuration. See: https://redocly.com/docs/realm/access`)}},et=t=>{const e={...t};if(e.content){const r={};for(const n in e.content)if(e.content[n]!==void 0){const s=k(n);r[s]=e.content[n]}e.content=r}return e};function It(t,e){const r=t.fsPath,n=t.slug,s=[];if(v(e)&&(r||n)){const o=[r,n].filter($),c=K(e,o);if(c){const a=e?.teamNamePatterns?.map(l=>l.replace("{teamPathSegment}",c.teamPathSegment).replace("{projectRole}","read"))??[];s.push(...a);const i=O({content:{...z(e),...e.content}},t);s.push(...g(i))}else{const a=O(e,t);s.push(...g(a))}}else{const o=O(e,t);s.push(...g(o))}return rt(e,s)}function g(t){if(!t)return[];const e=[],r=u in t?{authenticated:t[u],anonymous:t[u]}:{};for(const[n,s]of Object.entries({...r,...t}))s.toLowerCase()!=="none"&&n!==u&&e.push(n);return e}function rt(t,e){return e.map(n=>H(t,n)??{teamName:n}).map(n=>n.projectRole&&n.projectRole!=="READ"?n.teamName?.toLowerCase().replace(n.projectRole?.toLowerCase?.()??"","read")??"":n.teamName?.toLowerCase()??"")}export{C as PROJECT_ROLES_ORDERED_BY_ACCESS_LEVEL,_t as applyL10nToRbacConfig,gt as canAccessAsset,Pt as canAccessFeature,P as canAccessResource,xt as canDownloadApiDefinition,rt as expandTeamsForRead,g as extractTeamsFromScopeItems,F as filterDataByAccessDeep,Dt as getAuthDetailsFromCookies,Ot as getHigherRole,It as getRbacTeamsListForResource,O as getScopeItemsForResource,tt as isRbacConfigValid,Tt as isResourcePubliclyAccessible,et as normalizeRbacConfig,jt as parseRbacConfig,Lt as parseTeamClaimToArray,St as resolveDirectoryHashes};
1
+ import y from"path";import T from"picomatch";import"../node-crypto-polyfill.js";import{REDOCLY_TEAMS_RBAC as L,REDOCLY_ROUTE_RBAC as R}from"@redocly/config";import{DEFAULT_ANONYMOUS_VISITOR_TEAM as x,ServerRoutes as w,PUBLIC_RBAC_SCOPE_ITEM as A,RBAC_ALL_OTHER_TEAMS as u,DEFAULT_RBAC_SCOPE as _}from"../../constants/common.js";import{DEPRECATED_PUBLIC_API_DEFINITIONS_FOLDER as I,PUBLIC_API_DEFINITIONS_FOLDER as j,PUBLIC_ASSETS_FOLDER as N}from"../constants/common.js";import{removeTrailingSlash as k}from"../../utils/url/remove-trailing-slash.js";import{removeLeadingSlash as B}from"../../utils/url/remove-leading-slash.js";import{parsePathVersions as b}from"../../utils/path/parse-path-versions.js";import{reporter as M}from"../tools/notifiers/reporter.js";import{bold as W}from"../tools/notifiers/helpers/colors.js";import{shaDirPathShort as U}from"../utils/crypto/sha-dir-path-short.js";import{isTruthy as $}from"../../utils/guards/is-truthy.js";import{canExpandConfig as v,expandRbacConfig as Y,getTeamFolderDefaults as z,parseTeamFoldersTemplate as K,parseTeamNameTemplate as H}from"./rbac-expand.js";import{getUserParamsFromCookies as G}from"../web-server/auth.js";import{getDeeperGlobPattern as V}from"./globs.js";import{EntitlementsProvider as J}from"../entitlements/entitlements-provider.js";const C=["NONE","READ","TRIAGE","WRITE","MAINTAIN","ADMIN"],Q=new Set(["x-parsed-md-description","x-parsed-md-summary"]);function Tt(t,e){const r=C.indexOf(t.toUpperCase()),n=C.indexOf(e.toUpperCase());return r>n?t:e}const E={};function O(t,e){if(!t?.content)return A;const r=t.content,{slug:n,fsPath:s}=e;if(!n&&!s)return A;const o=f=>{const d=`slug:${f}`,p=E[d]??T(f);E[d]=p;const D=`fsPath:${f}`,S=E[D]??T(B(f));return E[D]=S,!!(n&&p(n))||!!(s&&S(s))};if(et(n||s||"")&&Object.keys(r).filter(p=>o(p)).length===0)return r[_]||A;const a=Object.keys(r).filter(f=>o(f));if(a.length==0)return A;const l=a.map(f=>T.scan(f,{tokens:!0,parts:!0}));let h=l[0];for(let f=1;f<l.length;f++)h=V(h,l[f]);return r[h.input]}function xt(t,e,r={},n=!1){if(n&&Object.keys(r).length===0)return e.isAuthenticated;const s=r.features?.[t];return s?e.teams.some(o=>s[o]&&s[o].toLowerCase()!=="none"):!0}function gt(t,e){return P(t,{isAuthenticated:!1,teams:[x]},e.access?.rbac||{},e.access?.requiresLogin||!1)}function P(t,e={},r={},n=!1){if(t.slug&&typeof t.slug=="string"&&Object.values(w).some(a=>{const l=a.split(":")[0].replace(/\/$/,"");return t.slug===l||t.slug?.startsWith(a)})||typeof t.slug=="string"&&t.slug?.endsWith("/mcp")&&J.instance().canAccessFeature("mcp"))return!0;if(n&&Object.keys(r).length===0)return!!e.isAuthenticated;const s=Y(r,e.teams||[]),o=t[L]||O(s,t[R]||{});if(Object.keys(o||{}).length===0)return!1;if(Object.keys(o).length===1&&o[u]&&o[u].toLowerCase()!=="none")return!0;const c=(e?.email?[...e?.teams||[],e?.email]:e?.teams)||[],i=[];for(const a of c??[])o[a]?i.push(o[a]):o[u]&&a!==e?.email&&i.push(o[u]);return i.length?i.some(a=>a.toLowerCase()!=="none"):!1}function Dt(t,e,r,n){if(!t.startsWith(j)&&!t.startsWith(I))return!0;const s=t.replace(new RegExp(`^${j}/`),"").replace(new RegExp(`^${I}/`),""),c=s==="."?"":s,i={[R]:{slug:t,fsPath:c},slug:t};return P(i,n,e,r)}function St(t,e,r,n,s){if(!t.startsWith(N))return!0;const o=t.match(/.*\..{64}\.([A-Fa-f0-9]{8})\.[^\.]+$/)?.[1];if(!o)return!0;const c=n[o];if(!c)return!0;const{base:i,ext:a}=y.parse(t),l=i.split(".")[0],h=a.split(".").join(""),d=c==="."?"":c,p={[R]:{slug:t,fsPath:y.posix.join(d,`${l}.${h}`)},slug:t};return P(p,s,e,r)}async function Lt(t,e){const{isAuthenticated:r=!1,idpAccessToken:n,federatedAccessToken:s,federatedIdToken:o,...c}=await G(t,e),{teams:i=[]}=c;let a;return r?a=i.filter(l=>l!==x):a=[x],{isAuthenticated:r,idpAccessToken:n,teams:a,claims:c}}function F(t,e,r={},n=!1){if(!t)return t;if(Array.isArray(t)){const s=[];for(const o of t){const c=F(o,e,r,n);c!==void 0&&s.push(c)}return tt(s)}if(typeof t=="object"){if(!P(t,e,r,n))return;let s=!1;const o={};for(const c in t){if(c===L||c===R)continue;if(Q.has(c)){o[c]=t[c];continue}const i=F(t[c],e,r,n);if(c==="items"&&Array.isArray(i)&&i.length===0&&t[c].length!==0){s=!0;continue}i!==void 0&&(o[c]=i),c==="paths"&&X(i)&&Z(i)}return s?void 0:o}return t}function _t(t){return typeof t=="string"?t.split(" ").filter(Boolean):Array.isArray(t)?t.map(e=>e.toString()):[]}function It(t,e){if(!e)return;const r=e.content;if(!r)return e;const n=Object.entries(r).flatMap(([o,c])=>o===_?[[o,c]]:[[o,c],...t.localeFolders.map(i=>[o.startsWith("/")?`/${i.toLocaleLowerCase()}${o}`:y.posix.join(t.localizationFolder,i,o),c])]),s=Object.fromEntries(n);return{...e,content:s}}async function jt(t,e){if(!e)return{};const r={},n=new Set((await t.scan()).flatMap(({relativePath:s})=>{const{versionFolderPath:o}=b(s)||{},c=y.dirname(s);return o?[o,c]:c}));for(const s of n)r[U(s)]=s;return r}const m=t=>typeof t=="object"&&t!==null&&!Array.isArray(t);function X(t){return m(t)&&Object.keys(t).length>0}function Z(t){for(const e of Object.keys(t)){const r=t[e];m(r)&&Object.keys(r).length===0&&delete t[e]}}function q(t){return m(t)&&t.type==="separator"}function tt(t){const e=[];let r;for(const n of t){if(q(n)){r=n;continue}r&&(e.push(r),r=void 0),e.push(n)}return e}function et(t){return t?t.split("/").filter(Boolean).some(r=>r.startsWith(".")):!1}const rt=t=>{if(t&&m(t)&&("content"in t&&m(t.content)||"reunite"in t&&m(t.reunite)||"features"in t&&m(t.features)||t.teamFolders&&t.teamNamePatterns)){const e=Object.values(t.content||{});if(e.length===0)return!0;if(e.every(m))return e.every(r=>Object.values(r).every(n=>typeof n=="string"))}return!1},Ct=async t=>{if(t){if(Object.keys(t).length===0)return{};if(rt(t))return nt(t);await M.panicOnContentError(`You are using an incorrect format of ${W("rbac:")} configuration. See: https://redocly.com/docs/realm/access`)}},nt=t=>{const e={...t};if(e.content){const r={};for(const n in e.content)if(e.content[n]!==void 0){const s=k(n);r[s]=e.content[n]}e.content=r}return e};function Ft(t,e){const r=t.fsPath,n=t.slug,s=[];if(v(e)&&(r||n)){const o=[r,n].filter($),c=K(e,o);if(c){const i=e?.teamNamePatterns?.map(l=>l.replace("{teamPathSegment}",c.teamPathSegment).replace("{projectRole}","read"))??[];s.push(...i);const a=O({content:{...z(e),...e.content}},t);s.push(...g(a))}else{const i=O(e,t);s.push(...g(i))}}else{const o=O(e,t);s.push(...g(o))}return st(e,s)}function g(t){if(!t)return[];const e=[],r=u in t?{authenticated:t[u],anonymous:t[u]}:{};for(const[n,s]of Object.entries({...r,...t}))s.toLowerCase()!=="none"&&n!==u&&e.push(n);return e}function st(t,e){return e.map(n=>H(t,n)??{teamName:n}).map(n=>n.projectRole&&n.projectRole!=="READ"?n.teamName?.toLowerCase().replace(n.projectRole?.toLowerCase?.()??"","read")??"":n.teamName?.toLowerCase()??"")}export{C as PROJECT_ROLES_ORDERED_BY_ACCESS_LEVEL,It as applyL10nToRbacConfig,St as canAccessAsset,xt as canAccessFeature,P as canAccessResource,Dt as canDownloadApiDefinition,st as expandTeamsForRead,g as extractTeamsFromScopeItems,F as filterDataByAccessDeep,Lt as getAuthDetailsFromCookies,Tt as getHigherRole,Ft as getRbacTeamsListForResource,O as getScopeItemsForResource,rt as isRbacConfigValid,gt as isResourcePubliclyAccessible,nt as normalizeRbacConfig,Ct as parseRbacConfig,_t as parseTeamClaimToArray,jt as resolveDirectoryHashes};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@redocly/reef",
3
- "version": "0.133.0-next.6",
3
+ "version": "0.134.0-next.0",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "bin": {
@@ -90,14 +90,14 @@
90
90
  "xpath": "0.0.34",
91
91
  "yaml-ast-parser": "0.0.43",
92
92
  "zod": "^3.25.76",
93
- "@redocly/asyncapi-docs": "1.10.0-next.6",
94
- "@redocly/config": "0.48.1",
95
- "@redocly/graphql-docs": "1.10.0-next.6",
96
- "@redocly/openapi-docs": "3.21.0-next.6",
97
- "@redocly/portal-legacy-ui": "0.16.0-next.0",
98
- "@redocly/portal-plugin-mock-server": "0.18.0-next.6",
99
- "@redocly/realm-asyncapi-sdk": "0.11.0-next.4",
100
- "@redocly/theme": "0.65.0-next.5"
93
+ "@redocly/asyncapi-docs": "1.11.0-next.0",
94
+ "@redocly/config": "0.48.2",
95
+ "@redocly/graphql-docs": "1.11.0-next.0",
96
+ "@redocly/openapi-docs": "3.22.0-next.0",
97
+ "@redocly/portal-legacy-ui": "0.17.0-next.0",
98
+ "@redocly/portal-plugin-mock-server": "0.19.0-next.0",
99
+ "@redocly/realm-asyncapi-sdk": "0.12.0-next.0",
100
+ "@redocly/theme": "0.66.0-next.0"
101
101
  },
102
102
  "peerDependencies": {
103
103
  "react": "^19.2.4",