@redocly/revel 0.138.1 → 0.139.0-next.10
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 +148 -0
- package/dist/cli/eject/resolveEjectParams.js +1 -1
- package/dist/client/app/Sidebar/RequestAccessButton.js +2 -2
- package/dist/client/app/hooks/useL10nConfig.d.ts +1 -0
- package/dist/client/app/markdoc/custom-components/openapi/openapi-example.js +1 -1
- package/dist/client/app/markdoc/custom-components/openapi/replay-openapi.js +1 -1
- package/dist/client/app/search/useSearch.js +1 -1
- package/dist/client/app/utils/programmatic-scroll.js +1 -1
- package/dist/client/app/webmcp/tools/api-tools.js +1 -1
- package/dist/client/app/webmcp/tools/site-tools.js +2 -2
- package/dist/client/app/webmcp/useWebMcpTools.js +1 -1
- package/dist/client/templates/api-docs/template.js +10 -8
- package/dist/constants/common.d.ts +1 -0
- package/dist/constants/common.js +1 -1
- package/dist/constants/l10n/langs/ar.js +1 -1
- package/dist/constants/l10n/langs/de.js +1 -1
- package/dist/constants/l10n/langs/en.js +1 -1
- package/dist/constants/l10n/langs/es.js +1 -1
- package/dist/constants/l10n/langs/fr.js +1 -1
- package/dist/constants/l10n/langs/hi.js +1 -1
- package/dist/constants/l10n/langs/it.js +1 -1
- package/dist/constants/l10n/langs/ja.js +1 -1
- package/dist/constants/l10n/langs/ko.js +1 -1
- package/dist/constants/l10n/langs/pl.js +1 -1
- package/dist/constants/l10n/langs/pt-BR.js +1 -1
- package/dist/constants/l10n/langs/pt.js +1 -1
- package/dist/constants/l10n/langs/ru.js +1 -1
- package/dist/constants/l10n/langs/uk.js +1 -1
- package/dist/constants/l10n/langs/zh.js +1 -1
- package/dist/markdoc/helpers/get-inner-text.d.ts +2 -0
- package/dist/markdoc/helpers/get-inner-text.js +2 -2
- package/dist/markdoc/helpers/remove-markdoc-tags.js +1 -1
- package/dist/server/config/env-schemas/feature-flags.d.ts +1 -1
- package/dist/server/constants/entitlements.d.ts +2 -2
- package/dist/server/constants/entitlements.js +1 -1
- package/dist/server/entitlements/entitlements-provider.d.ts +2 -2
- package/dist/server/entitlements/is-valid-plan.d.ts +2 -2
- package/dist/server/entitlements/is-valid-plan.js +1 -1
- package/dist/server/fs/content-fs.js +1 -1
- package/dist/server/fs/utils/external-ref-resolver.js +2 -2
- package/dist/server/fs/utils/is-translation-fallback.d.ts +9 -0
- package/dist/server/fs/utils/is-translation-fallback.js +1 -0
- package/dist/server/node-bundle-entry.js +1 -1
- package/dist/server/plugins/api-docs/get-server-props.js +1 -1
- package/dist/server/plugins/api-docs/index.js +1 -1
- package/dist/server/plugins/api-docs/search/create-indexer.d.ts +9 -2
- package/dist/server/plugins/api-docs/search/create-indexer.js +1 -1
- package/dist/server/plugins/api-docs/search/get-ai-search-documents.js +72 -72
- package/dist/server/plugins/api-docs/search/search-resolver.js +1 -1
- package/dist/server/plugins/arazzo-docs/arazzo-doc-loader.js +2 -2
- package/dist/server/plugins/arazzo-docs/index.js +1 -1
- package/dist/server/plugins/catalog-entities/extensions/extractors/api-description/openapi-entities-extractor.js +1 -1
- package/dist/server/plugins/catalog-entities/template/index.js +1 -1
- package/dist/server/plugins/config-parser/loaders/utils/read-and-validate-config.js +1 -1
- package/dist/server/plugins/config-parser/loaders/versions-config-loader.js +1 -1
- package/dist/server/plugins/default-theme/resolve-logo.js +1 -1
- package/dist/server/plugins/dev-onboarding/api/routes/index.js +1 -1
- package/dist/server/plugins/dev-onboarding/api/routes/products.js +1 -1
- package/dist/server/plugins/dev-onboarding/template/App.js +4 -4
- package/dist/server/plugins/dev-onboarding/template/AppsList.js +7 -7
- package/dist/server/plugins/dev-onboarding/template/CreateAppDialog.js +3 -3
- package/dist/server/plugins/dev-onboarding/template/components/ApiKeyItem.js +4 -4
- package/dist/server/plugins/dev-onboarding/template/components/ApiLogDetails.js +7 -7
- package/dist/server/plugins/dev-onboarding/template/components/ApiLogs.js +5 -5
- package/dist/server/plugins/dev-onboarding/template/components/ApiLogsActions.js +6 -6
- package/dist/server/plugins/dev-onboarding/template/components/ApisList.js +1 -1
- package/dist/server/plugins/dev-onboarding/template/components/CreateApiKey.js +1 -1
- package/dist/server/plugins/dev-onboarding/template/components/DeleteAppDialog.js +1 -1
- package/dist/server/plugins/dev-onboarding/template/components/EditApis.js +1 -1
- package/dist/server/plugins/dev-onboarding/template/components/EditAppDescriptionDialog.js +1 -1
- package/dist/server/plugins/dev-onboarding/template/components/EditAppDialog.js +1 -1
- package/dist/server/plugins/dev-onboarding/template/components/EditCallbackUrlDialog.js +1 -1
- package/dist/server/plugins/dev-onboarding/template/components/RevokeAPIKey.js +5 -5
- package/dist/server/plugins/dev-onboarding/template/components/RollAPIKey.js +5 -5
- package/dist/server/plugins/dev-onboarding/template/components/UpdateApiKey.js +1 -1
- package/dist/server/plugins/l10n/index.js +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-json-example-ref.js +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-link.js +1 -1
- package/dist/server/plugins/markdown/get-server-props.js +1 -1
- package/dist/server/plugins/markdown/index.js +1 -1
- package/dist/server/plugins/markdown/markdoc/plugins/utils.js +1 -1
- package/dist/server/plugins/markdown/markdoc/resolve-raw-partials.js +1 -1
- package/dist/server/plugins/markdown/markdown-static-data-loader.js +1 -1
- package/dist/server/plugins/markdown/read-file-content.js +1 -1
- package/dist/server/plugins/markdown/search/search-resolver.js +1 -1
- package/dist/server/plugins/mcp/codemode/capabilities/utils.js +4 -4
- package/dist/server/plugins/mcp/codemode/constants.js +1 -1
- package/dist/server/plugins/mcp/codemode/prompts.d.ts +2 -2
- package/dist/server/plugins/mcp/codemode/prompts.js +8 -8
- package/dist/server/plugins/mcp/codemode/tools/describe-tools.js +2 -2
- package/dist/server/plugins/mcp/codemode/tools/execute-schema.d.ts +2 -0
- package/dist/server/plugins/mcp/codemode/tools/execute-schema.js +1 -1
- package/dist/server/plugins/mcp/constants.d.ts +2 -2
- package/dist/server/plugins/mcp/constants.js +1 -1
- package/dist/server/plugins/mcp/docs-mcp/tool-schemas.js +1 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/core/create-anonymous-session.js +1 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/core/submit-feedback.js +2 -2
- package/dist/server/plugins/mcp/docs-mcp/tools/openapi/endpoint-suggestions.d.ts +0 -2
- package/dist/server/plugins/mcp/docs-mcp/tools/openapi/endpoint-suggestions.js +1 -1
- package/dist/server/plugins/mcp/gateway-mcp/allowed-http-methods.d.ts +0 -5
- package/dist/server/plugins/mcp/gateway-mcp/allowed-http-methods.js +1 -1
- package/dist/server/plugins/mcp/gateway-mcp/callable-apis.d.ts +3 -2
- package/dist/server/plugins/mcp/gateway-mcp/callable-apis.js +1 -1
- package/dist/server/plugins/mcp/gateway-mcp/caller-api-calls.d.ts +3 -4
- package/dist/server/plugins/mcp/gateway-mcp/caller-api-calls.js +1 -1
- package/dist/server/plugins/mcp/gateway-mcp/eligibility.d.ts +1 -12
- package/dist/server/plugins/mcp/gateway-mcp/eligibility.js +1 -1
- package/dist/server/plugins/mcp/handlers/docs-mcp-handler.js +1 -1
- package/dist/server/plugins/mcp/handlers/errors.d.ts +0 -2
- package/dist/server/plugins/mcp/handlers/errors.js +1 -1
- package/dist/server/plugins/mcp/servers/docs-server.js +1 -1
- package/dist/server/plugins/mcp/utils/docs-site-url.d.ts +6 -0
- package/dist/server/plugins/mcp/utils/docs-site-url.js +1 -0
- package/dist/server/plugins/mcp/utils.d.ts +0 -8
- package/dist/server/plugins/mcp/utils.js +1 -1
- package/dist/server/plugins/nav-utils.js +1 -1
- package/dist/server/plugins/pages/index.js +1 -1
- package/dist/server/plugins/register-page-props.d.ts +1 -1
- package/dist/server/plugins/register-page-props.js +1 -1
- package/dist/server/plugins/sidebars/index.js +1 -1
- package/dist/server/plugins/sidebars/utils.js +1 -1
- package/dist/server/types/plugins/markdown.d.ts +1 -0
- package/dist/server/utils/envs/load-env-variables.js +1 -1
- package/dist/server/utils/rbac-expand.d.ts +4 -0
- package/dist/server/utils/rbac-expand.js +1 -1
- package/dist/server/utils/rbac.js +1 -1
- package/dist/server/utils/resolve-asset-path.js +1 -1
- package/dist/server/web-server/auth.d.ts +2 -0
- package/dist/server/web-server/auth.js +3 -3
- package/dist/server/web-server/jwt/jwt.js +1 -1
- package/dist/server/web-server/middleware/catalogAuthMiddleware.js +1 -1
- package/dist/server/web-server/routes/mcp-routes/mcp-server-card.js +1 -1
- package/dist/types/entitlements.d.ts +2 -1
- package/dist/types/global-data.d.ts +1 -0
- package/dist/utils/url/api-keys-url.d.ts +11 -0
- package/dist/utils/url/api-keys-url.js +1 -0
- package/package.json +7 -7
- package/dist/server/plugins/mcp/docs-mcp/tools/core/utils.d.ts +0 -3
- package/dist/server/plugins/mcp/docs-mcp/tools/core/utils.js +0 -11
|
@@ -1 +1 @@
|
|
|
1
|
-
import{logger as A}from"../../../tools/notifiers/logger.js";import{getFeedbackClientIp as N}from"../../../web-server/utils/feedback-ip.js";import{getForwardedOrigin as M,getInternalOrigin as
|
|
1
|
+
import{logger as A}from"../../../tools/notifiers/logger.js";import{getFeedbackClientIp as N}from"../../../web-server/utils/feedback-ip.js";import{getForwardedOrigin as M,getInternalOrigin as L}from"../../../web-server/utils/get-request-origin.js";import{GATEWAY_FETCH_LIMIT_DEFAULTS as B,DEFAULT_ANONYMOUS_VISITOR_TEAM as H,RbacFeatures as j}from"../../../../constants/common.js";import{isObject as V}from"../../../../utils/guards/is-object.js";import{getAccessibleSkills as $}from"../../../utils/skills/get-accessible-skills.js";import{getSkillUrl as G}from"../../../utils/skills/get-skill-url.js";import{createMcpHandler as J}from"@modelcontextprotocol/server";import{createDocsMcpServer as K}from"../servers/docs-server.js";import{filterApiDescriptionsByRbac as Y,filterGraphqlDescriptionsByRbac as z}from"../utils.js";import{userSubject as W}from"../gateway-mcp/subject.js";import{ipRateLimitKey as X}from"../gateway-mcp/rate-limit/utils/ip-key.js";import{McpClientInputError as Q,createMethodNotAllowedError as Z,withErrorHandling as q}from"./errors.js";import{constructForbiddenResponse as x,constructInvalidTokenResponse as ee,constructUnauthorizedResponse as re,handleMcpAuth as oe}from"../auth/auth-handlers.js";import{isAssistantAnonymousToken as se}from"../auth/assistant-anonymous-token.js";import{shouldHandleMcpAuth as ne}from"../../../utils/rbac/should-handle-mcp-auth.js";import{extractTokenFromAuthHeader as ie}from"../utils/jwt.js";import{resolveMcpClient as te}from"../utils/mcp-client.js";import{randomUUID as ce}from"../../../utils/crypto/random-uuid.js";import{getPublicMcpEndpointStatus as ae}from"../utils/public-endpoint.js";import{narrowMcpConfigForCaller as pe}from"../gateway-mcp/caller-api-calls.js";import{DEFAULT_DOCS_MCP_SERVER_NAME as de,SSE_KEEPALIVE_INTERVAL_MS as me}from"../constants.js";import{withPathPrefix as le}from"@redocly/theme/core/utils";import{PUBLIC_MCP_ROUTE as ue}from"@redocly/theme/core/constants/mcp";import{canAccessFeature as fe}from"../../../utils/rbac.js";import{ANONYMOUS_AUTH_DETAILS as ge}from"../../../constants/rbac.js";const E="X-Redocly-AI-Metadata";function he(r){if(r)try{const e=JSON.parse(r);if(V(e))return e;A.warn(`Ignoring ${E} header: not a JSON object.`)}catch{A.warn(`Ignoring ${E} header: invalid JSON.`)}}function Ae(r,e){return new URL(r).searchParams.get("mode")==="tools"?"tools":e}function I(){return{...ge,email:"",idpAccessToken:void 0,idpId:void 0}}const Me=async(r,e,i)=>{const t=!!e?.config?.access?.requiresLogin,c=e?.config?.access?.rbac||{},y=i?.props?.config?.mcpMode??"tools",p=Ae(r.url,y),C=i?.props?.config?.gatewayFetchBudgetPerExec??B.budgetPerExec,U=i?.props?.config?.searchIgnoredRoutes??[],s=i,R=!!s?.props?.config?.isPublicEndpoint;let f;const T=r.headers.get("Authorization");if(R)e.user=I();else if(ne(t,c)){const{isAuthenticated:n,isTokenValid:d,isFirstPartyAnonymous:g,currentUser:m,accessToken:h}=await oe(r,e);if(g)e.user=I();else if(n)m&&(e.user=m),f=h;else{const a=M(r),l=ae(e.config)==="served"?`${a}${le(ue)}`:void 0;return d===!1?ee(a,l):re(a,l)}}else if(T){const n=ie(T)??void 0;f=(n?await se(n):!1)?void 0:n}const w={isAuthenticated:!!e.user?.isAuthenticated,teams:e.user?.teams||[H],claims:e.user?.claims??{}};return fe(j.MCP,w,c,t)?await q(async()=>{const n=p==="code"&&(i?.props?.config?.elicitationEnabled??!1);if(r.method==="GET")return new Response(JSON.stringify({error:"Method Not Allowed",message:`In order to use this MCP server, you need to register it in your MCP client (VS Code, Cursor, Claude Code, etc.) using this URL: ${r.url}`}),{status:405,headers:{"Content-Type":"application/json"}});if(r.method!=="POST")return Z();const d=s?.props?.config?.apiDescriptionsMap||{},g=s?.props?.config?.graphqlDescriptions||[],m=s?.props?.config?.mcpDocsServerName||de,{config:{mcp:h={}}}=e,a=Y(d,e.user,c,t),l=z(g,e.user,c,t),P=e.config.products?Object.values(e.config.products).map(o=>o?.name):[],D=h.docs?.name||m,u=he(r.headers.get(E)),_=s?.props?.tools||[],O=s?.props?.skillsBaseUrl||M(r),k=$(s?.props?.skills||[],e.user,c,t).map(o=>({slug:o.slug,name:o.name,description:o.description,content:o.content,uri:G(O,o.slug)})),S=await Ee(r),b=s?.props?.fetchCountSecret,v={name:D,tools:_,skills:k,context:{...e,config:{...e.config,mcp:pe(e.config.mcp,u)},accessToken:f,outdir:e.outdir||"",baseUrl:e.baseUrl||M(r),internalBaseUrl:L(r),apiDescriptionsMap:a,graphqlDescriptions:l,products:P,metadata:u,mcpMode:p,elicitationEnabled:n,gatewayFetchBudgetPerExec:C,fetchCountRequest:p==="code"&&b?{caller:{subject:W(e.user),ip:X(r)},secret:b}:void 0,searchIgnoredRoutes:U,clientIp:N(r),...te(r),requestId:ce(),messageId:typeof u?.messageId=="string"?u.messageId:void 0}},F=await K({...v,getKv:e.getKv});return await J(async()=>F,{keepAliveMs:me,onerror:o=>A.warn(`MCP handler: ${o.message}`)}).fetch(r,S!==void 0?{parsedBody:S}:void 0)},p):x()};async function Ee(r){try{return await r.json()}catch(e){throw new Q(e instanceof Error?e.message:String(e),{cause:e})}}var ze=Me;export{ze as default};
|
|
@@ -19,7 +19,5 @@ export declare class McpClientInputError extends Error {
|
|
|
19
19
|
}
|
|
20
20
|
export declare function createMethodNotAllowedError(requestId?: string | number | null): Response;
|
|
21
21
|
export declare function createInternalServerError(error: Error | string, requestId?: string | number | null): Response;
|
|
22
|
-
export declare function createInvalidRequestError(message?: string, requestId?: string | number | null): Response;
|
|
23
|
-
export declare function createInvalidParamsError(message?: string, requestId?: string | number | null): Response;
|
|
24
22
|
export declare function withErrorHandling<T>(operation: () => Promise<T>, mode?: McpMode): Promise<T | Response>;
|
|
25
23
|
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{telemetry as c}from"../../../telemetry/index.js";import{McpErrorCodes as o,McpServerType as i}from"../constants.js";import{serverAttributes as d}from"../utils/telemetry-attributes.js";class
|
|
1
|
+
import{telemetry as c}from"../../../telemetry/index.js";import{McpErrorCodes as o,McpServerType as i}from"../constants.js";import{serverAttributes as d}from"../utils/telemetry-attributes.js";class n extends Error{code;data;requestId;constructor(t,r,s,a){super(r),this.name="McpError",this.code=t,this.data=s,this.requestId=a}createErrorResponse(){const t={jsonrpc:"2.0",error:{code:this.code,message:this.message,...this.data?{data:this.data}:{}},id:this.requestId??null},r=u(this.code);return new Response(JSON.stringify(t),{status:r,headers:{"Content-Type":"application/json"}})}}class p extends Error{constructor(t,r){super(t,r),this.name="McpClientInputError"}}function u(e){switch(e){case o.InvalidRequest:case o.InvalidParams:return 400;case o.MethodNotFound:return 404;case o.ServerError:return 405;case o.InternalError:default:return 500}}function f(e){return new n(o.ServerError,"Method not allowed",void 0,e).createErrorResponse()}function l(e,t){const r=e instanceof Error?e.message:String(e);return new n(o.InternalError,"Internal server error mcp",r,t).createErrorResponse()}async function M(e,t="tools"){try{return await e()}catch(r){return c.sendMcpErrorMessage([{...d(i.Docs),message:r?.message||"",stack:r?.stack||"",error_class:r instanceof p?"client_error":"server_error",mode:t}]),l(r)}}export{p as McpClientInputError,n as McpError,l as createInternalServerError,f as createMethodNotAllowedError,M as withErrorHandling};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{logger as
|
|
1
|
+
import{logger as N}from"../../../tools/notifiers/logger.js";import{mcpToolWorkers as y,MCP_TOOL_IS_AVAILABLE_KEY as U}from"../../../workers/mcp-tool-worker-pool.js";import{CREATE_ANONYMOUS_SESSION_TOOL_NAME as S,MANAGE_API_CREDENTIALS_TOOL_NAME as w,SUBMIT_FEEDBACK_TOOL_NAME as h}from"../constants.js";import{isAnonymousSessionToolAvailable as I}from"../docs-mcp/tools/core/create-anonymous-session.js";import{isManageApiCredentialsToolAvailable as x,manageApiCredentials as H,manageApiCredentialsSchema as B}from"../codemode/tools/manage-credentials.js";import{EXECUTE_TOOL_SCHEMA as M,executeToolTitle as F}from"../codemode/tools/execute-schema.js";import{EXECUTE_TOOL_NAME as P,CODE_MODE_TOOL_NAMES as g,FETCH_TOOL_NAME as R}from"../codemode/constants.js";import{buildCodeModeInstructions as Y,buildExecuteDescription as z}from"../codemode/prompts.js";import{toToolListEntries as K}from"../codemode/build-tool-list.js";import{composeExecuteAnnotations as W,getActiveCapabilities as X}from"../codemode/capabilities/index.js";import{describeToolsSchema as $,describeTools as j}from"../codemode/tools/describe-tools.js";import{availableSandboxTools as G}from"../utils/available-sandbox-tools.js";import{resolveDocsSiteUrl as V}from"../utils/docs-site-url.js";import{isToolDisabledByCaller as b}from"../utils/disabled-tools.js";import{toRegisterToolConfig as L}from"../utils/tool-registration.js";import{createMcpServer as q,createToolDispatch as J,extractSerializableContext as Q}from"./mcp-server.js";const Z=new Set([...g].filter(s=>s!==h));function v(s,a){const o=a.schema;if(s)return o;const{sessionHandle:u,...f}=o.properties;return{...o,properties:f}}function ee(s){return Object.fromEntries(s.map(a=>[a.name,a.schema]))}async function ue({name:s,tools:a,context:o,skills:u=[],getKv:f}){const l=Q(o),r=o.mcpMode==="code",c=r?X(o):[],_=c.some(e=>e.id===R),m=r?await G(a.filter(e=>!g.has(e.name)),l):[],A=K(m,c),T=I(o)&&!b(S,o.metadata),D=r&&x(o)&&!b(w,o.metadata),p=q(s,r?Y(_,A):void 0),O={getClientCapabilities:()=>p.server.getClientCapabilities(),getKv:f},d=J(r?{...l,sandboxToolSchemas:ee(m)}:l,O),C=async e=>{try{return await y.exec(U,[{toolName:e,context:l}],{timeout:1e4})}catch(i){return N.error(`Failed to check MCP tool availability for "${e}": ${i instanceof Error?i.message:String(i)}`),!1}};if(r){const e=W(m,c,o.config?.mcp),i=[{tool:{...M,title:F(e),description:z(_,A,V(o.config?.seo?.siteUrl,o.baseUrl)),schema:v(T,M),annotations:e},callback:d(P)},{tool:$(m,c),callback:j(m,C,c,o)}],n=a.find(t=>t.name===h);n&&!b(n.name,o.metadata)&&i.push({tool:n,callback:d(n.name)});const E=a.find(t=>t.name===S);if(E&&T&&i.push({tool:E,callback:d(E.name)}),D){const t=B(o);i.push({tool:{...t,schema:v(T,t)},callback:H(l,O)})}for(const{tool:t,callback:k}of i)p.registerTool(t.name,L(t),k)}else{const e=a.filter(i=>!Z.has(i.name));await Promise.all(e.map(async i=>{const n=p.registerTool(i.name,L({...i,outputSchema:void 0}),d(i.name));await C(i.name)||n.disable()}))}for(const e of u)p.registerResource(e.slug,e.uri,{title:e.name,description:e.description,mimeType:"text/markdown"},async()=>({contents:[{uri:e.uri,mimeType:"text/markdown",text:e.content}]}));return p}export{ue as createDocsMcpServer};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The first http(s) URL of `seo.siteUrl`, `REDOCLY_PUBLIC_URL`, and the request origin, without a
|
|
3
|
+
* trailing slash. The request origin gives only its origin. Undefined when none of them is valid.
|
|
4
|
+
*/
|
|
5
|
+
export declare function resolveDocsSiteUrl(siteUrl: string | undefined, requestOrigin: string | undefined): string | undefined;
|
|
6
|
+
//# sourceMappingURL=docs-site-url.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{envConfig as e}from"../../../config/env-config.js";import{removeTrailingSlash as i}from"../../../../utils/url/remove-trailing-slash.js";function t(r){if(!r||!URL.canParse(r))return;const n=new URL(r);return n.protocol==="http:"||n.protocol==="https:"?n:void 0}function c(r,n){const o=t(r)??t(e.REDOCLY_PUBLIC_URL);return o?i(`${o.origin}${o.pathname}`):t(n)?.origin}export{c as resolveDocsSiteUrl};
|
|
@@ -83,12 +83,4 @@ export declare function collectIgnoredRoutes(routes: {
|
|
|
83
83
|
export declare function isMcpInRedirects(redirects?: {
|
|
84
84
|
[key: string]: RedirectConfig;
|
|
85
85
|
}): boolean;
|
|
86
|
-
/** Whether an API definition is part of the Docs MCP catalog (not a localized copy, has public paths, not ignored via mcp.docs.ignore). */
|
|
87
|
-
export declare function isApiIncludedInDocsMcp(relativePath: string, definition: {
|
|
88
|
-
paths?: Record<string, unknown>;
|
|
89
|
-
} | undefined, mcpConfig: {
|
|
90
|
-
docs?: {
|
|
91
|
-
ignore?: readonly string[];
|
|
92
|
-
};
|
|
93
|
-
} | undefined): boolean;
|
|
94
86
|
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import
|
|
1
|
+
import c,{join as f}from"node:path";import a from"picomatch";import{PUBLIC_API_DEFINITIONS_FOLDER as u,L10N_DIR_NAME as l,I18N_DIR_NAME as m}from"../../constants/common.js";import{RESERVED_ROUTES as h}from"../../plugins/get-reserved-routes.js";import{removeL10nPrefix as D}from"../../fs/utils/remove-l10n-prefix.js";import{removeTrailingSlash as A}from"../../../utils/url/remove-trailing-slash.js";import{slash as g}from"../../../utils/path/slash.js";import{canDownloadApiDefinition as d}from"../../utils/rbac.js";function v(e){return e.filter(t=>t.type==="openapi").map(t=>({relativePath:t.relativePath,definition:t.document}))}function T(e){return e.filter(t=>t.type==="graphql").map(t=>({relativePath:t.relativePath,definition:t.document,options:t.options}))}function p(e){if(typeof e!="object"||e===null)return e;if(Array.isArray(e))return e.map(p);const t={};for(const i in e)if(Object.hasOwn(e,i)){if(i.toString().startsWith("x-parsed-"))continue;t[i]=p(e[i])}return t}function N(e){return e.reduce((t,i)=>(i.relativePath.startsWith(l)||i.relativePath.startsWith(m)||!i.definition||typeof i.definition!="object"||!("paths"in i.definition)||i.definition?.paths&&Object.keys(i.definition.paths).length>0&&t.push({...i,definition:p(i.definition)}),t),[])}function S(e,t,i,r){const n={};for(const[o,s]of Object.entries(e))d(f(u,s.relativePath),i,r,t)&&(n[o]=s);return n}function b(e,t,i,r){return e.filter(n=>d(f(u,n.relativePath),i,r,t))}function M(e){return e.filter(({relativePath:t})=>!t.startsWith(l)&&!t.startsWith(m)).map(({relativePath:t,options:i})=>({name:i.info?.title||c.basename(t,c.extname(t)),description:i.info?.description,relativePath:t}))}function W(e,t){const i=a(t||[]);return e.filter(({relativePath:r})=>!i(r))}function q(e,t){if(!t?.length)return[];const i=a(t),r=e.filter(({fsPath:n})=>{if(!n)return!1;const o=g(n);return i(o)||i(D(o))}).map(({slug:n})=>A(n));return[...new Set(r)].sort()}function w(e={}){for(const[t,i]of Object.entries(e))if(t===h.mcp||(typeof i=="string"?i:i.to)===h.mcp)return!0;return!1}export{M as buildGraphqlDescriptions,T as bundledGraphqlDocumentsToMcpOpenApi,v as bundledOpenApiDocumentsToMcpOpenApi,q as collectIgnoredRoutes,S as filterApiDescriptionsByRbac,b as filterGraphqlDescriptionsByRbac,W as filterIgnoredApiDescriptions,N as getCleanedUpApiDescriptions,w as isMcpInRedirects};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import*as v from"path";import{REDOCLY_ROUTE_RBAC as b,REDOCLY_TEAMS_RBAC as h}from"@redocly/config";import{VERSION_SEPARATOR as M}from"../constants/common.js";import{DEFAULT_LOCALE_PLACEHOLDER as _}from"../../constants/common.js";import{removeTrailingSlash as j}from"../../utils/url/remove-trailing-slash.js";import{isPrimitive as W}from"../../utils/guards/is-primitive.js";import{slash as w}from"../../utils/path/slash.js";import{isAbsoluteUrl as z}from"../../utils/url/is-absolute-url.js";import{normalizeRouteSlug as J}from"../../utils/path/normalize-route-slug.js";import{parsePathVersions as C}from"../../utils/path/parse-path-versions.js";import{logger as A}from"../tools/notifiers/logger.js";import{reporter as S}from"../tools/notifiers/reporter.js";import{shaDirPathShort as R}from"../utils/crypto/sha-dir-path-short.js";import{copyStaticFile as U,FileNotFoundError as E}from"../utils/fs.js";import{isIconPath as H,resolveAssetPath as Y}from"../utils/index.js";import{resolveSrcSet as G}from"../utils/resolve-src-set.js";import{isL10nPath as B}from"../fs/utils/is-l10n-path.js";import{getLocaleFromRelativePath as q}from"../fs/utils/get-locale-from-relative-path.js";async function N(e,i,n,t,a){if(!e)return;const f={...a,ignoreCustomSidebar:!0};if(W(e)){if(typeof e=="string"){const r=F(n.contentDir,i,a,e,t.fs);if(t.fs.exists(r)){if(n.getRouteByFsPath(r))return K({page:e},i,n,t,f);{const g=t.fs.getFileInfo(r);return g?U(n.contentDir,g.realRelativePath,n.outdir):void 0}}}return e}return Array.isArray(e)?I(D(e),i,n,t,f):Object.fromEntries(await Promise.all(Object.entries(e).map(async([r,l])=>[r,await N(l,i,n,t,a)])))}function D(e){return e.map(i=>({...i,items:i.items?D(i.items):void 0}))}async function I(e,i,n,t,a){if(Array.isArray(e))return(await Promise.all(e.map(f=>K(f,i,n,t,a)))).flatMap(f=>f)}async function y(e,i,n,t){let a,f;if(typeof e.icon=="object"){if("srcSet"in e.icon)try{a=await G(e.icon.srcSet,n.fs,{fromFileRelativePath:t.navFile,contentDir:i.contentDir,outdir:i.outdir})}catch(d){d instanceof E?await S.panicOnBuildContentError(`Cannot resolve "item.icon.srcSet" from ${t.navFile}: ${d.message}`):await S.panicOnBuild(`Cannot resolve "item.icon.srcSet" from ${t.navFile}: ${d.message}`)}}else if(typeof e.icon=="string")if(z(e.icon)||H(e.icon))try{f=await Y(e.icon,n.fs,{fromFileRelativePath:t.navFile,contentDir:i.contentDir,outdir:i.outdir})}catch(d){d instanceof E?await S.panicOnBuildContentError(`Cannot resolve "item.icon" from ${t.navFile}: file ${f} does not exist`):await S.panicOnBuild(`Cannot resolve "item.icon" from ${t.navFile}: ${d.message}`)}else f=e.icon;return{icon:f,srcSet:a}}function Q(e){return i=>{if(i.type==="link"||i.type==="group"){const n=i.metadata;return n?Object.entries(e).every(([t,a])=>Array.isArray(a)?a.some(f=>n[t]===f):n[t]===a):!1}return!0}}async function K(e,i,n,t,a){if(e?.tab!==void 0||e?.menu!==void 0){const s=`Navigation tabs ("tab"/"menu") are only allowed at the top level of a sidebars.yaml file: ${JSON.stringify(e)}`;return await S.panicOnBuildContentError(`Invalid nav item in %rp. ${s}`,a.navFile),{type:"error",label:s}}if(e?.directory&&e.items?.length)return{type:"error",label:`Can't have both "directory" and "items" in the nav item: ${JSON.stringify(e)}`};e?.directory&&e?.group&&(e={...e,directory:void 0,items:[{directory:e.directory}]});const f=e?.directory?F(n.contentDir,i,a,e.directory,t.fs):void 0;if(f!==void 0){const s=f===""?"":f+"/",{locale:u,ignoredRoutes:o}=a,p=n.getAllRoutesForLocale(u).filter(c=>!o?.has(c.baseSlug||"")&&c.fsPath.startsWith(s)&&!c.excludeFromSidebar).sort((c,P)=>c.fsPath===P.fsPath?0:c.baseSlug.localeCompare(P.baseSlug,void 0,{numeric:!0})),m=e.includeByMetadata?Q(e.includeByMetadata):Boolean;if(!p.length)return[];const T=(await Promise.all(p.map(async c=>{const P=c.versions?.find(x=>x.active),L=P&&{version:P.version,isDefault:P.default,versionFolderId:P.folderId},V=ee(v.posix.relative(f,c.fsPath)),O=c.getSidebar?.(c);return!a.ignoreCustomSidebar&&O?.length?{type:"group",fsPath:c.fsPath,metadata:c.metadata,link:c.slug,routeSlug:c.slug,label:await c.getNavText?.()||c.slug,[h]:c[h],[b]:c[b],sidebarItems:k(O,L,c[h],c[b]),...L,relativePathFromDirectory:v.relative(f,c.fsPath).replace(/@(?<!@[^/]*?@)[^/]+\//,"")}:{type:"link",fsPath:c.fsPath,metadata:c.metadata,[h]:c[h],[b]:c[b],label:await c.getNavText?.()||c.slug,link:c.slug,routeSlug:c.slug,...L,relativePathFromDirectory:V}}))).filter(m);return e.flatten?$(T,a):Z(T,a)}let d=typeof e=="string"?e:e?.page,r,l;if(d){if(d.includes("#")){const[s,u]=d.split("#");u?l=u:A.warn(`Invalid heading anchor format in sidebar: "${u}". Heading anchors should contain only alphanumeric characters, hyphens, and underscores.`),d=s}if(d=j(d),a.locale&&a.locale!==_){const s=J(v.join(a.locale.toLowerCase(),d));r=n.getRouteBySlug(s)}r||(r=n.getRouteBySlug(d)),r||(r=n.getRouteByFsPath(F(n.contentDir,i,a,d,t.fs)))}const g=r?.metadata;if(e?.$ref){let s=F(n.contentDir,i,a,e.$ref,t.fs);if(a.ref!==void 0&&(s=v.posix.join(a.ref,e.$ref)),!t.fs.exists(s))return await S.panicOnBuildContentError(`Failed to load ${s} file. Make sure sidebar $ref path is correct.`),[];const u=await t.cache.load(s,"yaml"),o=v.dirname(s);return await I(u.data,i,n,t,{...a,navFile:s,ref:o})||[]}if(!r){const s=a.excludedFromLinkCheckerPatterns?.catalog.some(o=>o.test(d||"")),u=a.excludedFromLinkCheckerPatterns?.apiFunctions.some(o=>o.test(d||e.href||""));(u||s)&&(e={...e,href:d||e.href,page:void 0,target:e.target??(u?"_blank":void 0)}),await X(e,a,t,i)}if(r&&!e.disconnect&&!a.ignoreCustomSidebar&&(l||r?.getSidebar)){const s=r.versions?.find(o=>o.active),u=s&&{version:s.version,isDefault:s.default,versionFolderId:s.folderId};if(l){let o=[];if(r.getSidebar&&(o=r.getSidebar(r,{...e,...await y(e,n,t,a)}),o&&o.length>0)){const p=o[0];p&&p.link&&(p.link=`${p.link}#${l}`)}if(!o||o.length===0){const p=e.group||e.label||l;o=[{type:"link",fsPath:r.fsPath,metadata:r.metadata,link:`${r.slug}#${l}`,routeSlug:r.slug,label:p,labelTranslationKey:e.labelTranslationKey,...await y(e,n,t,a),[h]:r[h],[b]:{slug:r.slug,fsPath:r.fsPath},...u}]}return k(o,u,r[h],r[b])}if(r?.getSidebar){const o=r.getSidebar(r,{...e,...await y(e,n,t,a)}),p=e.group&&o?.[0]?.routeSlug===r.slug?o.slice(1):o;return k(a.groupCustomSidebars||e.group?[{type:"group",fsPath:r.fsPath,link:r.slug,routeSlug:r.slug,label:e.group||e.label||await r.getNavText?.()||r.slug,items:p,labelTranslationKey:e.labelTranslationKey,metadata:g,badges:e.badges,...await y(e,n,t,a)}]:o,u,r[h],r[b])}}if(r&&!e.group){const s=l?`${r.slug}#${l}`:r.slug;let u=e.label||l||"";u||(u=await r.getNavText?.()||r.slug);const o=r.versions?.find(m=>m.active),p=o&&{version:o.version,isDefault:o.default,versionFolderId:o.folderId};return{type:"link",fsPath:r.fsPath,linkedSidebars:e.linkedSidebars,metadata:g,[h]:e?.rbac||r[h],[b]:{slug:r.slug,fsPath:r.fsPath},label:u,labelTranslationKey:e.labelTranslationKey,link:s,items:await I(e.items,i,n,t,a),separatorLine:e.separatorLine,linePosition:e.linePosition,routeSlug:e.disconnect?void 0:s,external:e.external,target:e.target,badges:e.badges,...await y(e,n,t,a),...p,additionalProps:e.additionalProps}}else if(e?.group){const s=r?.versions?.find(o=>o.active),u=C(a?.navFile);return{type:"group",fsPath:r?.fsPath,linkedSidebars:e.linkedSidebars,metadata:g,version:s?.version||u?.versionName,versionFolderId:s?.folderId||(u?.versionFolderPath?R(u.versionFolderPath):void 0),label:e.group,link:r?.slug,routeSlug:r?.slug,badges:e.badges,labelTranslationKey:e.groupTranslationKey,items:await I(e.items,i,n,t,a),expanded:e.expanded?e.expanded.toString():void 0,selectFirstItemOnExpand:e.selectFirstItemOnExpand,menuStyle:e.menuStyle,separatorLine:e.separatorLine,linePosition:e.linePosition,...await y(e,n,t,a),[h]:e?.rbac,[b]:{slug:r?.slug||"",fsPath:r?.fsPath||""},additionalProps:e.additionalProps}}else{if(e?.href||e?.label)return{type:"link",metadata:g,link:e.href||"",label:e?.label||e?.href||"",labelTranslationKey:e.labelTranslationKey,external:e.external,target:e.target,separatorLine:e.separatorLine,linePosition:e.linePosition,badges:e.badges,...await y(e,n,t,a),[h]:e?.rbac,additionalProps:e.additionalProps};if(e?.separator!=null||e?.separatorLine!=null){const s=C(a?.navFile);return{type:"separator",metadata:g,version:s?.versionName,versionFolderId:s?.versionFolderPath?R(s.versionFolderPath):void 0,label:e.separator,labelTranslationKey:e.separatorTranslationKey,separatorLine:e.separatorLine,linePosition:e.linePosition,...await y(e,n,t,a),[h]:e?.rbac,additionalProps:e.additionalProps}}else{const s=C(a?.navFile);return{type:"error",label:`Can't resolve page: ${JSON.stringify(e)}`,version:s?.versionName,versionFolderId:s?.versionFolderPath?R(s.versionFolderPath):void 0}}}}async function X(e,i,n,t){const{href:a,page:f}=e;if(a||!f)return;const d=F(n.fs.cwd,t,i,f,n.fs),r=n.fs.exists(d),l=await n.isPathIgnored(d),g=(r?"The page is ignored: ":"Can't resolve page: ")+f;(!r||l)&&S.reportBrokenLink({type:"BROKEN_LINK",brokenLinkType:"LINK",title:e.label||e.group||"",link:d,rawLink:f,message:g,sourceFileRelativePath:i.navFile,sourceFileLocation:{line:0}})}function F(e,i,n,t="",a){if(n.ref!==void 0)return w(v.relative(e,v.resolve(e,v.join(n.ref,t))));if(t.startsWith("/")){const f=B(i)?q(i):void 0,d=f?`${a.localizationFolder}/${f}/`:"",r=t.slice(1);return B(r)?r:d+w(r)}return w(v.relative(e,v.resolve(e,i,t)))}function Z(e,i){const n={};for(const r of e){const l=v.dirname(r.relativePathFromDirectory),g=r.version?M+r.version:"",s=v.basename(r.relativePathFromDirectory)+g;d(l,r,s)}const t=f(a(n));return $(t,i);function a(r){const l=[];for(const g of Object.keys(r)){const s=r[g];l.push({...s,items:s.items?a(s.items):void 0})}return l}function f(r){return r.sort((l,g)=>{const s=typeof l=="string"?l.toLowerCase():l.relativePathFromDirectory||l.label||"",u=typeof g=="string"?g.toLowerCase():g.relativePathFromDirectory||g.label||"";return s.startsWith("index.")?-1:u.startsWith("index.")?1:s.localeCompare(u,void 0,{numeric:!0})})}function d(r,l,g){r==="."&&(r="");const s=r.split("/").filter(Boolean);let u=n;for(const o of s){const p=o+(l?.version||"");u[p]||(u[p]={type:"group",version:l?.version,label:o,isDefault:l?.isDefault,versionFolderId:l.versionFolderId,items:{}}),u=u[p].items}u[g]=l}}function $(e,i){return e.flatMap(n=>n?.sidebarItems?i.groupCustomSidebars?{...n,items:n.sidebarItems,sidebarItems:void 0,relativePathFromDirectory:void 0}:n.sidebarItems:{...n,items:n.items?$(n.items,i):void 0})}function k(e,i,n,t){return e.map(a=>({...a,...i,[h]:a[h]||n,[b]:a[b]||t,items:a.type==="group"&&a.items?k(a.items,i,n):a.items}))}function ee(e){return e.replace(/@(?<!@[^/]*?@)[^/]+\//,"")}async function ye(e,i,n,t){const a=(e?.items||[]).filter(r=>r.linkedSidebars?.length).map(r=>({...r,items:void 0})),f=await N(a,i.contentDir,i,n,t),d=new Map;for(const r of f)if(r.linkedSidebars?.length)for(const l of r.linkedSidebars){if(d.has(l)){A.warn(`Only one navbar item can belong to sidebar. "${l}" on 'linkedSidebars' property on "${r.label}" will be ignored.`);continue}d.set(l,{label:r.label,link:r.link})}return d}export{ye as collectItemsLinkedToSidebars,D as normalizeItems,K as resolveItem,I as resolveItems,N as resolveLinksFromConfig};
|
|
1
|
+
import*as h from"path";import{REDOCLY_ROUTE_RBAC as b,REDOCLY_TEAMS_RBAC as p}from"@redocly/config";import{VERSION_SEPARATOR as x}from"../constants/common.js";import{DEFAULT_LOCALE_PLACEHOLDER as M}from"../../constants/common.js";import{removeTrailingSlash as j}from"../../utils/url/remove-trailing-slash.js";import{isPrimitive as W}from"../../utils/guards/is-primitive.js";import{slash as w}from"../../utils/path/slash.js";import{isAbsoluteUrl as z}from"../../utils/url/is-absolute-url.js";import{normalizeRouteSlug as J}from"../../utils/path/normalize-route-slug.js";import{parsePathVersions as C}from"../../utils/path/parse-path-versions.js";import{logger as A}from"../tools/notifiers/logger.js";import{reporter as F}from"../tools/notifiers/reporter.js";import{shaDirPathShort as R}from"../utils/crypto/sha-dir-path-short.js";import{copyStaticFile as U,FileNotFoundError as D}from"../utils/fs.js";import{isIconPath as H,resolveAssetPath as Y}from"../utils/index.js";import{resolveSrcSet as G}from"../utils/resolve-src-set.js";import{isL10nPath as E}from"../fs/utils/is-l10n-path.js";import{getLocaleFromRelativePath as q}from"../fs/utils/get-locale-from-relative-path.js";async function B(e,i,n,s,a){if(!e)return;const f={...a,ignoreCustomSidebar:!0};if(W(e)){if(typeof e=="string"){const r=I(n.contentDir,i,a,e,s.fs);if(s.fs.exists(r)){if(n.getRouteByFsPath(r))return K({page:e},i,n,s,f);{const g=s.fs.getFileInfo(r);return g?U(n.contentDir,g.realRelativePath,n.outdir):void 0}}}return e}return Array.isArray(e)?k(N(e),i,n,s,f):Object.fromEntries(await Promise.all(Object.entries(e).map(async([r,l])=>[r,await B(l,i,n,s,a)])))}function N(e){return e.map(i=>({...i,items:i.items?N(i.items):void 0}))}async function k(e,i,n,s,a){if(Array.isArray(e))return(await Promise.all(e.map(f=>K(f,i,n,s,a)))).flatMap(f=>f)}async function y(e,i,n,s){let a,f;if(typeof e.icon=="object"){if("srcSet"in e.icon)try{a=await G(e.icon.srcSet,n.fs,{fromFileRelativePath:s.navFile,contentDir:i.contentDir,outdir:i.outdir})}catch(d){d instanceof D?await F.panicOnBuildContentError(`Cannot resolve "item.icon.srcSet" from ${s.navFile}: ${d.message}`):await F.panicOnBuild(`Cannot resolve "item.icon.srcSet" from ${s.navFile}: ${d.message}`)}}else if(typeof e.icon=="string")if(z(e.icon)||H(e.icon))try{f=await Y(e.icon,n.fs,{fromFileRelativePath:s.navFile,contentDir:i.contentDir,outdir:i.outdir})}catch(d){d instanceof D?await F.panicOnBuildContentError(`Cannot resolve "item.icon" from ${s.navFile}: file ${f} does not exist`):await F.panicOnBuild(`Cannot resolve "item.icon" from ${s.navFile}: ${d.message}`)}else f=e.icon;return{icon:f,srcSet:a}}function Q(e){return i=>{if(i.type==="link"||i.type==="group"){const n=i.metadata;return n?Object.entries(e).every(([s,a])=>Array.isArray(a)?a.some(f=>n[s]===f):n[s]===a):!1}return!0}}async function K(e,i,n,s,a){if(e?.tab!==void 0||e?.menu!==void 0){const t=`Navigation tabs ("tab"/"menu") are only allowed at the top level of a sidebars.yaml file: ${JSON.stringify(e)}`;return await F.panicOnBuildContentError(`Invalid nav item in %rp. ${t}`,a.navFile),{type:"error",label:t}}if(e?.directory&&e.items?.length)return{type:"error",label:`Can't have both "directory" and "items" in the nav item: ${JSON.stringify(e)}`};e?.directory&&e?.group&&(e={...e,directory:void 0,items:[{directory:e.directory}]});const f=e?.directory?I(n.contentDir,i,a,e.directory,s.fs):void 0;if(f!==void 0){const t=f===""?"":f+"/",{locale:u,ignoredRoutes:o}=a,v=n.getAllRoutesForLocale(u).filter(c=>!o?.has(c.baseSlug||"")&&c.fsPath.startsWith(t)&&!c.excludeFromSidebar).sort((c,P)=>c.fsPath===P.fsPath?0:c.baseSlug.localeCompare(P.baseSlug,void 0,{numeric:!0})),L=e.includeByMetadata?Q(e.includeByMetadata):Boolean;if(!v.length)return[];const T=(await Promise.all(v.map(async c=>{const P=c.versions?.find(_=>_.active),S=P&&{version:P.version,isDefault:P.default,versionFolderId:P.folderId},V=ee(h.posix.relative(f,c.fsPath)),O=c.getSidebar?.(c);return!a.ignoreCustomSidebar&&O?.length?{type:"group",fsPath:c.fsPath,metadata:c.metadata,link:c.slug,routeSlug:c.slug,label:await c.getNavText?.()||c.slug,[p]:c[p],[b]:c[b],sidebarItems:m(O,S,c[p],c[b]),version:S?.version,isDefault:S?.isDefault,versionFolderId:S?.versionFolderId,relativePathFromDirectory:h.relative(f,c.fsPath).replace(/@(?<!@[^/]*?@)[^/]+\//,"")}:{type:"link",fsPath:c.fsPath,metadata:c.metadata,[p]:c[p],[b]:c[b],label:await c.getNavText?.()||c.slug,link:c.slug,routeSlug:c.slug,version:S?.version,isDefault:S?.isDefault,versionFolderId:S?.versionFolderId,relativePathFromDirectory:V}}))).filter(L);return e.flatten?$(T,a):Z(T,a)}let d=typeof e=="string"?e:e?.page,r,l;if(d){if(d.includes("#")){const[t,u]=d.split("#");u?l=u:A.warn(`Invalid heading anchor format in sidebar: "${u}". Heading anchors should contain only alphanumeric characters, hyphens, and underscores.`),d=t}if(d=j(d),a.locale&&a.locale!==M){const t=J(h.join(a.locale.toLowerCase(),d));r=n.getRouteBySlug(t)}r||(r=n.getRouteBySlug(d)),r||(r=n.getRouteByFsPath(I(n.contentDir,i,a,d,s.fs)))}const g=r?.metadata;if(e?.$ref){let t=I(n.contentDir,i,a,e.$ref,s.fs);if(a.ref!==void 0&&(t=h.posix.join(a.ref,e.$ref)),!s.fs.exists(t))return await F.panicOnBuildContentError(`Failed to load ${t} file. Make sure sidebar $ref path is correct.`),[];const u=await s.cache.load(t,"yaml"),o=h.dirname(t);return await k(u.data,i,n,s,{...a,navFile:t,ref:o})||[]}if(!r){const t=a.excludedFromLinkCheckerPatterns?.catalog.some(o=>o.test(d||"")),u=a.excludedFromLinkCheckerPatterns?.apiFunctions.some(o=>o.test(d||e.href||""));(u||t)&&(e={...e,href:d||e.href,page:void 0,target:e.target??(u?"_blank":void 0)}),await X(e,a,s,i)}if(r&&!e.disconnect&&!a.ignoreCustomSidebar&&(l||r?.getSidebar)){const t=r.versions?.find(o=>o.active),u=t&&{version:t.version,isDefault:t.default,versionFolderId:t.folderId};if(l){let o=[];if(r.getSidebar&&(o=r.getSidebar(r,{...e,...await y(e,n,s,a)}),o&&o.length>0)){const v=o[0];v&&v.link&&(v.link=`${v.link}#${l}`)}if(!o||o.length===0){const v=e.group||e.label||l;o=[{type:"link",fsPath:r.fsPath,metadata:r.metadata,link:`${r.slug}#${l}`,routeSlug:r.slug,label:v,labelTranslationKey:e.labelTranslationKey,...await y(e,n,s,a),[p]:r[p],[b]:{slug:r.slug,fsPath:r.fsPath},...u}]}return m(o,u,r[p],r[b])}if(r?.getSidebar){const o=r.getSidebar(r,{...e,...await y(e,n,s,a)}),v=e.group&&o?.[0]?.routeSlug===r.slug?o.slice(1):o;return m(a.groupCustomSidebars||e.group?[{type:"group",fsPath:r.fsPath,link:r.slug,routeSlug:r.slug,label:e.group||e.label||await r.getNavText?.()||r.slug,items:v,labelTranslationKey:e.labelTranslationKey,metadata:g,badges:e.badges,...await y(e,n,s,a)}]:o,u,r[p],r[b])}}if(r&&!e.group){const t=l?`${r.slug}#${l}`:r.slug;let u=e.label||l||"";u||(u=await r.getNavText?.()||r.slug);const o=r.versions?.find(L=>L.active),v=o&&{version:o.version,isDefault:o.default,versionFolderId:o.folderId};return{type:"link",fsPath:r.fsPath,linkedSidebars:e.linkedSidebars,metadata:g,[p]:e?.rbac||r[p],[b]:{slug:r.slug,fsPath:r.fsPath},label:u,labelTranslationKey:e.labelTranslationKey,link:t,items:await k(e.items,i,n,s,a),separatorLine:e.separatorLine,linePosition:e.linePosition,routeSlug:e.disconnect?void 0:t,external:e.external,target:e.target,badges:e.badges,...await y(e,n,s,a),...v,additionalProps:e.additionalProps}}else if(e?.group){const t=r?.versions?.find(o=>o.active),u=C(a?.navFile);return{type:"group",fsPath:r?.fsPath,linkedSidebars:e.linkedSidebars,metadata:g,version:t?.version||u?.versionName,versionFolderId:t?.folderId||(u?.versionFolderPath?R(u.versionFolderPath):void 0),label:e.group,link:r?.slug,routeSlug:r?.slug,badges:e.badges,labelTranslationKey:e.groupTranslationKey,items:await k(e.items,i,n,s,a),expanded:e.expanded?e.expanded.toString():void 0,selectFirstItemOnExpand:e.selectFirstItemOnExpand,menuStyle:e.menuStyle,separatorLine:e.separatorLine,linePosition:e.linePosition,...await y(e,n,s,a),[p]:e?.rbac,[b]:{slug:r?.slug||"",fsPath:r?.fsPath||""},additionalProps:e.additionalProps}}else{if(e?.href||e?.label)return{type:"link",metadata:g,link:e.href||"",label:e?.label||e?.href||"",labelTranslationKey:e.labelTranslationKey,external:e.external,target:e.target,separatorLine:e.separatorLine,linePosition:e.linePosition,badges:e.badges,...await y(e,n,s,a),[p]:e?.rbac,additionalProps:e.additionalProps};if(e?.separator!=null||e?.separatorLine!=null){const t=C(a?.navFile);return{type:"separator",metadata:g,version:t?.versionName,versionFolderId:t?.versionFolderPath?R(t.versionFolderPath):void 0,label:e.separator,labelTranslationKey:e.separatorTranslationKey,separatorLine:e.separatorLine,linePosition:e.linePosition,...await y(e,n,s,a),[p]:e?.rbac,additionalProps:e.additionalProps}}else{const t=C(a?.navFile);return{type:"error",label:`Can't resolve page: ${JSON.stringify(e)}`,version:t?.versionName,versionFolderId:t?.versionFolderPath?R(t.versionFolderPath):void 0}}}}async function X(e,i,n,s){const{href:a,page:f}=e;if(a||!f)return;const d=I(n.fs.cwd,s,i,f,n.fs),r=n.fs.exists(d),l=await n.isPathIgnored(d),g=(r?"The page is ignored: ":"Can't resolve page: ")+f;(!r||l)&&F.reportBrokenLink({type:"BROKEN_LINK",brokenLinkType:"LINK",title:e.label||e.group||"",link:d,rawLink:f,message:g,sourceFileRelativePath:i.navFile,sourceFileLocation:{line:0}})}function I(e,i,n,s="",a){if(n.ref!==void 0)return w(h.relative(e,h.resolve(e,h.join(n.ref,s))));if(s.startsWith("/")){const f=E(i)?q(i):void 0,d=f?`${a.localizationFolder}/${f}/`:"",r=s.slice(1);return E(r)?r:d+w(r)}return w(h.relative(e,h.resolve(e,i,s)))}function Z(e,i){const n={};for(const r of e){const l=h.dirname(r.relativePathFromDirectory),g=r.version?x+r.version:"",t=h.basename(r.relativePathFromDirectory)+g;d(l,r,t)}const s=f(a(n));return $(s,i);function a(r){const l=[];for(const g of Object.keys(r)){const t=r[g];l.push({...t,items:t.items?a(t.items):void 0})}return l}function f(r){return r.sort((l,g)=>{const t=typeof l=="string"?l.toLowerCase():l.relativePathFromDirectory||l.label||"",u=typeof g=="string"?g.toLowerCase():g.relativePathFromDirectory||g.label||"";return t.startsWith("index.")?-1:u.startsWith("index.")?1:t.localeCompare(u,void 0,{numeric:!0})})}function d(r,l,g){r==="."&&(r="");const t=r.split("/").filter(Boolean);let u=n;for(const o of t){const v=o+(l?.version||"");u[v]||(u[v]={type:"group",version:l?.version,label:o,isDefault:l?.isDefault,versionFolderId:l.versionFolderId,items:{}}),u=u[v].items}u[g]=l}}function $(e,i){return e.flatMap(n=>n?.sidebarItems?i.groupCustomSidebars?{...n,items:n.sidebarItems,sidebarItems:void 0,relativePathFromDirectory:void 0}:n.sidebarItems:{...n,items:n.items?$(n.items,i):void 0})}function m(e,i,n,s){return e.map(a=>({...a,...i,[p]:a[p]||n,[b]:a[b]||s,items:a.type==="group"&&a.items?m(a.items,i,n):a.items}))}function ee(e){return e.replace(/@(?<!@[^/]*?@)[^/]+\//,"")}async function ye(e,i,n,s){const a=(e?.items||[]).filter(r=>r.linkedSidebars?.length).map(({items:r,...l})=>l),f=await B(a,i.contentDir,i,n,s),d=new Map;for(const r of f)if(r.linkedSidebars?.length)for(const l of r.linkedSidebars){if(d.has(l)){A.warn(`Only one navbar item can belong to sidebar. "${l}" on 'linkedSidebars' property on "${r.label}" will be ignored.`);continue}d.set(l,{label:r.label,link:r.link})}return d}export{ye as collectItemsLinkedToSidebars,N as normalizeItems,K as resolveItem,k as resolveItems,B as resolveLinksFromConfig};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import g from"node:path";import{REDOCLY_TEAMS_RBAC as h}from"@redocly/config";import{slash as S}from"../../../utils/path/slash.js";import{canAccessFeature as y}from"../../utils/entitlements/can-access-feature.js";import{staticDataLoader as b}from"./loaders/static-data-loader.js";import{findFrontmatterSlugs as F,getSidebarSharedDataId as P,resolveFrontmatterSlugs as
|
|
1
|
+
import g from"node:path";import{REDOCLY_TEAMS_RBAC as h}from"@redocly/config";import{slash as S}from"../../../utils/path/slash.js";import{canAccessFeature as y}from"../../utils/entitlements/can-access-feature.js";import{staticDataLoader as b}from"./loaders/static-data-loader.js";import{findFrontmatterSlugs as F,getSidebarSharedDataId as P,resolveFrontmatterSlugs as v}from"../utils.js";import{reactFrontmatterLoader as w}from"./loaders/react-frontmatter-loader.js";import{registerPageProps as D}from"../register-page-props.js";import{telemetryTraceStep as R}from"../../../cli/telemetry/helpers/trace-step.js";import{searchResolver as E}from"./search/search-resolver.js";async function x(){return{loaders:{"react-frontmatter":w},id:"react-pages",requiredEntitlements:["reactPages"],processContent:async(r,a)=>{await R("com.redocly.build.plugin.pages",async()=>{const{fs:o,cache:f}=a;for(const n of o.scan(/\.page\.tsx?$/)){const{relativePath:e,realRelativePath:l}=n;if(await a.isPathIgnored(e))continue;const p=r.createTemplate(S(e),g.resolve(o.cwd,l));D(n,o,r);const{data:t}=await f.load(e,"react-frontmatter"),u=await F(e,"react-frontmatter",t,a),s=v(u,e);let c=null;t?.sidebar&&(c=await P(t.sidebar,e,a.fs)),(s.length?s.reverse():[void 0]).forEach(i=>{r.addRoute({excludeFromSearch:t?.excludeFromSearch||!1,slug:i,templateId:p,fsPath:e,sharedData:c?[{id:c,key:"sidebar"}]:void 0,[h]:y("rbac")?t?.rbac:void 0,getNavText:async()=>t?.seo?.title,getStaticData:async(m,d)=>({props:await b({frontmatter:t,relativePath:e},a,d)}),getSearchDocuments:E(t,e,r.getSearchFacets,r.setSearchFacets)})});for(const[i,{to:m,type:d}]of Object.entries(t?.redirects||{}))r.addRedirect(i,{to:m||s[0],type:d||301})}})}}}export{x as customPagesPlugin};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { ContentFs } from '../fs/content-fs.js';
|
|
2
2
|
import type { FileInfo, ProcessContentActions } from '../types';
|
|
3
|
-
export declare function registerPageProps(file: FileInfo, fs: ContentFs, actions: ProcessContentActions):
|
|
3
|
+
export declare function registerPageProps(file: FileInfo, fs: ContentFs, actions: ProcessContentActions): void;
|
|
4
4
|
//# sourceMappingURL=register-page-props.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import
|
|
1
|
+
import a from"path";function l(e,t,p){const{realRelativePath:r,relativePath:o}=e;let s;r.match(/\.md$/)&&(s=r.replace(/\.md$/,".props.ts")),r.match(/\.page\.tsx?$/)&&(s=r.replace(/\.page\.tsx?$/,".props.ts"));const i=s?n(s,t):void 0;i&&p.registerPagePropsGetter(o,i)}function n(e,t){return t.exists(e)?a.resolve(t.cwd,e):void 0}export{l as registerPageProps};
|
|
@@ -4,4 +4,4 @@ import{writeFileSync as at}from"node:fs";import*as g from"path";import{removeMar
|
|
|
4
4
|
- ${y.join(`
|
|
5
5
|
- `)}`,m);return}const{fromDir:k,resolveOptions:n}=V(m,f,p);return Ft(l,k,a,c,n)}))).flat().filter(M),e=vt(r),s=It(e);if(s.length){await I.panicOnBuildContentError(`Navigation tabs conflict in %rp. A route can belong to one tab only:
|
|
6
6
|
- ${s.map(({routeSlug:l,owners:f})=>`${l} is claimed by ${f.map(m=>`"${m}"`).join(" and ")}`).join(`
|
|
7
|
-
- `)}`,i);return}return{routeOwners:e,sharedData:{items:[],tabs:r},navItems:Ct(r)}}function V(t,i,o){return{fromDir:g.dirname(g.join(u,t)),resolveOptions:{locale:i,ignoredRoutes:o,navFile:t,excludedFromLinkCheckerPatterns:T}}}async function rt(t,{routeOwners:i,sharedData:o,navItems:r}){const e=Q(t),s=new Set;for(const{routeSlug:f,items:m}of i){const p=a.getRouteBySlug(f)?.fsPath??"",y=x[p];y&&(Array.from(s).find(n=>n.key===y.key&&n.version===y.version)||s.add(y)),a.addRouteSharedData(f,"sidebar",e),F.set(J(f),m)}const l=s.size===1?Array.from(s)[0]:void 0;return await a.createSharedData(e,{relatedNavbarItem:tt?.get(t),...o,catalogEntity:l?{key:l.key,version:l.version}:void 0}),{firstLink:B(r,f=>!!f.link),resolved:r}}async function K(t,i,o,r=!1){const e=structuredClone(i);o&&o!==E&&e.items.forEach(n=>{n.directory=g.posix.join(d.localizationFolder||"",o,n.directory||"")});const s=await q(e.items,u,a,c,{groupCustomSidebars:!0,locale:o,navFile:Y,excludedFromLinkCheckerPatterns:T});if(!s){await I.panicOnBuild(`Failed to resolve catalog configuration. Make sure catalog ${t} has valid config`);return}Bt(s);const l=o===E?"":"/"+o.toLowerCase(),f=o===E?"":`-${o}`,m=J(g.posix.join(l,e.slug));if(r)for(const n of s){const S=B(n.items||[],v=>!!v.routeSlug);if(!S?.routeSlug)continue;const b=F.get(S.routeSlug);if(!b)continue;const O=N(b,"routeSlug"),R="current-catalog-info-"+n.routeSlug+f,P={catalog:{label:e.title,titleTranslationKey:e.titleTranslationKey,link:m,icon:e?.icon},item:{label:n.metadata?.title,link:n.link,icon:n.icon}};await a.createSharedData(R,P);for(const v of O)a.addRouteSharedData(v,"current-catalog-info",R),C.add(v);const X=B(b,v=>!!v.link&&!v.external&&ut(v.link)&&(!n.version||v.version===n.version));X&&(n.sidebar=[{...X,items:void 0}])}const p={},y=new Set;for(const n of s){if(!(n.routeSlug||n.sidebar?.[0]?.routeSlug)||!n.fsPath||y.has(n.fsPath))continue;y.add(n.fsPath);const b=g.dirname(n.fsPath);p[b]=(p[b]||0)+1}if(r){const n=await a.createSharedData(pt(t,f),s.flatMap(S=>{const b=g.dirname(S.fsPath??""),O=p[b]===1,R=P=>({...P,fsPath:O?b:P.fsPath??""});return S.type==="group"&&S.items?.every(P=>P.type==="group")?(S.items||[]).map(R):R(S)}));a.addRouteSharedData(m,"catalog",n),Ot(o,s,j,p)}const k=N(s,"routeSlug");for(const n of k)C.add(n)}})}}}function Ot(u,a,c,h){if(u===E)for(const d of a){const D=d.routeSlug||d.sidebar?.[0]?.routeSlug;if(!D||!d.fsPath)continue;const F=g.dirname(d.fsPath),C=h[F]===1;c.set(D,{rootFileFsPath:d.fsPath,fsPath:C?F:d.fsPath,metadata:d.metadata||{},title:d.metadata?.title||d.label||"Untitled",version:d.version||"latest"})}}function Bt(u){const a=c=>{typeof c.metadata?.description=="string"&&(c.metadata={...c.metadata,description:nt(c.metadata.description)})};for(const c of u)if(c.routeSlug)a(c);else for(const h of c.items||[])a(h)}function Q(u){return st+dt(u)}async function fe(u,a,c){const h=g.posix.join(g.dirname(u),a);return
|
|
7
|
+
- `)}`,i);return}return{routeOwners:e,sharedData:{items:[],tabs:r},navItems:Ct(r)}}function V(t,i,o){return{fromDir:g.dirname(g.join(u,t)),resolveOptions:{locale:i,ignoredRoutes:o,navFile:t,excludedFromLinkCheckerPatterns:T}}}async function rt(t,{routeOwners:i,sharedData:o,navItems:r}){const e=Q(t),s=new Set;for(const{routeSlug:f,items:m}of i){const p=a.getRouteBySlug(f)?.fsPath??"",y=x[p];y&&(Array.from(s).find(n=>n.key===y.key&&n.version===y.version)||s.add(y)),a.addRouteSharedData(f,"sidebar",e),F.set(J(f),m)}const l=s.size===1?Array.from(s)[0]:void 0;return await a.createSharedData(e,{relatedNavbarItem:tt?.get(t),...o,catalogEntity:l?{key:l.key,version:l.version}:void 0}),{firstLink:B(r,f=>!!f.link),resolved:r}}async function K(t,i,o,r=!1){const e=structuredClone(i);o&&o!==E&&e.items.forEach(n=>{n.directory=g.posix.join(d.localizationFolder||"",o,n.directory||"")});const s=await q(e.items,u,a,c,{groupCustomSidebars:!0,locale:o,navFile:Y,excludedFromLinkCheckerPatterns:T});if(!s){await I.panicOnBuild(`Failed to resolve catalog configuration. Make sure catalog ${t} has valid config`);return}Bt(s);const l=o===E?"":"/"+o.toLowerCase(),f=o===E?"":`-${o}`,m=J(g.posix.join(l,e.slug));if(r)for(const n of s){const S=B(n.items||[],v=>!!v.routeSlug);if(!S?.routeSlug)continue;const b=F.get(S.routeSlug);if(!b)continue;const O=N(b,"routeSlug"),R="current-catalog-info-"+n.routeSlug+f,P={catalog:{label:e.title,titleTranslationKey:e.titleTranslationKey,link:m,icon:e?.icon},item:{label:n.metadata?.title,link:n.link,icon:n.icon}};await a.createSharedData(R,P);for(const v of O)a.addRouteSharedData(v,"current-catalog-info",R),C.add(v);const X=B(b,v=>!!v.link&&!v.external&&ut(v.link)&&(!n.version||v.version===n.version));X&&(n.sidebar=[{...X,items:void 0}])}const p={},y=new Set;for(const n of s){if(!(n.routeSlug||n.sidebar?.[0]?.routeSlug)||!n.fsPath||y.has(n.fsPath))continue;y.add(n.fsPath);const b=g.dirname(n.fsPath);p[b]=(p[b]||0)+1}if(r){const n=await a.createSharedData(pt(t,f),s.flatMap(S=>{const b=g.dirname(S.fsPath??""),O=p[b]===1,R=P=>({...P,fsPath:O?b:P.fsPath??""});return S.type==="group"&&S.items?.every(P=>P.type==="group")?(S.items||[]).map(R):R(S)}));a.addRouteSharedData(m,"catalog",n),Ot(o,s,j,p)}const k=N(s,"routeSlug");for(const n of k)C.add(n)}})}}}function Ot(u,a,c,h){if(u===E)for(const d of a){const D=d.routeSlug||d.sidebar?.[0]?.routeSlug;if(!D||!d.fsPath)continue;const F=g.dirname(d.fsPath),C=h[F]===1;c.set(D,{rootFileFsPath:d.fsPath,fsPath:C?F:d.fsPath,metadata:d.metadata||{},title:d.metadata?.title||d.label||"Untitled",version:d.version||"latest"})}}function Bt(u){const a=c=>{typeof c.metadata?.description=="string"&&(c.metadata={...c.metadata,description:nt(c.metadata.description)})};for(const c of u)if(c.routeSlug)a(c);else for(const h of c.items||[])a(h)}function Q(u){return st+dt(u)}async function fe(u,a,c){const h=g.posix.join(g.dirname(u),a);return c.exists(h)?Q(h):(await I.panicOnBuildContentErrorForRealFile("File %rp: Failed to create relative path for sidebars.yaml using %s",u,c,u,a),null)}function Mt(u){const a=u.replaceAll("/","_");if(a.length>Lt){const c=a.slice(0,Tt),h=gt(u).slice(0,_t).replaceAll("/","_");return c+h}else return a}export{fe as resolveSidebarId,ce as sidebarsPlugin,Bt as stripMarkdocFromDescriptions};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import s from"path";import{collectPropValueDeep as g}from"../../../utils/tree/collect-prop-value-deep.js";import{removeTrailingSlash as f}from"../../../utils/url/remove-trailing-slash.js";import{slash as C}from"../../../utils/path/slash.js";import{removeLeadingSlash as u}from"../../../utils/url/remove-leading-slash.js";import{reporter as p}from"../../tools/notifiers/reporter.js";import{getCompleteCatalogConfig as h}from"../catalog-entities/get-complete-catalog-config.js";async function k({fs:r,cache:i},e,n){const a=new Map;for(const t of n){if(!
|
|
1
|
+
import s from"path";import{collectPropValueDeep as g}from"../../../utils/tree/collect-prop-value-deep.js";import{removeTrailingSlash as f}from"../../../utils/url/remove-trailing-slash.js";import{slash as C}from"../../../utils/path/slash.js";import{removeLeadingSlash as u}from"../../../utils/url/remove-leading-slash.js";import{reporter as p}from"../../tools/notifiers/reporter.js";import{getCompleteCatalogConfig as h}from"../catalog-entities/get-complete-catalog-config.js";async function k({fs:r,cache:i},e,n){const a=new Map;for(const t of n){if(!r.exists(t))continue;const o=s.dirname(s.join(e,t)),m=(await i.load(t,"yaml")).data;try{const c=g(m,"$ref");for(const d of c){const l=C(s.relative(e,s.join(o,d)));a.has(l)&&await p.panicOnBuildContentError(`Sidebar reference '${l}' was used multiple times.`),a.set(l,t)}}catch(c){if(c.message.includes("not iterable")){await p.panicOnBuildContentErrorForRealFile('Invalid sidebar format at %rp, "items" should be an array',t,r,t);continue}throw c}}return a}function v(r){function i(e,n){if(n.includes(e))return[...n,e];const a=r.get(e);if(a){const t=i(a,[...n,e]);if(t)return t}return!1}for(const e of r.keys()){const n=i(e,[]);if(n)return n}return!1}function P(r){const i=r.apiFunctions?.folders?.map(o=>new RegExp(`^/?(${u(f(o))})(/|$)`))||[],e=[new RegExp("^/?(api)(/|$)")],n=h(r.entitiesCatalog),t=Object.values(n?.catalogs||{}).map(o=>o?.slug?new RegExp(`^/?(catalogs\\/${u(f(o?.slug||""))})(/|$)`):null).filter(o=>o!==null);return{apiFunctions:[...i,...e],catalog:t}}export{P as getExcludedFromLinkCheckerPatterns,k as getSidebarReferences,v as hasCircularDependency};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import*as
|
|
1
|
+
import*as o from"dotenv";import*as n from"path";import{simpleGit as p}from"simple-git";import{envConfig as s,reloadEnvConfig as c,setEnv as m}from"../../config/env-config.js";import{readEnvVariable as f}from"../../utils/envs/read-env-variable.js";import{sanitizeBranchName as E}from"../../utils/envs/sanitize-branch-name.js";async function l(e){try{return(await p(e??process.cwd()).revparse(["--abbrev-ref","HEAD"])).trim()}catch{return""}}const h=["REDOCLY_EXP_REPLAY_GRAPHQL_ENABLED"];async function N(e){const a=Object.fromEntries(h.map(t=>[t,f(t)]));o.config({path:n.resolve(e??"",".env")}),c();const i=s.PUBLIC_REDOCLY_BRANCH_NAME||await l(e);if(i){const t=E(i);o.config({path:n.resolve(e??"",`.env.branch.${t}`),override:!0}),c()}const v=s.REDOCLY_ENV;let r;switch(v){case"production":r=".env.production";break;case"preview":r=".env.preview";break;default:r=".env.development";break}o.config({path:n.resolve(e??"",r),override:!0}),m(a)}export{N as loadEnvVariables};
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
+
* LEGACY: classic team folders (`teamFolders`, `teamNamePatterns`, `teamFoldersBaseRoles`).
|
|
3
|
+
* One customer uses it. Remove this module and its callers once that customer runs
|
|
4
|
+
* on Realm Plus, which derives team rules from directories instead (`{folder}` rules).
|
|
5
|
+
*
|
|
2
6
|
* (!) We have a copy of this file in the packages/shared, so we need to keep them in sync.
|
|
3
7
|
*/
|
|
4
8
|
import type { RbacConfig, RbacScopeItems } from '@redocly/config';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{getHigherRole as c}from"./rbac.js";function
|
|
1
|
+
import{getHigherRole as c}from"./rbac.js";function R(e,r){if(!e)return;if(!p(e))return e;const o={reunite:{},content:f(e)},n=i(e,r);for(const t of n)o.reunite[t.teamName]=t.projectRole,o.content={...o.content,...Object.fromEntries((e.teamFolders||[]).flatMap(a=>{const l={...e.teamFoldersBaseRoles||{authenticated:"READ"},[t.teamName]:t.projectRole,"redocly.owners":"ADMIN"},m=a.replaceAll("{teamPathSegment}",t.teamPathSegment),s=m+"/**";return[[m,l],[s,l]]}))};return{...e,reunite:{...e.reunite,...o.reunite},content:{...d(e.content||{},o.content)}}}function p(e){return!!(e.teamNamePatterns&&e.teamFolders)}function u(e,r){for(const o of e.teamNamePatterns||[]){if(!o.includes("{teamPathSegment}")&&!o.includes("{projectRole}"))continue;const n="^"+o.replace("{teamPathSegment}","(?<teamPathSegment>[a-zA-Z0-9_.-]+)").replace("{projectRole}","(?<projectRole>admin|maintain|triage|write|read|none)")+"$",a=new RegExp(n,"i").exec(r)?.groups;if(a?.projectRole||a?.teamPathSegment)return{teamName:r,projectRole:a.projectRole?.toUpperCase(),teamPathSegment:a.teamPathSegment?.toLowerCase()}}return null}function g(e,r){for(const o of e?.teamFolders||[]){if(!o.includes("{teamPathSegment}"))continue;const n=`^${o.replace("{teamPathSegment}","(?<teamPathSegment>[a-zA-Z0-9_.-]+)")}($|/)`,t=new RegExp(n,"i");for(const a of r){const l=t.exec(a)?.groups;if(l?.teamPathSegment)return{teamPathSegment:l.teamPathSegment.toLowerCase()}}}return null}function i(e,r){const o=r.map(t=>u(e,t));let n=null;for(const t of o)t?.projectRole&&!t.teamPathSegment&&(n=n?c(n,t.projectRole):t.projectRole);return o.map(t=>!t?.teamPathSegment||!t.projectRole&&!n?null:(t.projectRole=t.projectRole??n??void 0,t)).filter(Boolean)}function f(e){const r={};if(e.teamFoldersBaseRoles)for(const o of e.teamFolders){const n=o.replaceAll("{teamPathSegment}","**");r[n]=e.teamFoldersBaseRoles}return r}function d(e,r){const o={...e};for(const[n,t]of Object.entries(r))o[n]?o[n]={...o[n],...t}:o[n]=t;return o}export{p as canExpandConfig,R as expandRbacConfig,f as getTeamFolderDefaults,g as parseTeamFoldersTemplate,u as parseTeamNameTemplate,i as parseTeams};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import R from"path";import P from"picomatch";import"../node-crypto-polyfill.js";import{REDOCLY_TEAMS_RBAC as x,REDOCLY_ROUTE_RBAC as E}from"@redocly/config";import{MCP_ROUTE as U,PUBLIC_MCP_ROUTE as k}from"@redocly/theme/core/constants/mcp";import{ServerRoutes as w}from"../../constants/api.js";import{DEFAULT_ANONYMOUS_VISITOR_TEAM as D,PUBLIC_RBAC_SCOPE_ITEM as y,RBAC_ALL_OTHER_TEAMS as l,DEFAULT_RBAC_SCOPE as L,GRAPHQL_SPEC_SLUG as M}from"../../constants/common.js";import{DEPRECATED_PUBLIC_API_DEFINITIONS_FOLDER as g,PUBLIC_API_DEFINITIONS_FOLDER as C,PUBLIC_ASSETS_FOLDER as B}from"../constants/common.js";import{MCP_CREDENTIALS_ROUTE as b}from"../constants/mcp.js";import{ANONYMOUS_AUTH_DETAILS as W}from"../constants/rbac.js";import{removeTrailingSlash as T}from"../../utils/url/remove-trailing-slash.js";import{removeLeadingSlash as $}from"../../utils/url/remove-leading-slash.js";import{parsePathVersions as v}from"../../utils/path/parse-path-versions.js";import{reporter as Y}from"../tools/notifiers/reporter.js";import{bold as G}from"../tools/notifiers/helpers/colors.js";import{shaDirPathShort as H}from"../utils/crypto/sha-dir-path-short.js";import{isTruthy as z}from"../../utils/guards/is-truthy.js";import{canExpandConfig as K,expandRbacConfig as V,getTeamFolderDefaults as J,parseTeamFoldersTemplate as Q,parseTeamNameTemplate as X}from"./rbac-expand.js";import{getUserParamsFromCookies as Z}from"../web-server/auth.js";import{getDeeperGlobPattern as q}from"./globs.js";import{EntitlementsProvider as tt}from"../entitlements/entitlements-provider.js";const j=["NONE","READ","TRIAGE","WRITE","MAINTAIN","ADMIN"],et=new Set(["x-parsed-md-description","x-parsed-md-summary"]),rt=new Set(Object.values(w).map(t=>T(t.split(":")[0])));function It(t,e){const r=j.indexOf(t.toUpperCase()),n=j.indexOf(e.toUpperCase());return r>n?t:e}const A={};function I(t,e){if(!t?.content)return y;const r=t.content,{slug:n,fsPath:o}=e;if(!n&&!o)return y;const s=a=>{const d=`slug:${a}`,p=A[d]??P(a);A[d]=p;const _=`fsPath:${a}`,S=A[_]??P($(a));return A[_]=S,!!(n&&p(n))||!!(o&&S(o))};if(st(n||o||"")&&Object.keys(r).filter(p=>s(p)).length===0)return r[L]||y;const f=Object.keys(r).filter(a=>s(a));if(f.length==0)return y;const u=f.map(a=>P.scan(a,{tokens:!0,parts:!0}));let h=u[0];for(let a=1;a<u.length;a++)h=q(h,u[a]);return r[h.input]}function F(t,e,r){const n=r?[...e,r]:e,o=[];for(const s of n)t[s]?o.push(t[s]):t[l]&&s!==r&&o.push(t[l]);return o.some(s=>s.toLowerCase()!=="none")}function Ft(t,e,r={},n=!1){if(n&&Object.keys(r).length===0)return e.isAuthenticated;const o=r.features?.[t];return o?F(o,e.teams):!0}function Nt(t,e){return O(t,W,e.access?.rbac||{},e.access?.requiresLogin||!1)}function O(t,e={},r={},n=!1){if(t.slug&&typeof t.slug=="string"&&rt.has(T(t.slug))||(t.slug===U||t.slug===k||t.slug===b)&&tt.instance().canAccessFeature("mcp"))return!0;if(n&&Object.keys(r).length===0)return!!e.isAuthenticated;const o=V(r,e.teams||[]),s=t[x]||I(o,t[E]||{});return Object.keys(s||{}).length===0?!1:Object.keys(s).length===1&&s[l]&&s[l].toLowerCase()!=="none"?!0:F(s,e?.teams||[],e?.email)}function Ut(t,e,r,n){if(!t.startsWith(C)&&!t.startsWith(g))return!0;const o=t.replace(new RegExp(`^${C}/`),"").replace(new RegExp(`^${g}/`),"").replace(new RegExp(`^${M}/`),""),c=o==="."?"":o,i={[E]:{slug:t,fsPath:c},slug:t};return O(i,n,e,r)}function kt(t,e,r,n,o){if(!t.startsWith(B))return!0;const s=t.match(/\..{64}\.([A-Fa-f0-9]{8})\.[^.]+$/)?.[1];if(!s)return!0;const c=n[s];if(!c)return!0;const{base:i,ext:f}=R.parse(t),u=i.split(".")[0],h=f.split(".").join(""),d=c==="."?"":c,p={[E]:{slug:t,fsPath:R.posix.join(d,`${u}.${h}`)},slug:t};return O(p,o,e,r)}async function wt(t,e){const{isAuthenticated:r=!1,idpAccessToken:n,federatedAccessToken:o,federatedIdToken:s,...c}=await Z(t,e),{teams:i=[]}=c;let f;return r?f=i.filter(u=>u!==D):f=[D],{isAuthenticated:r,idpAccessToken:n,teams:f,claims:c}}function N(t,e,r={},n=!1){if(!t)return t;if(Array.isArray(t)){const o=[];for(const s of t){const c=N(s,e,r,n);c!==void 0&&o.push(c)}return o}if(typeof t=="object"){if(!O(t,e,r,n))return;let o=!1;const s={};for(const c in t){if(c===x||c===E)continue;if(et.has(c)){s[c]=t[c];continue}const i=N(t[c],e,r,n);if(!t.link&&(c==="items"||c==="menu"&&t.type==="tab")&&Array.isArray(i)&&i.length===0&&t[c].length!==0){o=!0;continue}i!==void 0&&(s[c]=i),c==="paths"&&nt(i)&&ot(i)}return o?void 0:s}return t}function Mt(t){return typeof t=="string"?t.split(" ").filter(Boolean):Array.isArray(t)?t.map(e=>e.toString()):[]}function Bt(t,e){if(!e)return;const r=e.content;if(!r)return e;const n=Object.entries(r).flatMap(([s,c])=>s===L?[[s,c]]:[[s,c]].concat(t.localeFolders.map(i=>[s.startsWith("/")?`/${i.toLocaleLowerCase()}${s}`:R.posix.join(t.localizationFolder,i,s),c]))),o=Object.fromEntries(n);return{...e,content:o}}async function bt(t,e){if(!e)return{};const r={},n=new Set(
|
|
1
|
+
import R from"path";import P from"picomatch";import"../node-crypto-polyfill.js";import{REDOCLY_TEAMS_RBAC as x,REDOCLY_ROUTE_RBAC as E}from"@redocly/config";import{MCP_ROUTE as U,PUBLIC_MCP_ROUTE as k}from"@redocly/theme/core/constants/mcp";import{ServerRoutes as w}from"../../constants/api.js";import{DEFAULT_ANONYMOUS_VISITOR_TEAM as D,PUBLIC_RBAC_SCOPE_ITEM as y,RBAC_ALL_OTHER_TEAMS as l,DEFAULT_RBAC_SCOPE as L,GRAPHQL_SPEC_SLUG as M}from"../../constants/common.js";import{DEPRECATED_PUBLIC_API_DEFINITIONS_FOLDER as g,PUBLIC_API_DEFINITIONS_FOLDER as C,PUBLIC_ASSETS_FOLDER as B}from"../constants/common.js";import{MCP_CREDENTIALS_ROUTE as b}from"../constants/mcp.js";import{ANONYMOUS_AUTH_DETAILS as W}from"../constants/rbac.js";import{removeTrailingSlash as T}from"../../utils/url/remove-trailing-slash.js";import{removeLeadingSlash as $}from"../../utils/url/remove-leading-slash.js";import{parsePathVersions as v}from"../../utils/path/parse-path-versions.js";import{reporter as Y}from"../tools/notifiers/reporter.js";import{bold as G}from"../tools/notifiers/helpers/colors.js";import{shaDirPathShort as H}from"../utils/crypto/sha-dir-path-short.js";import{isTruthy as z}from"../../utils/guards/is-truthy.js";import{canExpandConfig as K,expandRbacConfig as V,getTeamFolderDefaults as J,parseTeamFoldersTemplate as Q,parseTeamNameTemplate as X}from"./rbac-expand.js";import{getUserParamsFromCookies as Z}from"../web-server/auth.js";import{getDeeperGlobPattern as q}from"./globs.js";import{EntitlementsProvider as tt}from"../entitlements/entitlements-provider.js";const j=["NONE","READ","TRIAGE","WRITE","MAINTAIN","ADMIN"],et=new Set(["x-parsed-md-description","x-parsed-md-summary"]),rt=new Set(Object.values(w).map(t=>T(t.split(":")[0])));function It(t,e){const r=j.indexOf(t.toUpperCase()),n=j.indexOf(e.toUpperCase());return r>n?t:e}const A={};function I(t,e){if(!t?.content)return y;const r=t.content,{slug:n,fsPath:o}=e;if(!n&&!o)return y;const s=a=>{const d=`slug:${a}`,p=A[d]??P(a);A[d]=p;const _=`fsPath:${a}`,S=A[_]??P($(a));return A[_]=S,!!(n&&p(n))||!!(o&&S(o))};if(st(n||o||"")&&Object.keys(r).filter(p=>s(p)).length===0)return r[L]||y;const f=Object.keys(r).filter(a=>s(a));if(f.length==0)return y;const u=f.map(a=>P.scan(a,{tokens:!0,parts:!0}));let h=u[0];for(let a=1;a<u.length;a++)h=q(h,u[a]);return r[h.input]}function F(t,e,r){const n=r?[...e,r]:e,o=[];for(const s of n)t[s]?o.push(t[s]):t[l]&&s!==r&&o.push(t[l]);return o.some(s=>s.toLowerCase()!=="none")}function Ft(t,e,r={},n=!1){if(n&&Object.keys(r).length===0)return e.isAuthenticated;const o=r.features?.[t];return o?F(o,e.teams):!0}function Nt(t,e){return O(t,W,e.access?.rbac||{},e.access?.requiresLogin||!1)}function O(t,e={},r={},n=!1){if(t.slug&&typeof t.slug=="string"&&rt.has(T(t.slug))||(t.slug===U||t.slug===k||t.slug===b)&&tt.instance().canAccessFeature("mcp"))return!0;if(n&&Object.keys(r).length===0)return!!e.isAuthenticated;const o=V(r,e.teams||[]),s=t[x]||I(o,t[E]||{});return Object.keys(s||{}).length===0?!1:Object.keys(s).length===1&&s[l]&&s[l].toLowerCase()!=="none"?!0:F(s,e?.teams||[],e?.email)}function Ut(t,e,r,n){if(!t.startsWith(C)&&!t.startsWith(g))return!0;const o=t.replace(new RegExp(`^${C}/`),"").replace(new RegExp(`^${g}/`),"").replace(new RegExp(`^${M}/`),""),c=o==="."?"":o,i={[E]:{slug:t,fsPath:c},slug:t};return O(i,n,e,r)}function kt(t,e,r,n,o){if(!t.startsWith(B))return!0;const s=t.match(/\..{64}\.([A-Fa-f0-9]{8})\.[^.]+$/)?.[1];if(!s)return!0;const c=n[s];if(!c)return!0;const{base:i,ext:f}=R.parse(t),u=i.split(".")[0],h=f.split(".").join(""),d=c==="."?"":c,p={[E]:{slug:t,fsPath:R.posix.join(d,`${u}.${h}`)},slug:t};return O(p,o,e,r)}async function wt(t,e){const{isAuthenticated:r=!1,idpAccessToken:n,federatedAccessToken:o,federatedIdToken:s,...c}=await Z(t,e),{teams:i=[]}=c;let f;return r?f=i.filter(u=>u!==D):f=[D],{isAuthenticated:r,idpAccessToken:n,teams:f,claims:c}}function N(t,e,r={},n=!1){if(!t)return t;if(Array.isArray(t)){const o=[];for(const s of t){const c=N(s,e,r,n);c!==void 0&&o.push(c)}return o}if(typeof t=="object"){if(!O(t,e,r,n))return;let o=!1;const s={};for(const c in t){if(c===x||c===E)continue;if(et.has(c)){s[c]=t[c];continue}const i=N(t[c],e,r,n);if(!t.link&&(c==="items"||c==="menu"&&t.type==="tab")&&Array.isArray(i)&&i.length===0&&t[c].length!==0){o=!0;continue}i!==void 0&&(s[c]=i),c==="paths"&&nt(i)&&ot(i)}return o?void 0:s}return t}function Mt(t){return typeof t=="string"?t.split(" ").filter(Boolean):Array.isArray(t)?t.map(e=>e.toString()):[]}function Bt(t,e){if(!e)return;const r=e.content;if(!r)return e;const n=Object.entries(r).flatMap(([s,c])=>s===L?[[s,c]]:[[s,c]].concat(t.localeFolders.map(i=>[s.startsWith("/")?`/${i.toLocaleLowerCase()}${s}`:R.posix.join(t.localizationFolder,i,s),c]))),o=Object.fromEntries(n);return{...e,content:o}}async function bt(t,e){if(!e)return{};const r={},n=new Set(t.scan().flatMap(({relativePath:o})=>{const{versionFolderPath:s}=v(o)||{},c=R.dirname(o);return s?[s,c]:c}));for(const o of n)r[H(o)]=o;return r}const m=t=>typeof t=="object"&&t!==null&&!Array.isArray(t);function nt(t){return m(t)&&Object.keys(t).length>0}function ot(t){for(const e of Object.keys(t)){const r=t[e];m(r)&&Object.keys(r).length===0&&delete t[e]}}function st(t){return t?t.split("/").filter(Boolean).some(r=>r.startsWith(".")):!1}const ct=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},Wt=async t=>{if(t){if(Object.keys(t).length===0)return{};if(ct(t))return it(t);await Y.panicOnContentError(`You are using an incorrect format of ${G("rbac:")} configuration. See: https://redocly.com/docs/realm/access`)}},it=t=>{const e={...t};if(e.content){const r={};for(const n in e.content)if(e.content[n]!==void 0){const o=T(n);r[o]=e.content[n]}e.content=r}return e};function $t(t,e){const r=t.fsPath,n=t.slug,o=[],s=K(e)&&(r||n)?Q(e,[r,n].filter(z)):null;if(s){const i=e?.teamNamePatterns?.map(f=>f.replace("{teamPathSegment}",s.teamPathSegment).replace("{projectRole}","read"))??[];o.push(...i)}const c=I(s?{content:{...J(e),...e.content}}:e,t);return o.push(...at(c)),ft(e,o)}function at(t){if(!t)return[];const e=[],r=l in t?{authenticated:t[l],anonymous:t[l]}:{};for(const[n,o]of Object.entries({...r,...t}))o.toLowerCase()!=="none"&&n!==l&&e.push(n);return e}function ft(t,e){return e.map(n=>X(t,n)??{teamName:n}).map(n=>n.projectRole&&n.projectRole!=="READ"?n.teamName?.toLowerCase().replace(n.projectRole?.toLowerCase?.()??"","read")??"":n.teamName?.toLowerCase()??"")}export{j as PROJECT_ROLES_ORDERED_BY_ACCESS_LEVEL,Bt as applyL10nToRbacConfig,kt as canAccessAsset,Ft as canAccessFeature,O as canAccessResource,Ut as canDownloadApiDefinition,ft as expandTeamsForRead,at as extractTeamsFromScopeItems,N as filterDataByAccessDeep,wt as getAuthDetailsFromCookies,It as getHigherRole,$t as getRbacTeamsListForResource,I as getScopeItemsForResource,F as hasScopeAccess,ct as isRbacConfigValid,Nt as isResourcePubliclyAccessible,it as normalizeRbacConfig,Wt as parseRbacConfig,Mt as parseTeamClaimToArray,bt as resolveDirectoryHashes};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import
|
|
1
|
+
import n from"node:path";import{withPathPrefix as f}from"@redocly/theme/core/utils";import{PUBLIC_STATIC_FOLDER as e}from"../constants/common.js";import{isLocalLink as p}from"../../utils/path/is-local-link.js";import{copyStaticFile as u,FileNotFoundError as x}from"./fs.js";async function w(r,o,i){if(!p(r))return r;const t=r.startsWith("/")?n.posix.join(e,r):void 0;if(t&&o.exists(t))return f(r);const c=r.startsWith("/")?r.slice(1):n.posix.join(n.dirname(i.fromFileRelativePath),r),m=o.exists(c)?o.getFileInfo(c):null;if(!m)throw new x(`Cannot resolve asset path: ${r}`,r);return u(i.contentDir,m.realRelativePath,i.outdir)}export{w as resolveAssetPath};
|
|
@@ -155,7 +155,9 @@ export declare const oidcJwksCache: {
|
|
|
155
155
|
jwks: Record<string, (OidcJwk & {
|
|
156
156
|
idpIds: string[];
|
|
157
157
|
}) | null>;
|
|
158
|
+
missedAt: Record<string, number>;
|
|
158
159
|
};
|
|
160
|
+
export declare const UNKNOWN_KID_RETRY_MS = 60000;
|
|
159
161
|
export declare function getOidcMetadata(idpId: string, providerConfig: OidcProviderConfig): Promise<OidcIssuerMetadata>;
|
|
160
162
|
export declare function discoverJwks(ssoConfig: SsoConfig): Promise<void>;
|
|
161
163
|
export declare function getRedoclyTokenPayload(token: string): Promise<Record<string, unknown>>;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import"../node-crypto-polyfill.js";import{DOMParser as j}from"@xmldom/xmldom";import{SignedXml as Z}from"xml-crypto";import ee from"xpath";import{deflateSync as te,inflateSync as ne}from"fflate";import{createHash as re}from"crypto";import{ulid as oe}from"ulid";import{AuthProviderType as f,DEFAULT_TEAM_CLAIM_NAME as U}from"@redocly/config";import{ALTERNATIVE_AUD_CLAIM_NAME as se,AUTH_URL as ie,JWT_SECRET_KEY as y,MAX_AUTH_TOKEN_COOKIE_BYTES as ae}from"../constants/common.js";import{ensureArray as R}from"../../utils/array/ensure-array.js";import{envConfig as ce}from"../config/env-config.js";import{decryptClaimValue as ue}from"../utils/crypto/decrypt-claim-value.js";import{decryptAesGcm as de}from"../utils/crypto/decrypt-aes-gcm.js";import{encryptAesGcm as le}from"../utils/crypto/encrypt-aes-gcm.js";import{getPathPrefix as me,withPathPrefix as pe,withoutPathPrefix as fe}from"@redocly/theme/core/utils";import{ServerRoutes as
|
|
1
|
+
import"../node-crypto-polyfill.js";import{DOMParser as j}from"@xmldom/xmldom";import{SignedXml as Z}from"xml-crypto";import ee from"xpath";import{deflateSync as te,inflateSync as ne}from"fflate";import{createHash as re}from"crypto";import{ulid as oe}from"ulid";import{AuthProviderType as f,DEFAULT_TEAM_CLAIM_NAME as U}from"@redocly/config";import{ALTERNATIVE_AUD_CLAIM_NAME as se,AUTH_URL as ie,JWT_SECRET_KEY as y,MAX_AUTH_TOKEN_COOKIE_BYTES as ae}from"../constants/common.js";import{ensureArray as R}from"../../utils/array/ensure-array.js";import{envConfig as ce}from"../config/env-config.js";import{decryptClaimValue as ue}from"../utils/crypto/decrypt-claim-value.js";import{decryptAesGcm as de}from"../utils/crypto/decrypt-aes-gcm.js";import{encryptAesGcm as le}from"../utils/crypto/encrypt-aes-gcm.js";import{getPathPrefix as me,withPathPrefix as pe,withoutPathPrefix as fe}from"@redocly/theme/core/utils";import{ServerRoutes as K}from"../../constants/api.js";import{AuthCookieNames as I,DEFAULT_AUTHENTICATED_TEAM as he,REQUIRED_OIDC_SCOPES as V}from"../../constants/common.js";import{appendQueryParams as ye}from"../../utils/url/append-query-params.js";import{parsePreviewUrl as B}from"../../utils/url/parse-preview-url.js";import{logger as O}from"../tools/notifiers/logger.js";import{randomString as Ae}from"../utils/crypto/random-string.js";import{randomUUID as M}from"../utils/crypto/random-uuid.js";import{AlgorithmTypes as l,JwtTokenExpired as _e}from"./jwt/types.js";import*as p from"./jwt/jwt.js";import{InternalTokenTypes as x}from"./jwt/token-types.js";import{parseTeamClaimToArray as we}from"../utils/index.js";import{parseTeamNameTemplate as Se}from"../utils/rbac-expand.js";import{arrayBufferToBase64 as Te,decodeBase64 as $,encodeBase64URL as xe,urlSafeBase64 as F}from"./jwt/encode.js";import{formatSamlCertificate as ge}from"./utils/format-saml-certificate.js";const Ie=new Set(Object.values(x));function g(e){return e?.type===f.OIDC}function Ee(e){return e?.type===f.SAML2}async function Mt(e,t){if(g(t))return ke(e,t);if(Ee(t))return Re(e,t)}async function ke(e,t){const n=await G(e,t),r=new Set((t.scopes||[]).concat(V)),o=t.authorizationRequestCustomParams||{};return{type:f.OIDC,idpId:e,name:"OAuth provider",authorizationEndpoint:n.authorization_endpoint,clientId:t.clientId,responseType:"code",scope:Array.from(r).join(" "),extraParams:o,pkce:t.pkce}}function Re(e,t){return{type:f.SAML2,idpId:e,name:"SAML2 provider",ssoUrl:t.ssoUrl,issuerId:t.issuerId,entityId:t.entityId||t.issuerId}}function H(e){return Array.from(new Set((e.scopes||[]).concat(V))).join(" ")}async function W(e,t,n){return await fetch(e,{method:"POST",body:new URLSearchParams({client_id:t.clientId,...t.clientSecret?{client_secret:t.clientSecret}:{},...n}).toString(),headers:{"Content-Type":"application/x-www-form-urlencoded",Accept:"application/json"}}).then(r=>r.json())}async function Lt(e,t,n,r,o={}){return await W(e,r,{scope:H(r),code:t,redirect_uri:J(n),grant_type:"authorization_code",...o})}async function Nt(e,t,n){return await W(e,n,{scope:H(n),grant_type:"refresh_token",refresh_token:t})}function Oe(e,{authorizationEndpoint:t,clientId:n,responseType:r,scope:o,extraParams:s,idpId:i,pkce:c},d,h,u){if(!t||!n||!r||!o)return{loginUrl:void 0};const a=new URL(t),_=u?.redirectUriOverride??`${e}${pe(K.OIDC_CALLBACK)}`,S={state:M(),idpId:i,redirectUri:_,redirectTo:d,branch:u?.branchOverride??De(e),inviteCode:h,source:u?.sourceOverride??"portal",uiLocales:u?.uiLocales},T={};if(c){const A=F(Ae(50)),E=F(re("sha256").update(A).digest("base64")),k="S256";a.searchParams.append("code_challenge",E),a.searchParams.append("code_challenge_method",k),T.code_verifier={value:A,options:{secure:!0,httpOnly:!0,expires:new Date(Date.now()+1e3*60*10),path:me()||"/"}}}a.searchParams.append("client_id",n),a.searchParams.append("scope",o),a.searchParams.append("response_type",r),a.searchParams.append("redirect_uri",J(_)),a.searchParams.append("state",xe(JSON.stringify(S))),u?.uiLocales&&a.searchParams.append("ui_locales",u.uiLocales);for(const A in s)s[A]!==void 0&&a.searchParams.append(A,s[A]);return{loginUrl:a.toString(),cookies:T}}function Dt(e,t,n,r){const o=new URL(e);return n&&(o.searchParams.append("post_logout_redirect_uri",t),r&&o.searchParams.append("state",r),o.searchParams.append("id_token_hint",n)),o.toString()}function Me(e,t){const n=R(t?.audience??[]);return!n.length||z(e,n)}function z(e,t){const n=[e.aud,e[se]].flat();return t.some(r=>r!==""&&n.includes(r))}function Le(e,t){return!t||!g(t)?!0:Me(e,t)&&Ne(e,t)}function Ne(e,t){return!g(t)||!Ye(t)||!t.clientId?!0:R(e.aud||[]).includes(t.clientId)}function Ct(e){if(!e)return!1;try{return p.decode(e).header.alg===l.RS256}catch{return!1}}async function bt(e){const t=Math.floor(Date.now()/1e3),n=t+(e.ttlSec??600);return p.sign({type:x.MCP_AUTHORIZATION_CODE,client_id:e.clientId,redirect_uri:e.redirectUri,id_token_enc:le(e.idToken,y),...e.idpId?{idp_id:e.idpId}:{},...e.idpAccessTokenEnc?{idp_access_token_enc:e.idpAccessTokenEnc}:{},...e.idpRefreshTokenEnc?{idp_refresh_token_enc:e.idpRefreshTokenEnc}:{},...e.codeChallenge?{code_challenge:e.codeChallenge}:{},...e.codeChallengeMethod?{code_challenge_method:e.codeChallengeMethod}:{},iat:t,exp:n},y,l.HS256)}async function Pt(e){await p.verify(e,y,l.HS256);const{payload:t}=p.decode(e);if(t.type!==x.MCP_AUTHORIZATION_CODE)throw new Error("Invalid authorization code type");if(!t.client_id||!t.redirect_uri)throw new Error("Authorization code missing required claims");if(typeof t.exp=="number"&&Date.now()>=t.exp*1e3)throw new Error("Authorization code expired");if(typeof t.id_token_enc!="string")throw new Error("Authorization code missing session");return{...t,id_token:de(t.id_token_enc,y)}}async function vt(e){const t=Math.floor(Date.now()/1e3);return p.sign({type:x.MCP_REFRESH_TOKEN,client_id:e.clientId,...e.idpId?{idp_id:e.idpId}:{},claims:e.claims,...e.idpAccessTokenEnc?{idp_access_token_enc:e.idpAccessTokenEnc}:{},...e.idpRefreshTokenEnc?{idp_refresh_token_enc:e.idpRefreshTokenEnc}:{},session_exp:e.sessionExp,iat:t,exp:e.sessionExp,jti:M()},y,l.HS256)}async function jt(e){await p.verify(e,y,l.HS256);const{payload:t}=p.decode(e);if(t.type!==x.MCP_REFRESH_TOKEN)throw new Error("Invalid refresh token type");if(!t.client_id||typeof t.claims!="object"||t.claims===null)throw new Error("Refresh token missing required claims");if(typeof t.session_exp!="number")throw new Error("Refresh token missing session expiry");return t}function Ut(e){const t=e||oe(),n=t.startsWith("mcp_")?t:`mcp_${t}`;return{id:n,object:"mcpSession",uri:`urn:redocly:realm:mcp:session:${n}`}}function J(e){const t=B(e);if(!t)return e;const n=Ce(t.hostname);if(n)return t.hostname=`previewauth--${n.previewBranch}${n.after}`,Y(e,t);const r=q(t.hostname);return r?(t.hostname=`${r.projectSlug}.previewauth.${r.after}`,Y(e,t)):e}function De(e){const t=B(e);if(t)return q(t.hostname)?.previewBranch}function Y(e,t){const n=e.replace(/^https?:\/\/[^/?#]+/i,"");return`${t.protocol}//${t.host}${fe(n)}`}function q(e){const t=e.split(".preview.",2);if(t.length<2)return null;const[n,r]=t,o=n.indexOf("--");if(o===-1)return null;const s=n.slice(0,o),i=n.slice(o+2);return!s||!i||i.includes(".")?null:{projectSlug:s,previewBranch:i,after:r}}function Ce(e){const t=e.indexOf("."),n=t===-1?e:e.slice(0,t);if(!n.startsWith("preview-"))return null;const r=n.indexOf("--");if(r===-1)return null;const o=n.slice(r+2);if(!o)return null;const s=t===-1?"":e.slice(t);return{previewBranch:o,after:s}}function be(e){return e.type===f.OIDC}function Pe(e){return e.type===f.SAML2}function Kt(e,t,n,r,o){return be(e)?Oe(t,e,n,r,{uiLocales:o}):Pe(e)?ve(t,e,n,r,o):{}}function ve(e,t,n,r,o){const i=`<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
|
|
2
2
|
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
|
|
3
3
|
Version="2.0"
|
|
4
4
|
ID="_${M()}"
|
|
5
5
|
IssueInstant="${new Date().toISOString()}"
|
|
6
|
-
AssertionConsumerServiceURL="${e}${
|
|
6
|
+
AssertionConsumerServiceURL="${e}${K.SAML_CALLBACK}"
|
|
7
7
|
AttributeConsumingServiceIndex="0">
|
|
8
8
|
<saml:Issuer>${t.entityId}</saml:Issuer>
|
|
9
9
|
<samlp:NameIDPolicy
|
|
10
10
|
AllowCreate="true"
|
|
11
11
|
Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"/>
|
|
12
|
-
</samlp:AuthnRequest>`,c=je(i);return{loginUrl:ye(t.ssoUrl,{SAMLRequest:c,RelayState:JSON.stringify({idpId:t.idpId,redirectTo:n,inviteCode:r,source:"portal",uiLocales:o})})}}function je(e){return Te(te(new TextEncoder().encode(e)).buffer)}function
|
|
12
|
+
</samlp:AuthnRequest>`,c=je(i);return{loginUrl:ye(t.ssoUrl,{SAMLRequest:c,RelayState:JSON.stringify({idpId:t.idpId,redirectTo:n,inviteCode:r,source:"portal",uiLocales:o})})}}function je(e){return Te(te(new TextEncoder().encode(e)).buffer)}function Vt(e){const t=$(e);if(t.startsWith("<samlp:Response")||t.indexOf("<saml2p:Response")>-1)return t;const n=ne(new Uint8Array(atob(e).split("").map(r=>r.charCodeAt(0))));return new TextDecoder().decode(n)}function Bt(e){try{return JSON.parse($(e||""))}catch{throw new Error("Invalid OAuth2 state")}}function $t(e){const t=new j().parseFromString(e,"application/xml"),r=m(t,"//*[local-name(.)='StatusCode']/@Value")[0]?.nodeValue?.endsWith("Success")||!1,s=m(t,"//*[local-name(.)='Response']/@Destination")[0]?.nodeValue||"",i=m(t,"//*[local-name(.)='Assertion']//*[local-name(.)='Issuer']/text()")[0],c=i&&i.nodeValue||void 0,d=m(t,"//*[local-name(.)='Audience']/text()")[0],h=d&&d.nodeValue||void 0,a=m(t,"//*[local-name(.)='Assertion']//*[local-name(.)='X509Certificate']/text()")[0]?.nodeValue||"",_=m(t,"//*[local-name(.)='Subject']//*[local-name(.)='NameID']/text()")[0],S=_&&_.nodeValue||"",T=m(t,"//*[local-name(.)='Subject']//*[local-name(.)='NameID']/@Format")[0],A=T&&T.nodeValue||"",E=m(t,"//*[local-name(.)='Conditions']/@NotOnOrAfter")[0],k=Ue(E),D={},C=m(t,"//*[local-name(.)='AttributeStatement']//*[local-name(.)='Attribute']");if(C.length)for(const b of C){const P=m(b,"./@Name")[0];if(P.nodeValue){const v=m(b,"./*[local-name(.)='AttributeValue']/text()")[0];v?.nodeValue&&(D[P.nodeValue]=v.nodeValue)}}return{uid:S,success:r,expiresAt:k,issuerId:c,entityId:h,attrs:D,cert:a,nameFormat:A,destination:s}}function Ue(e){const t=typeof e?.nodeValue=="string"&&L(Date.parse(e.nodeValue)),n=L(Date.now()),r=L(Date.now()+720*60*1e3);return t?t>n&&t<r?r:t:n}function L(e){return Math.floor(e/1e3)}const N={},w={jwks:{},missedAt:{}},Ke=6e4;function Ve(e){const t=w.jwks[e];return t===void 0?!0:t===null&&Date.now()-(w.missedAt[e]??0)>=Ke}async function G(e,t){if(!N[e]){const n=t.configurationUrl?await Q(t.configurationUrl):t.configuration;N[e]=Be()?Fe(n):n}return N[e]}function Be(){const e=ce.REDOCLY_ENFORCE_RESIDENCY;return!!e&&e.includes("host.docker.internal")}const $e=["authorization_endpoint","end_session_endpoint"];function Fe(e){if(typeof e!="object"||e===null)return e;const t={...e};for(const n of Object.keys(t)){if($e.includes(String(n)))continue;const r=t[n];typeof r=="string"&&r.includes("://localhost")&&(t[n]=r.replace("://localhost","://host.docker.internal"))}return t}const He=["kty","n","e","crv","x","y"];function We(e,t){return He.every(n=>e[n]===t[n])}async function ze(e){const t={};for(const n of Object.keys(e)){const r=e[n];if(!g(r))continue;const o=await G(n,r);if(o.jwks_uri){const s=await Q(o.jwks_uri);for(const i of s.keys){const c=t[i.kid],d=c&&We(c,i)?[...c.idpIds,n]:[n];t[i.kid]={...i,idpIds:d},w.jwks[i.kid]=t[i.kid]}}}}function Je(e,t,n){const r=w.jwks[e]?.idpIds??[];return r.find(o=>{const s=n[o];if(!g(s))return!1;const i=R(s.audience??[]);return z(t,i.length?i:[s.clientId])})??r.at(-1)}async function Q(e){return fetch(e,{headers:{Accept:"application/json"}}).then(t=>t.json())}async function Ft(e){return fetch(`${ie}/oidc/userinfo`,{headers:{Accept:"application/json",Authorization:`Bearer ${e}`}}).then(t=>t.status===200?t.json():void 0).catch(()=>{})}function Ye(e){if(!e.configurationUrl)return!1;const t=new URL(e.configurationUrl);return["localhost","127.0.0.1","blueharvest.cloud","bhstage.cloud","cloud.redocly.com","beta.redocly.com","cloud.eu.redocly.com","beta.eu.redocly.com"].some(r=>qe(t.hostname,r))}function qe(e,t){return e===t||e.endsWith(`.${t}`)}async function Ht(e,t){const n=new j().parseFromString(e,"application/xml"),r=m(n,"//*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']")[0];if(!r)throw new Error("Cannot find Signature in the SAML response");const o=ge(t),s=new Z({publicCert:o});s.loadSignature(r);try{return s.checkSignature(e)}catch{return!1}}function Ge(e){const t=new Set,n=r=>{if(!(!r||typeof r!="object"||Array.isArray(r)))for(const[o,s]of Object.entries(r))typeof s=="string"?t.add(o):n(s)};return n(e),t}function Qe(e,t,n){if(!t)return e;const r=Ge(t),o=s=>{const i=n?.[s]||s;return r.has(i)||!!Se(t,i)};return[...e.filter(o),...e.filter(s=>!o(s))]}async function Wt(e,t,n,r){const o=n?e[n]:void 0,s=Array.isArray(o)?Qe(o.map(String),r?.rbacConfig,r?.teamsMapping):[];let i=s.length;const c=s.length+1;for(let d=0;d<c;d++){const h={...e,idpId:t};n&&s.length&&(h[n]=s.slice(0,i));const u=await p.sign(h,y,l.HS256),a=Buffer.byteLength(u)-ae;if(a<=0)return{token:u,teamsTotal:s.length,teamsKept:i,droppedTeams:s.slice(i)};if(i===0)return null;const _=Buffer.byteLength(JSON.stringify(s.slice(0,i))),S=Math.max(1,_/i*4/3);i=Math.max(0,i-Math.max(1,Math.ceil(a/S)))}return null}function zt(e,t,n,r){t==="urn:oasis:names:tc:SAML:2.0:nameid-format:transient"&&(e=n["http://schemas.microsoft.com/identity/claims/objectidentifier"]);let o;(t==="urn:oasis:names:tc:SAML:2.0:nameid-format:email"||t==="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress")&&(o=e),t==="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"&&e?.match(/^.+@.+/m)&&(o=e);const s=n["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"],i=s?.match(/^.+@.+/m);return o=o||n["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"]||(i?s:void 0),o=o?.toLowerCase(),{sub:e,given_name:n["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname"],family_name:n["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname"],name:n["http://schemas.microsoft.com/identity/claims/displayname"]||s,email:o,email_verified:!0,teams:r?we(n[r]):[]}}function X(e,t={}){return e.map(n=>t[n]||n)}async function Jt(e,t){if(!t)return{};const n=t[I.AUTHORIZATION];if(!n)return{};try{const r=p.decode(n);if(typeof r.payload.type=="string"&&Ie.has(r.payload.type))return{};if(r.header.alg===l.RS256){const h=Ve(r.header.kid);h&&await ze(e);const u=w.jwks[r.header.kid];if(!u)return h&&(w.missedAt[r.header.kid]=Date.now()),w.jwks[r.header.kid]=null,{};await p.verify(n,u,l.RS256)}else await p.verify(n,y,l.HS256);const s=r.header.alg===l.RS256?Je(r.header.kid,r.payload,e):r.payload.idpId,i=e[s]||{};if(r.header.alg===l.RS256&&typeof r.payload.exp!="number")return O.warn("Rejected id_token: it has no exp claim"),{};if(r.header.alg===l.RS256&&!Le(r.payload,i))return O.warn("Rejected id_token: it was issued for another project"),{};const c=et(i),d=Ze(i);return{...r.payload,email:r.payload.email?.toLowerCase(),idpId:s,teams:Array.from(new Set([...X(r.payload.teams||[],d),..."defaultTeams"in i&&i.defaultTeams||[],...X("teamsClaimName"in i&&r.payload[c||""]||[],d),he])),name:Xe(r.payload),isAuthenticated:!0,idpAccessToken:ue(r.payload.idp_access_token,y)||t[I.IDP_ACCESS_TOKEN],federatedAccessToken:t[I.FEDERATED_ACCESS_TOKEN],federatedIdToken:t[I.FEDERATED_ID_TOKEN],authCookie:n}}catch(r){r instanceof _e||O.error("Malformed JWT token: %s",r.message)}return{}}function Xe(e){return(e.firstName&&e.lastName?`${e.firstName} ${e.lastName}`:e.name||e.given_name||e.firstName||e.lastName)||e.email}function Ze(e){switch(e.type){case f.SAML2:return e.teamsAttributeMap;case f.OIDC:return e.teamsClaimMap;default:return}}function et(e){switch(e.type){case f.SAML2:return e.teamsAttributeName??U;case f.OIDC:return e.teamsClaimName;default:return U}}function m(e,t){return ee.select(t,e)||[]}export{Ke as UNKNOWN_KID_RETRY_MS,Kt as buildLoginUrl,Oe as buildOidcLoginUrl,Dt as buildOidcLogoutUrl,ve as buildSAML2LoginUrl,bt as createMcpAuthorizationCode,vt as createMcpRefreshToken,Ut as createMcpSessionResource,Vt as decodeSamlResponse,ze as discoverJwks,je as encodeSAML2,zt as extractUserClaims,Mt as getAuthProviderLoginParams,ke as getOidcLoginParams,G as getOidcMetadata,Ft as getRedoclyTokenPayload,Re as getSaml2LoginParams,Jt as getUserParamsFromCookies,Xe as getUsernameFromPayload,Me as idTokenAudienceIsAllowed,Le as idTokenIsForThisProject,Ct as isIdpIssuedToken,g as isOidcProviderConfig,Ye as isRedoclySso,Ee as isSaml2ProviderConfig,Lt as oidcExchangeCodeForToken,w as oidcJwksCache,N as oidcMetadataCache,Nt as oidcRefreshTokenGrant,Qe as orderTeamsRbacFirst,Bt as parseOidcState,De as parsePreviewBranch,$t as parseSamlResponse,J as rewritePreviewAuthRedirectUri,Wt as signTokenWithinCookieSizeLimit,Pt as verifyMcpAuthorizationCode,jt as verifyMcpRefreshToken,Ht as verifySAMLResponse};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import"../../node-crypto-polyfill.js";import{timingSafeEqual as H}from"node:crypto";import{utf8ToUint8Array as u,encodeBase64URL as m,arrayBufferToBase64URL as w,decodeBase64URL as S}from"./encode.js";import{decodeJwtSignature as b}from"./decode-jwt-signature.js";import{AlgorithmTypes as s,JwtAlgorithmNotImplemented as E,JwtTokenInvalid as d,JwtTokenNotBefore as K,JwtTokenExpired as T,JwtTokenSignatureMismatched as B,CryptoKeyFormat as h,CryptoKeyUsage as l}from"./types.js";const p=e=>{switch(e.toUpperCase()){case"HS256":return{name:"HMAC",hash:{name:"SHA-256"}};case"HS384":return{name:"HMAC",hash:{name:"SHA-384"}};case"HS512":return{name:"HMAC",hash:{name:"SHA-512"}};case"RS256":return{name:"RSASSA-PKCS1-v1_5",hash:{name:"SHA-256"}};case"ES256":return{name:"ECDSA",namedCurve:"P-256",hash:{name:"SHA-256"}};default:throw new E(e)}},g=async(e,t,n=s.HS256)=>{if(!crypto.subtle||!crypto.subtle.importKey)throw new Error("`crypto.subtle.importKey` is undefined. JWT auth middleware requires it.");t.startsWith("-----BEGIN PRIVATE KEY-----")&&(t=t.replace("-----BEGIN PRIVATE KEY-----","").replace("-----END PRIVATE KEY-----","").split(/\\n|\n/).join("").trim(),t=atob(t));const r=n===s.RS256||n===s.ES256,o=await crypto.subtle.importKey(r?h.PKCS8:h.RAW,r?C(t):u(t),p(n),!1,[l.Sign]);return await crypto.subtle.sign(p(n),o,u(e))};function C(e){const t=new ArrayBuffer(e.length),n=new Uint8Array(t);for(let r=0,o=e.length;r<o;r++)n[r]=e.charCodeAt(r);return t}const V=async(e,t,n=s.HS256,r)=>{const o=
|
|
1
|
+
import"../../node-crypto-polyfill.js";import{timingSafeEqual as H}from"node:crypto";import{utf8ToUint8Array as u,encodeBase64URL as m,arrayBufferToBase64URL as w,decodeBase64URL as S}from"./encode.js";import{decodeJwtSignature as b}from"./decode-jwt-signature.js";import{AlgorithmTypes as s,JwtAlgorithmNotImplemented as E,JwtTokenInvalid as d,JwtTokenNotBefore as K,JwtTokenExpired as T,JwtTokenSignatureMismatched as B,CryptoKeyFormat as h,CryptoKeyUsage as l}from"./types.js";const p=e=>{switch(e.toUpperCase()){case"HS256":return{name:"HMAC",hash:{name:"SHA-256"}};case"HS384":return{name:"HMAC",hash:{name:"SHA-384"}};case"HS512":return{name:"HMAC",hash:{name:"SHA-512"}};case"RS256":return{name:"RSASSA-PKCS1-v1_5",hash:{name:"SHA-256"}};case"ES256":return{name:"ECDSA",namedCurve:"P-256",hash:{name:"SHA-256"}};default:throw new E(e)}},g=async(e,t,n=s.HS256)=>{if(!crypto.subtle||!crypto.subtle.importKey)throw new Error("`crypto.subtle.importKey` is undefined. JWT auth middleware requires it.");t.startsWith("-----BEGIN PRIVATE KEY-----")&&(t=t.replace("-----BEGIN PRIVATE KEY-----","").replace("-----END PRIVATE KEY-----","").split(/\\n|\n/).join("").trim(),t=atob(t));const r=n===s.RS256||n===s.ES256,o=await crypto.subtle.importKey(r?h.PKCS8:h.RAW,r?C(t):u(t),p(n),!1,[l.Sign]);return await crypto.subtle.sign(p(n),o,u(e))};function C(e){const t=new ArrayBuffer(e.length),n=new Uint8Array(t);for(let r=0,o=e.length;r<o;r++)n[r]=e.charCodeAt(r);return t}const V=async(e,t,n=s.HS256,r)=>{const o=m(JSON.stringify(e)),i=`${m(JSON.stringify({alg:n,typ:"JWT",kid:r}))}.${o}`,c=await w(await g(i,t,n));return`${i}.${c}`},k=async(e,t,n=s.HS256,r=!1)=>{const o=e.split(".");if(o.length!==3)throw new d;const{payload:a}=J(e),i=Math.floor(Date.now()/1e3);if(typeof a.nbf=="number"&&a.nbf>i)throw new K;if(!r&&typeof a.exp=="number"&&a.exp<=i)throw new T;const c=o.slice(0,2).join("."),y=o[2];let f=!1;if(typeof t!="string")f=await N(c,y,t,n);else{const A=await w(await g(c,t,n));f=R(A,y)}if(!f)throw new B;return!0};function R(e,t){const n=Buffer.from(e),r=Buffer.from(t);return n.length===r.length&&H(n,r)}const J=e=>{try{const[t,n]=e.split("."),r=JSON.parse(S(t)),o=JSON.parse(S(n));return{header:r,payload:o}}catch{throw new d}},N=async(e,t,n,r)=>{const o=await crypto.subtle.importKey("jwk",n,p(r),!1,[l.Verify]);return await crypto.subtle.verify(p(r),o,b(t),u(e))};export{J as decode,V as sign,k as verify};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{KvService as
|
|
1
|
+
import{KvService as A}from"../../persistence/kv/services/kv-service.js";import{DEFAULT_AUTHENTICATED_TEAM as h}from"../../../constants/common.js";import{envConfig as c}from"../../config/env-config.js";import{fetchWithClient as l}from"../../utils/fetch-with-client.js";import{CACHE_CONTROL_NO_STORE_HEADER_VALUE as y,JWT_SECRET_KEY as T}from"../../constants/common.js";import*as m from"../jwt/jwt.js";import{AlgorithmTypes as f}from"../jwt/types.js";const p=60,I=e=>["POST","PUT","DELETE","PATCH"].includes(e),E=e=>["GET"].includes(e);function O({serverOutDir:e,protectReadMethods:t=!0}){return async(a,r)=>await _(a,r,e,t)}const _=async(e,t,a,r=!0)=>{e.header("Cache-Control",y);const n=e.req.method,i=I(n)||E(n)&&r,o=e.req.header("apiKey");if(o)return await w(e,t,o,a);const s=e.req.header("authorization")?.replace("Bearer ","");return s?await C(e,t,s):i?e.json({message:"API key is required"},401):await t()},w=async(e,t,a,r)=>{if(!c.BH_API_URL||!c.ORGANIZATION_ID)return e.json({message:"API key validation service not configured"},500);try{const n=await A.getInstance({baseDbDir:r}),i=await g(n,a);if(i)return e.set("apiKeyTeams",i.teams),await t();const o=new URL(`/api/orgs/${c.ORGANIZATION_ID}/session`,c.BH_API_URL).toString(),u=await l(o,{method:"GET",headers:{Authorization:`Bearer ${a}`}});if(!u.ok)return e.json({message:"Invalid API key"},401);const s=await u.json(),d=[h,...s.teams];return e.set("apiKeyTeams",d),await n.set(["api-keys","reunite",a],{valid:!0,teams:d},{ttlInSeconds:p}),await t()}catch{return e.json({message:"API key validation failed"},400)}},C=async(e,t,a)=>{try{const r=await m.verify(a,T,f.HS256),n=m.decode(a).payload.isInternalConnection;return!r||!n?e.json({message:"API key is required"},401):await t()}catch{return e.json({message:"API key validation failed"},400)}},g=async(e,t)=>{try{return await e.get(["api-keys","reunite",t])}catch{return null}};export{O as catalogAuthMiddleware};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{combineUrls as
|
|
1
|
+
import{combineUrls as O,withPathPrefix as h}from"@redocly/theme/core/utils";import{DEFAULT_DOCS_MCP_SERVER_NAME as M,MCP_PROTOCOL_VERSION as R}from"../../../plugins/mcp/constants.js";import{RESERVED_ROUTES as L}from"../../../plugins/get-reserved-routes.js";import{isMcpCodeModeEnabled as y}from"../../../plugins/mcp/utils/mode.js";import{CODE_MODE_TOOL_NAMES as A,EXECUTE_TOOL_NAME as D,FETCH_TOOL_NAME as U}from"../../../plugins/mcp/codemode/constants.js";import{EXECUTE_TOOL_SCHEMA as I,executeToolTitle as P}from"../../../plugins/mcp/codemode/tools/execute-schema.js";import{describeToolsSchema as x}from"../../../plugins/mcp/codemode/tools/describe-tools.js";import{normalizeToolDisplayName as V}from"../../../plugins/mcp/utils/tool-registration.js";import{buildCodeModeInstructions as H,buildExecuteDescription as N}from"../../../plugins/mcp/codemode/prompts.js";import{toToolListEntries as w}from"../../../plugins/mcp/codemode/build-tool-list.js";import{composeExecuteAnnotations as q}from"../../../plugins/mcp/codemode/capabilities/index.js";import{ALL_CAPABILITIES as j}from"../../../plugins/mcp/codemode/capabilities/registry.js";import{isGatewayCapabilityEnabled as k}from"../../../plugins/mcp/gateway-mcp/eligibility.js";import{shouldHandleMcpAuth as B}from"../../../utils/rbac/should-handle-mcp-auth.js";import{resolvePublicBaseUrl as F}from"../../../web-server/utils/resolve-public-base-url.js";import{getRequestOrigin as G}from"../../../web-server/utils/get-request-origin.js";import{resolveDocsSiteUrl as X}from"../../../plugins/mcp/utils/docs-site-url.js";import{telemetryTraceStep as z}from"../../../telemetry/helpers/trace-step.js";import{MCP_AUTH_SCHEMES as $}from"./constants.js";const J="https://static.modelcontextprotocol.io/schemas/mcp-server-card/v1.json",K="1.0";function fe(r){const s=y(),T=new Date().toISOString().slice(0,10);return async n=>await z("com.redocly.mcpServerCard.served",async t=>{t?.setAttribute("id","mcpServerCardId"),t?.setAttribute("object","mcpServerCard"),t?.setAttribute("uri","urn:redocly:realm:api:mcpServerCard:mcpServerCardId");const o=r.getConfig(),a=o.mcp?.docs?.name||M,l=r.getMcpTools().filter(e=>e.name!==D),m=l.filter(e=>!e.hasAvailabilityGate),d=l.filter(e=>!A.has(e.name)),p=d.filter(e=>!e.hasAvailabilityGate),i=k(o.mcp)?[...j]:[],u=i.some(e=>e.id===U),E=w(p,i),C=q(d,i,o.mcp),c=(s?[{...I,title:P(C),description:N(u,E,X(o.seo?.siteUrl,G(n))),annotations:C},x(p,i),...m.filter(e=>A.has(e.name))]:m).map(V).map(({name:e,title:b,description:S,schema:g,annotations:v})=>({name:e,title:b,description:S,inputSchema:g,annotations:v})),_=o.skills?.hide===!0?[]:r.getSkills(),f={$schema:J,version:K,protocolVersion:R,serverInfo:{name:a,title:a,version:T},description:o.seo?.description,documentationUrl:O(F(r,n),h("/")),transport:{type:"streamable-http",endpoint:h(L.mcp)},capabilities:{logging:{},tools:{listChanged:!0},..._.length>0?{resources:{listChanged:!0},completions:{}}:{}},authentication:B(!!o.access?.requiresLogin,o.access?.rbac)?{required:!0,schemes:$}:void 0,instructions:s?H(u,E):void 0,tools:c.length>0?c:["dynamic"]};return t?.setAttribute("mode",s?"code":"tools"),t?.setAttribute("toolsCount",c.length),t?.setAttribute("authRequired",f.authentication!==void 0),n.json(f,200,{"Access-Control-Allow-Origin":"*","Cache-Control":"public, max-age=3600"})})}export{fe as mcpServerCardHandler};
|
|
@@ -43,9 +43,10 @@ export type PlanGates = {
|
|
|
43
43
|
[FEATURE.mcpRequestRatePerMin]: number;
|
|
44
44
|
[FEATURE.mcpRequestQuotaPerDay]: number;
|
|
45
45
|
[FEATURE.cookieConsent]: boolean;
|
|
46
|
+
[FEATURE.sdkGeneration]: boolean;
|
|
46
47
|
};
|
|
47
48
|
export type Entitlements = {
|
|
48
49
|
[key in Feature]: boolean | number | string;
|
|
49
50
|
};
|
|
50
|
-
export type
|
|
51
|
+
export type PricingTier = 'pro' | 'scale' | 'enterprise';
|
|
51
52
|
//# sourceMappingURL=entitlements.d.ts.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builds a developer onboarding API path under the configured path prefix.
|
|
3
|
+
*
|
|
4
|
+
* @param path - The path relative to the api-keys API base (e.g., "/meta", "/apps/:id").
|
|
5
|
+
* @returns The api-keys API path, prefixed with `REDOCLY_PREFIX_PATHS` when it is set.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* apiKeysUrl('/apps/my-app'); // "/api/api-keys/apps/my-app" (or "/prefix/api/api-keys/apps/my-app")
|
|
9
|
+
*/
|
|
10
|
+
export declare function apiKeysUrl(path: string): string;
|
|
11
|
+
//# sourceMappingURL=api-keys-url.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{withPathPrefix as r}from"@redocly/theme/core/utils";function e(i){return r(`/api/api-keys${i}`)}export{e as apiKeysUrl};
|