@redocly/realm 0.134.0 → 0.135.0-next.1
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 +37 -0
- package/dist/client/app/Link.d.ts +1 -1
- package/dist/client/app/Link.js +1 -1
- package/dist/client/app/Sidebar/RequestAccessButton.js +2 -2
- package/dist/client/app/hooks/useLoginUrl.js +1 -1
- package/dist/client/app/hooks/useScrollTracker.js +1 -1
- package/dist/client/app/markdoc/custom-components/openapi/json-schema.d.ts +1 -0
- package/dist/client/app/markdoc/custom-components/openapi/json-schema.js +1 -1
- package/dist/client/app/search/useAiSearch.js +1 -1
- package/dist/client/app/utils/programmatic-scroll.d.ts +22 -0
- package/dist/client/app/utils/programmatic-scroll.js +1 -0
- package/dist/markdoc/helpers/get-inner-text.js +2 -2
- package/dist/markdoc/tags/json-schema.js +1 -1
- package/dist/server/constants/common.d.ts +4 -1
- package/dist/server/constants/common.js +1 -1
- package/dist/server/plugins/catalog-entities/database/remote-publish-lock-service.js +1 -1
- package/dist/server/plugins/graphql-docs/graphql-doc-loader.d.ts +5 -0
- package/dist/server/plugins/graphql-docs/graphql-doc-loader.js +1 -1
- package/dist/server/plugins/graphql-docs/index.js +1 -1
- package/dist/server/plugins/markdown/search/to-markdown.js +14 -14
- package/dist/server/plugins/mcp/docs-mcp/tool-schemas.d.ts +1 -0
- package/dist/server/plugins/mcp/docs-mcp/tool-schemas.js +1 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/core/search.d.ts +6 -0
- package/dist/server/plugins/mcp/docs-mcp/tools/core/search.js +6 -0
- package/dist/server/plugins/mcp/docs-mcp/tools/core/utils.d.ts +3 -0
- package/dist/server/plugins/mcp/docs-mcp/tools/core/utils.js +11 -0
- package/dist/server/plugins/mcp/docs-mcp/tools/core/whoami.d.ts +6 -0
- package/dist/server/plugins/mcp/docs-mcp/tools/graphql/get-graphql-schema.d.ts +8 -0
- package/dist/server/plugins/mcp/docs-mcp/tools/graphql/get-graphql-schema.js +3 -0
- package/dist/server/plugins/mcp/docs-mcp/tools/graphql/get-graphql-type-list.d.ts +14 -0
- package/dist/server/plugins/mcp/docs-mcp/tools/graphql/get-graphql-type-list.js +1 -0
- package/dist/server/plugins/mcp/docs-mcp/tools/graphql/get-graphql-type.d.ts +10 -0
- package/dist/server/plugins/mcp/docs-mcp/tools/graphql/get-graphql-type.js +7 -0
- package/dist/server/plugins/mcp/docs-mcp/tools/graphql/list-graphql-apis.d.ts +10 -0
- package/dist/server/plugins/mcp/docs-mcp/tools/graphql/list-graphql-apis.js +1 -0
- package/dist/server/plugins/mcp/docs-mcp/tools/graphql/load-graphql-schema.d.ts +7 -0
- package/dist/server/plugins/mcp/docs-mcp/tools/graphql/load-graphql-schema.js +1 -0
- package/dist/server/plugins/mcp/docs-mcp/tools/graphql/tool-helpers.d.ts +14 -0
- package/dist/server/plugins/mcp/docs-mcp/tools/graphql/tool-helpers.js +1 -0
- package/dist/server/plugins/mcp/docs-mcp/tools/graphql/types.d.ts +10 -0
- package/dist/server/plugins/mcp/docs-mcp/tools/graphql/types.js +1 -0
- package/dist/server/plugins/mcp/docs-mcp/tools/graphql/utils.d.ts +16 -0
- package/dist/server/plugins/mcp/docs-mcp/tools/graphql/utils.js +3 -0
- package/dist/server/plugins/mcp/docs-mcp/tools/index.d.ts +28 -7
- package/dist/server/plugins/mcp/docs-mcp/tools/index.js +1 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/{get-endpoint-info.d.ts → openapi/get-endpoint-info.d.ts} +1 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/openapi/get-endpoint-info.js +1 -0
- package/dist/server/plugins/mcp/docs-mcp/tools/{get-endpoints.d.ts → openapi/get-endpoints.d.ts} +1 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/openapi/get-endpoints.js +1 -0
- package/dist/server/plugins/mcp/docs-mcp/tools/{get-full-api-description.d.ts → openapi/get-full-api-description.d.ts} +1 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/openapi/get-full-api-description.js +1 -0
- package/dist/server/plugins/mcp/docs-mcp/tools/{get-security-schemes.d.ts → openapi/get-security-schemes.d.ts} +1 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/openapi/get-security-schemes.js +1 -0
- package/dist/server/plugins/mcp/docs-mcp/tools/{list-apis.d.ts → openapi/list-apis.d.ts} +1 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/openapi/list-apis.js +1 -0
- package/dist/server/plugins/mcp/docs-mcp/tools/openapi/load-api-description.js +1 -0
- package/dist/server/plugins/mcp/docs-mcp/tools/{utils.d.ts → openapi/utils.d.ts} +1 -3
- package/dist/server/plugins/mcp/docs-mcp/tools/openapi/utils.js +1 -0
- package/dist/server/plugins/mcp/handlers/docs-mcp-handler.js +1 -1
- package/dist/server/plugins/mcp/index.js +1 -1
- package/dist/server/plugins/mcp/servers/docs-server.js +1 -1
- package/dist/server/plugins/mcp/types.d.ts +7 -0
- package/dist/server/plugins/mcp/utils.d.ts +7 -17
- package/dist/server/plugins/mcp/utils.js +1 -1
- package/dist/server/store.d.ts +2 -0
- package/dist/server/store.js +1 -1
- package/dist/server/types/plugins/common.d.ts +2 -0
- package/dist/server/web-server/middleware/catalogAuthMiddleware.js +1 -1
- package/dist/server/web-server/routes/api-routes/api-routes.d.ts +0 -5
- package/dist/server/web-server/routes/api-routes/api-routes.js +1 -1
- package/dist/server/web-server/routes/app-data.js +1 -1
- package/dist/server/web-server/routes/dynamic-route.js +1 -1
- package/dist/server/web-server/routes/page-data.js +1 -1
- package/dist/server/web-server/routes/search.js +1 -1
- package/dist/server/web-server/utils.js +1 -1
- package/package.json +8 -8
- package/dist/server/plugins/mcp/docs-mcp/tools/get-endpoint-info.js +0 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/get-endpoints.js +0 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/get-full-api-description.js +0 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/get-security-schemes.js +0 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/helpers/load-api-description.js +0 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/list-apis.js +0 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/search.d.ts +0 -6
- package/dist/server/plugins/mcp/docs-mcp/tools/search.js +0 -6
- package/dist/server/plugins/mcp/docs-mcp/tools/utils.js +0 -11
- package/dist/server/plugins/mcp/docs-mcp/tools/whoami.d.ts +0 -6
- /package/dist/server/plugins/mcp/docs-mcp/tools/{whoami.js → core/whoami.js} +0 -0
- /package/dist/server/plugins/mcp/docs-mcp/tools/{helpers → openapi}/load-api-description.d.ts +0 -0
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import{getNamedType as p,isEnumType as v,isInputObjectType as y,isInterfaceType as g,isIntrospectionType as u,isObjectType as T,isScalarType as m,isSpecifiedScalarType as S,isUnionType as b,print as c,printType as N,specifiedDirectives as O}from"graphql";const j=new Set(["queries","mutations","subscriptions"]);function C(e,r){const t=r.toLowerCase();return e.find(i=>i.name.toLowerCase().includes(t))}function a(e,r){return e.getQueryType()?.getFields()[r]??e.getMutationType()?.getFields()[r]??e.getSubscriptionType()?.getFields()[r]}function w(e){return[p(e.type).name,...e.args.map(r=>p(r.type).name)]}function d(e){const r=new Set;if(T(e)||g(e)){for(const t of Object.values(e.getFields())){r.add(p(t.type).name);for(const i of t.args)r.add(p(i.type).name)}for(const t of e.getInterfaces())r.add(t.name)}else if(b(e))for(const t of e.getTypes())r.add(t.name);else if(y(e))for(const t of Object.values(e.getFields()))r.add(p(t.type).name);return r}function $(e){const r=new Set([e.getQueryType(),e.getMutationType(),e.getSubscriptionType()].filter(n=>!!n).map(n=>n.name)),t={queries:l(e.getQueryType()),mutations:l(e.getMutationType()),subscriptions:l(e.getSubscriptionType()),objects:[],interfaces:[],unions:[],enums:[],inputs:[],scalars:[],directives:[]};for(const n of Object.values(e.getTypeMap())){if(u(n)||r.has(n.name))continue;const o={name:n.name,description:n.description??void 0};m(n)?S(n)||t.scalars.push(o):T(n)?t.objects.push(o):g(n)?t.interfaces.push(o):b(n)?t.unions.push(o):v(n)?t.enums.push(o):y(n)&&t.inputs.push(o)}const i=new Set(O.map(n=>n.name));return t.directives=e.getDirectives().filter(n=>!i.has(n.name)).map(n=>({name:n.name,description:n.description??void 0})),t}function l(e){return e?Object.values(e.getFields()).map(r=>({name:r.name,description:r.description??void 0,type:r.type.toString(),args:r.args.length?`(${r.args.map(t=>{const i=t.astNode?.defaultValue?` = ${c(t.astNode.defaultValue)}`:"";return`${t.name}: ${t.type}${i}`}).join(", ")})`:void 0})):[]}function q(e,r,t){const i=h(e,t);if(!i)return[];const n=new Set([i,...x(e,i)]);return r.filter(o=>{if(!j.has(o.kind))return n.has(o.name);const s=a(e,o.name);return s?w(s).some(f=>n.has(f)):!1})}function F(e,r){const t=new Set,i=[...M(e,r)];for(let n=0;n<i.length;n+=1){const o=i[n];if(t.has(o))continue;t.add(o);const s=e.getType(o);if(s)for(const f of d(s))t.has(f)||i.push(f)}return[...t].filter(n=>n!==r&&D(e,n))}function M(e,r){const t=e.getType(r);if(t)return d(t);const i=a(e,r);if(i)return new Set(w(i));const n=e.getDirective(r);return n?new Set(n.args.map(o=>p(o.type).name)):new Set}function x(e,r){const t=new Map;for(const o of Object.values(e.getTypeMap()))if(!u(o))for(const s of d(o)){let f=t.get(s);f||(f=new Set,t.set(s,f)),f.add(o.name)}const i=new Set,n=[r];for(let o=0;o<n.length;o+=1)for(const s of t.get(n[o])??[])i.has(s)||(i.add(s),n.push(s));return i}function h(e,r){const t=r.toLowerCase();return Object.keys(e.getTypeMap()).find(i=>i.toLowerCase()===t)}function D(e,r){const t=e.getType(r);return!t||u(t)?!1:!(m(t)&&S(t))}function I(e,r){const t=e.getType(r);if(t)return N(t);const i=a(e,r);if(i?.astNode)return c(i.astNode);const n=e.getDirective(r);if(n?.astNode)return c(n.astNode);throw new Error(`No GraphQL type, operation, or directive named "${r}" found.`)}function L(e,r){const t=I(e,r),i=F(e,r).map(n=>e.getType(n)).filter(n=>!!n).map(n=>N(n));return{sdl:[t,...i].join(`
|
|
2
|
+
|
|
3
|
+
`),referencedCount:i.length}}export{q as filterMembersReferencingType,C as findGraphqlSchemaByName,$ as groupSchemaTypes,I as printTypeOrField,L as printTypeOrFieldWithReferences,F as referencedTypeClosure};
|
|
@@ -1,11 +1,20 @@
|
|
|
1
1
|
declare const _default: {
|
|
2
|
+
'list-apis': import("../../types.js").McpToolHandler<{
|
|
3
|
+
filter?: string;
|
|
4
|
+
page?: number;
|
|
5
|
+
limit?: number;
|
|
6
|
+
}>;
|
|
7
|
+
'get-endpoints': import("../../types.js").McpToolHandler<{
|
|
8
|
+
name: string;
|
|
9
|
+
version?: string;
|
|
10
|
+
}>;
|
|
2
11
|
'get-endpoint-info': import("../../types.js").McpToolHandler<{
|
|
3
12
|
name: string;
|
|
4
13
|
path: string;
|
|
5
14
|
method: string;
|
|
6
15
|
version?: string;
|
|
7
16
|
}>;
|
|
8
|
-
'get-
|
|
17
|
+
'get-security-schemes': import("../../types.js").McpToolHandler<{
|
|
9
18
|
name: string;
|
|
10
19
|
version?: string;
|
|
11
20
|
}>;
|
|
@@ -13,17 +22,29 @@ declare const _default: {
|
|
|
13
22
|
name: string;
|
|
14
23
|
version?: string;
|
|
15
24
|
}>;
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
25
|
+
search: import("../../types.js").McpToolHandler;
|
|
26
|
+
whoami: import("../../types.js").McpToolHandler;
|
|
27
|
+
'list-graphql-apis': import("../../types.js").McpToolHandler<{
|
|
28
|
+
filter?: string;
|
|
29
|
+
page?: number;
|
|
30
|
+
limit?: number;
|
|
19
31
|
}>;
|
|
20
|
-
'list
|
|
32
|
+
'get-graphql-type-list': import("../../types.js").McpToolHandler<{
|
|
33
|
+
name: string;
|
|
34
|
+
kind?: import("./graphql/types.js").GraphqlTypeKind;
|
|
21
35
|
filter?: string;
|
|
36
|
+
referencesType?: string;
|
|
22
37
|
page?: number;
|
|
23
38
|
limit?: number;
|
|
24
39
|
}>;
|
|
25
|
-
|
|
26
|
-
|
|
40
|
+
'get-graphql-type': import("../../types.js").McpToolHandler<{
|
|
41
|
+
name: string;
|
|
42
|
+
type: string;
|
|
43
|
+
includeReferencedTypes?: boolean;
|
|
44
|
+
}>;
|
|
45
|
+
'get-graphql-schema': import("../../types.js").McpToolHandler<{
|
|
46
|
+
name: string;
|
|
47
|
+
}>;
|
|
27
48
|
};
|
|
28
49
|
export default _default;
|
|
29
50
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import
|
|
1
|
+
import r from"./openapi/list-apis.js";import o from"./openapi/get-endpoints.js";import t from"./openapi/get-endpoint-info.js";import m from"./openapi/get-security-schemes.js";import p from"./openapi/get-full-api-description.js";import i from"./core/search.js";import e from"./core/whoami.js";import f from"./graphql/list-graphql-apis.js";import l from"./graphql/get-graphql-type-list.js";import s from"./graphql/get-graphql-type.js";import a from"./graphql/get-graphql-schema.js";var E={...r,...o,...t,...m,...p,...i,...e,...f,...l,...s,...a};export{E as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{resolveParameters as h,resolveRequestBody as v,resolveResponses as x}from"../../utils.js";import{isMcpEndpoint as E}from"./utils.js";import{loadApiDescription as g}from"./load-api-description.js";import{checkEndpointAndDeleteXMcp as P}from"../../../utils/xmcp-utils.js";const S=async(s,i)=>{const{name:p,path:o,method:n,version:a}=s;let t;try{t=await g(p,i,a)}catch(y){return{content:[{type:"text",text:y.message}],isError:!0}}const c=o.startsWith("/")?o:`/${o}`,{title:d=""}=t.info||{},r=t.paths?.[c],m=n.toLowerCase();if(!r)return{content:[{type:"text",text:"Endpoint not found"}],isError:!0};const e=r[m];if(!E(e)||!P(e,"docs"))return{content:[{type:"text",text:"Endpoint not found"}],isError:!0};const u=r?.parameters||[],l=e.parameters||[],f={...e,parameters:h({pathParams:u,opParams:l,definition:t}),requestBody:v(e.requestBody,t),responses:x(e.responses,t)};return{content:[{type:"text",text:JSON.stringify({api:d,version:t.info?.version||"",servers:t.servers||[],endpoint:{path:o,method:n.toUpperCase(),...f},globalSecurity:t.security||[],securitySchemes:t.components?.securitySchemes||[]},null,2)}]}};var M={"get-endpoint-info":S};export{M as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{loadApiDescription as p}from"./load-api-description.js";import{getEndpointsFromPaths as c}from"./utils.js";const a=async(n,r)=>{const{name:o,version:i}=n;let t;try{t=await p(o,r,i)}catch(s){return{content:[{type:"text",text:s.message}],isError:!0}}const e=c(t);return e.length===0?{content:[{type:"text",text:"No endpoints found"}]}:{content:[{type:"text",text:JSON.stringify({api:t.info?.title||"",version:t.info?.version||"",servers:t.servers||[],endpoints:e},null,2)}]}};var l={"get-endpoints":a};export{l as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{loadApiDescription as s}from"./load-api-description.js";const p=async(e,i)=>{const{name:n,version:r}=e;let t;try{t=await s(n,i,r)}catch(o){return{content:[{type:"text",text:o.message}],isError:!0}}return{content:[{type:"text",text:JSON.stringify({api:t.info?.title||"",version:t.info?.version||"",definition:t},null,2)}]}};var a={"get-full-api-description":p};export{a as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{loadApiDescription as c}from"./load-api-description.js";const o=async(t,r)=>{const{name:s,version:i}=t;let e;try{e=await c(s,r,i)}catch(n){return{content:[{type:"text",text:n.message}],isError:!0}}return{content:[{type:"text",text:JSON.stringify({name:e.info?.title,version:e.info?.version,securitySchemes:e.components?.securitySchemes||[],security:e.security||[]},null,2)}]}};var y={"get-security-schemes":o};export{y as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{filterApiDescriptionsByName as f}from"../../utils.js";const x=async(a,l)=>{const{filter:i,page:n=1,limit:e=300}=a;let t=Object.values(l.apiDescriptionsMap);i&&(t=f(t,i));const s=(n-1)*e,o=s+e,r=Math.ceil(t.length/e),c=t.length;return t=t.slice(s,o),t.length===0?{content:[{type:"text",text:"No APIs available"}]}:{content:[{type:"text",text:JSON.stringify({items:t.map(({relativePath:g,...p})=>p),limit:e,total:c,page:n,totalPages:r})}]}};var m={"list-apis":x};export{m as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{findApiDescriptionByNameAndVersion as t}from"../../utils.js";import{getApiDescriptionFromFs as a}from"./utils.js";async function u(r,i,s){const o=t(i.apiDescriptionsMap,r,s);if(!o)throw new Error(`No API found matching "${r}".`);const e=!!i?.config?.access?.requiresLogin,c=i?.config?.access?.rbac||{},n=await a({relativePath:o.relativePath||"",outdir:i.outdir||"",user:i.user,rbac:c,requiresLogin:e});if(!n)throw new Error(`No API found matching "${r}".`);return n}export{u as loadApiDescription};
|
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
import type { OpenAPIDefinition, OpenAPIOperation } from '@redocly/openapi-docs';
|
|
2
|
-
import type { SearchItemData } from '@redocly/theme/core/types';
|
|
3
2
|
import type { ApiFunctionsUser, RbacConfig } from '@redocly/config';
|
|
4
|
-
import type { McpEndpoint } from '
|
|
3
|
+
import type { McpEndpoint } from '../../../types';
|
|
5
4
|
export declare function isMcpEndpoint(value: unknown): value is McpEndpoint;
|
|
6
5
|
type EndpointInfo = Pick<OpenAPIOperation, 'summary' | 'description' | 'security'> & {
|
|
7
6
|
method: string;
|
|
8
7
|
path: string;
|
|
9
8
|
};
|
|
10
9
|
export declare function getEndpointsFromPaths(def: OpenAPIDefinition): EndpointInfo[];
|
|
11
|
-
export declare function processDocuments(documents: Record<string, SearchItemData[]>, outdir: string): string;
|
|
12
10
|
export declare function getApiDescriptionFromFs({ relativePath, outdir, user, rbac, requiresLogin }: {
|
|
13
11
|
relativePath: string;
|
|
14
12
|
outdir: string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import a from"node:path";import{existsSync as f}from"node:fs";import{readFile as d}from"node:fs/promises";import{replaceFileExtension as h}from"../../../../../plugins/openapi-docs/store-definition-bundles";import{PUBLIC_API_DEFINITIONS_FOLDER as l}from"../../../../../constants/common";import{filterDataByAccessDeep as u}from"../../../../../utils/rbac";import{checkEndpointAndDeleteXMcp as c}from"../../../utils/xmcp-utils.js";function I(t){return typeof t=="object"&&t!==null&&"responses"in t&&typeof t.responses=="object"}function O(t){const{paths:n={}}=t,e=[];for(const[r,i]of Object.entries(n)){const s=!c(i,"docs");for(const[p,o]of Object.entries(i))s||!c(o,"docs")||e.push({path:r,method:p.toUpperCase(),summary:o.summary,description:o.description,security:o.security})}return e}async function P({relativePath:t,outdir:n,user:e,rbac:r={},requiresLogin:i=!1}){const s=a.join(n||"",l,h(t,".json"));if(!f(s))return;const o=await d(s,"utf-8"),m=JSON.parse(o);return u(m,{isAuthenticated:e?.isAuthenticated,email:e?.email,teams:e?.teams},r,i)}export{P as getApiDescriptionFromFs,O as getEndpointsFromPaths,I as isMcpEndpoint};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{toFetchResponse as
|
|
1
|
+
import{toFetchResponse as b,toReqRes as N}from"fetch-to-node";import{logger as m}from"../../../tools/notifiers/logger.js";import{isObject as k}from"../../../../utils/guards/is-object.js";import{createDocsMcpServer as O}from"../servers/docs-server.js";import{filterApiDescriptionsByRbac as U,filterGraphqlDescriptionsByRbac as E}from"../utils.js";import{createMethodNotAllowedError as H,withErrorHandling as I}from"./errors.js";import{attachSseKeepalive as j}from"./sse-keepalive.js";import{McpServerType as L}from"../constants.js";import{constructInvalidTokenResponse as J,constructUnauthorizedResponse as P,handleMcpAuth as q,shouldHandleMcpAuth as B}from"../auth/auth-handlers.js";import{extractTokenFromAuthHeader as G}from"../utils/jwt.js";const u="X-Redocly-AI-Metadata";function $(r){if(r)try{const e=JSON.parse(r);if(k(e))return e;m.warn(`Ignoring ${u} header: not a JSON object.`)}catch{m.warn(`Ignoring ${u} header: invalid JSON.`)}}const z=async(r,e,h)=>{const n=!!e?.config?.access?.requiresLogin,i=e?.config?.access?.rbac||{};let a;const f=r.headers.get("Authorization");if(B(n,i)){const{isAuthenticated:o,isTokenValid:c,currentUser:t,accessToken:p}=await q(r,e);if(!o)return P(new URL(r.url).origin);if(!c)return J();t&&(e.user=t),a=p}else f&&(a=G(f||"")??void 0);let s;const g=async()=>{s&&(await s.cleanup(),s=void 0)};return await I(async()=>{if(r.method==="GET")return new Response(JSON.stringify({error:"Method Not Allowed",message:`In order to use this MCP server, you need register it in your MCP Client (VS Code, Cursor, Claude Code, etc.) using that URL: ${r.url}`}),{status:405,headers:{"Content-Type":"application/json"}});if(r.method!=="POST")return H();const o=h,c=o?.props?.config?.apiDescriptionsMap||{},t=o?.props?.config?.graphqlDescriptions||[],p=o?.props?.config?.mcpDocsServerName||"Docs MCP server",{config:{mcp:D={}}}=e,M=U(c,e.user,i,n),R=E(t,e.user,i,n),y=e.config.products?Object.values(e.config.products).map(l=>l?.name):[],A=D.docs?.name||p,w=$(r.headers.get(u)),T=o?.props?.tools||[];s=await O({name:A,tools:T,context:{...e,accessToken:a,outdir:e.outdir||"",baseUrl:e.baseUrl||new URL(r.url).origin,apiDescriptionsMap:M,graphqlDescriptions:R,products:y,metadata:w}});const v=await r.json(),{req:C,res:d}=N(r),S=j(d);try{await s.transport.handleRequest(C,d,v)}catch(l){throw S.stop(),l}return b(d)},L.Docs,g)};var ee=z;export{ee as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{fileURLToPath as
|
|
1
|
+
import{fileURLToPath as R}from"node:url";import{dirname as q,join as m}from"node:path";import{logger as g}from"../../tools/notifiers/logger.js";import{reporter as w}from"../../tools/notifiers/reporter.js";import{isDefined as A}from"../../../utils/guards/is-defined.js";import{buildGraphqlDescriptions as O,filterIgnoredApiDescriptions as u,getCleanedUpApiDescriptions as T,isMcpInRedirects as j}from"./utils.js";import{getDefaultToolSchemas as E}from"./docs-mcp/tool-schemas.js";import{telemetryTraceStep as G}from"../../../cli/telemetry/helpers/trace-step.js";const h="mcp-docs-server-handler",D=q(R(import.meta.url));async function L(){let i=!1;return{id:"mcp",async processContent(e,r){i||await G("build.plugin.mcp",async c=>{const o=await e.loadOpenApiDefinitions(r),a=await e.loadGraphqlDefinitions(r),s=await r.getConfig(),{mcp:t,redirects:v}=s;if(c?.setAttribute("config",JSON.stringify(t||{})),!(t?.hide||t?.docs?.hide)&&(j(v)&&await w.panicOnBuildContentError('The reserved route "/mcp" cannot be used in redirect configuration. Please remove any redirects involving "/mcp" from your redocly.yaml config.'),!t?.docs?.hide)){g.info("Configuring MCP servers...");const C=m(D,"./handlers/docs-mcp-handler.js"),M=T(u(o,t?.docs?.ignore||[])),p=new Map;for(const n of M){const l=n.definition.info?.title||"",f=n.definition.info?.version||"";p.set(`${l.toLowerCase()}@${f}`,{name:l,description:n.definition.info?.description||"",version:f,servers:n.definition.servers||[],relativePath:n.relativePath})}const d=O(u(a,t?.docs?.ignore||[])),P=Object.values(s.products||{}).map(n=>n?.name).filter(A),y=!!s?.access?.requiresLogin,S=s?.access?.rbac||{},b=E({products:P,requiresLogin:y,rbac:S,hasGraphqlApis:d.length>0});e.addMcpTools(m(D,"./docs-mcp/tools/index.js"),b),await _({actions:e,handlerPath:C,apiDescriptionsMap:Object.fromEntries(p),graphqlDescriptions:d,mcpConfig:t}),i=!0}})},async afterRoutesCreated(e,r){const c=await r.getConfig(),{mcp:o}=c;e.setGlobalData({mcpData:{docs:{enabled:!o?.hide&&!o?.docs?.hide,name:o?.docs?.name}}})}}}var V=L;async function _({actions:i,handlerPath:e,apiDescriptionsMap:r,graphqlDescriptions:c,mcpConfig:o}){i.createRequestHandler(h,e),i.addApiRoute({slug:"/mcp",requestHandlerId:h,httpMethod:"all",getStaticData:async()=>({props:{config:{apiDescriptionsMap:r,graphqlDescriptions:c,mcpDocsServerName:o?.docs?.name||"Docs MCP Server"},serverOutDir:i.serverOutDir,tools:i.getMcpTools().map(({importPath:a,...s})=>s)}})}),g.info("Registered Docs MCP Server endpoint at /mcp")}export{h as MCP_DOCS_SERVER_HANDLER_ID,V as default,L as mcpServerPlugin};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{McpServer as
|
|
1
|
+
import{McpServer as I}from"@redocly/mcp-typescript-sdk/server/mcp.js";import{StreamableHTTPServerTransport as b}from"@redocly/mcp-typescript-sdk/server/streamableHttp.js";import{logger as n}from"../../../tools/notifiers/logger.js";import{mcpToolWorkers as c,MCP_TOOL_WORKER_KEY as q,MCP_TOOL_IS_AVAILABLE_KEY as S}from"../../../workers/mcp-tool-worker-pool.js";async function y({name:e,tools:l,context:m}){const a=new I({name:e,version:new Date().toISOString().slice(0,10)},{capabilities:{logging:{}}}),s=new b({sessionIdGenerator:void 0}),i=M(m);for(const r of l){const p=async(o,d)=>{n.info(`MCP tool called: ${r.name}`);const g={toolName:r.name,args:o,context:i,extra:_(d)};return await c.exec(q,[g],{timeout:6e4})},u=a.tool(r.name,r.description,r.schema,p),f={toolName:r.name,context:i};let t=!1;try{t=await c.exec(S,[f],{timeout:1e4})}catch(o){n.error(`Failed to check MCP tool availability for "${r.name}": ${o instanceof Error?o.message:String(o)}`),t=!1}t||u.disable()}return await a.connect(s),{server:a,transport:s,cleanup:async()=>{s.close()}}}function _(e){return{sessionId:e.sessionId,authInfo:e.authInfo,requestId:e.requestId,requestInfo:e.requestInfo,_meta:e._meta}}function M(e){return{user:e.user,config:e.config,outdir:e.outdir,baseUrl:e.baseUrl,params:e.params,query:e.query,cookies:e.cookies,apiDescriptionsMap:e.apiDescriptionsMap,graphqlDescriptions:e.graphqlDescriptions,products:e.products,accessToken:e.accessToken,metadata:e.metadata}}export{y as createDocsMcpServer};
|
|
@@ -15,9 +15,15 @@ export type ApiDescriptionInfo = {
|
|
|
15
15
|
version?: string;
|
|
16
16
|
servers?: OpenAPIServer[];
|
|
17
17
|
};
|
|
18
|
+
export type GraphqlDescriptionInfo = {
|
|
19
|
+
name: string;
|
|
20
|
+
relativePath: string;
|
|
21
|
+
description?: string;
|
|
22
|
+
};
|
|
18
23
|
export type McpDocsStaticDataPropsConfig = {
|
|
19
24
|
mcpDocsServerName: string;
|
|
20
25
|
apiDescriptionsMap: Record<string, ApiDescriptionInfo>;
|
|
26
|
+
graphqlDescriptions: GraphqlDescriptionInfo[];
|
|
21
27
|
};
|
|
22
28
|
export type McpDocsStaticData = PageStaticData & {
|
|
23
29
|
props: {
|
|
@@ -76,6 +82,7 @@ export type McpToolExtra = {
|
|
|
76
82
|
};
|
|
77
83
|
export type McpToolContext = Omit<ApiFunctionsContext, 'telemetry' | 'getKv' | keyof ApiFunctionsContextMethods> & {
|
|
78
84
|
apiDescriptionsMap: Record<string, ApiDescriptionInfo>;
|
|
85
|
+
graphqlDescriptions: GraphqlDescriptionInfo[];
|
|
79
86
|
products?: string[];
|
|
80
87
|
accessToken?: string;
|
|
81
88
|
metadata?: Record<string, unknown>;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { ApiFunctionsUser, RbacConfig, RedirectConfig } from '@redocly/config';
|
|
2
2
|
import type { ProcessContentActions } from '../../types';
|
|
3
|
-
import type {
|
|
3
|
+
import type { BundledDefinition as GraphqlBundledDefinition } from '../../plugins/graphql-docs/graphql-doc-loader';
|
|
4
|
+
import type { ApiDescriptionInfo, GraphqlDescriptionInfo } from './types.js';
|
|
4
5
|
export type ApiDescriptions = Awaited<ReturnType<ProcessContentActions['loadOpenApiDefinitions']>>;
|
|
5
6
|
/**
|
|
6
7
|
* Filters out localizations and definitions with no public paths.
|
|
@@ -37,22 +38,11 @@ export declare function getCleanedUpApiDescriptions(apiDescriptions: ApiDescript
|
|
|
37
38
|
* // Returns only definitions the user can access with filtered content
|
|
38
39
|
*/
|
|
39
40
|
export declare function filterApiDescriptionsByRbac(apiDescriptions: Record<string, ApiDescriptionInfo>, user: ApiFunctionsUser, rbac: RbacConfig, requiresLogin: boolean): Record<string, ApiDescriptionInfo>;
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
* Definitions matching these patterns will be excluded from the result.
|
|
46
|
-
*
|
|
47
|
-
* @param apiDescriptions - Array of OpenAPI definitions to filter.
|
|
48
|
-
* @param ignoredPaths - Array of glob patterns for paths to ignore.
|
|
49
|
-
* @returns Array of definitions that don't match any ignored path patterns.
|
|
50
|
-
*
|
|
51
|
-
* @example
|
|
52
|
-
* filterIgnoredApiDescriptions(apiDescriptions, ['path/to/ignore']);
|
|
53
|
-
* // Returns definitions not matching test or internal path patterns
|
|
54
|
-
*/
|
|
55
|
-
export declare function filterIgnoredApiDescriptions(apiDescriptions: ApiDescriptions, ignoredPaths: string[]): ApiDescriptions;
|
|
41
|
+
export declare function filterGraphqlDescriptionsByRbac(graphqlDescriptions: GraphqlDescriptionInfo[], user: ApiFunctionsUser, rbac: RbacConfig, requiresLogin: boolean): GraphqlDescriptionInfo[];
|
|
42
|
+
export declare function buildGraphqlDescriptions(definitions: GraphqlBundledDefinition[]): GraphqlDescriptionInfo[];
|
|
43
|
+
export declare function filterIgnoredApiDescriptions<T extends {
|
|
44
|
+
relativePath: string;
|
|
45
|
+
}>(apiDescriptions: T[], ignoredPaths: string[]): T[];
|
|
56
46
|
/**
|
|
57
47
|
* Checks if the MCP route (/mcp) appears in redirect configuration.
|
|
58
48
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{join as
|
|
1
|
+
import p,{join as c}from"node:path";import D from"picomatch";import{PUBLIC_API_DEFINITIONS_FOLDER as f,L10N_DIR_NAME as a,I18N_DIR_NAME as u}from"../../constants/common.js";import{RESERVED_ROUTES as l}from"../../plugins/get-reserved-routes.js";import{canDownloadApiDefinition as h}from"../../utils/rbac.js";function o(r){if(typeof r!="object"||r===null)return r;if(Array.isArray(r))return r.map(o);const i={};for(const t in r)if(Object.hasOwn(r,t)){if(t.toString().startsWith("x-parsed-"))continue;i[t]=o(r[t])}return i}function R(r){return r.reduce((i,t)=>(t.relativePath.startsWith(a)||t.relativePath.startsWith(u)||t.definition?.paths&&Object.keys(t.definition.paths).length>0&&i.push({...t,definition:o(t.definition)}),i),[])}function x(r,i,t,e){const n={};for(const[m,s]of Object.entries(r))h(c(f,s.relativePath),t,e,i)&&(n[m]=s);return n}function E(r,i,t,e){return r.filter(n=>h(c(f,n.relativePath),t,e,i))}function P(r){return r.filter(({relativePath:i})=>!i.startsWith(a)&&!i.startsWith(u)).map(({relativePath:i,settings:t})=>({name:t.info?.title||p.basename(i,p.extname(i)),description:t.info?.description,relativePath:i}))}function _(r,i){return r.filter(({relativePath:t})=>!D(i||[])(t))}function g(r={}){for(const[i,t]of Object.entries(r))if(i===l.mcp||(typeof t=="string"?t:t.to)===l.mcp)return!0;return!1}export{P as buildGraphqlDescriptions,x as filterApiDescriptionsByRbac,E as filterGraphqlDescriptionsByRbac,_ as filterIgnoredApiDescriptions,R as getCleanedUpApiDescriptions,g as isMcpInRedirects};
|
package/dist/server/store.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ import type { RedoclyConfig, RedirectConfig, CompilationError, PageStaticData }
|
|
|
6
6
|
import type { SearchFacet } from '@redocly/theme/core/types';
|
|
7
7
|
import type { BundledDefinition as OpenApiBundledDefinition } from './plugins/openapi-docs/load-definition.js';
|
|
8
8
|
import type { BundledDefinition as AsyncApiBundledDefinition } from './plugins/asyncapi-docs/asyncapi-doc-loader.js';
|
|
9
|
+
import type { BundledDefinition as GraphqlBundledDefinition } from './plugins/graphql-docs/graphql-doc-loader.js';
|
|
9
10
|
import type { SearchEngine } from './plugins/search/engines/search-engine.js';
|
|
10
11
|
import { KvService } from './persistence/kv/services/kv-service.js';
|
|
11
12
|
export declare const MARKDOC_PARTIALS_DATA_KEY = "markdown/partials";
|
|
@@ -106,6 +107,7 @@ export declare class Store {
|
|
|
106
107
|
}>;
|
|
107
108
|
loadOpenApiDefinitions(context: LifecycleContext): Promise<OpenApiBundledDefinition[]>;
|
|
108
109
|
loadAsyncApiDefinitions(context: LifecycleContext): Promise<AsyncApiBundledDefinition[]>;
|
|
110
|
+
loadGraphqlDefinitions(context: LifecycleContext): Promise<GraphqlBundledDefinition[]>;
|
|
109
111
|
setSearchEngine(engine: SearchEngine): void;
|
|
110
112
|
setSearchFacets: (searchFacets: Map<string, SearchFacet>) => void;
|
|
111
113
|
setGlobalConfig: (data: Partial<RedoclyConfig>) => void;
|
package/dist/server/store.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import b from"@markdoc/markdoc";import{getPathnameForLocale as A}from"@redocly/theme/core/utils";import{DEFAULT_LOCALE_PLACEHOLDER as g}from"../constants/common.js";import{DEFAULT_TITLE as T}from"./constants/common.js";import{GATED_MARKDOC_TAGS as D}from"./constants/entitlements.js";import{isObject as O}from"../utils/guards/is-object.js";import{mapObject as M}from"../utils/object/map-object.js";import{getValueDeep as R}from"../utils/object/get-value-deep.js";import{removeTrailingSlash as L}from"../utils/url/remove-trailing-slash.js";import{normalizeRouteSlug as h}from"../utils/path/normalize-route-slug.js";import{isLocalLink as y}from"../utils/path/is-local-link.js";import{reporter as w}from"./tools/notifiers/reporter.js";import{logger as u}from"./tools/notifiers/logger.js";import{sha1 as k}from"./utils/crypto/sha1.js";import{envConfig as _,setEnv as G}from"./config/env-config.js";import{KvService as F}from"./persistence/kv/services/kv-service.js";import{writeSharedData as B}from"./utils/index.js";import{renderComponents as I}from"./ssr/render.js";import{readStaticData as H,writeStaticData as N}from"./utils/static-data.js";import{parseAndResolveMarkdoc as V}from"./plugins/markdown/compiler.js";import{getMarkdocOptions as j}from"./plugins/markdown/markdoc/markdoc-options.js";import{EntitlementsProvider as S}from"./entitlements/entitlements-provider.js";import{isL10nPath as q}from"./fs/utils/is-l10n-path.js";import{resolveGlobMapValue as K}from"./utils/globs.js";import{replaceEnvVariablesDeep as U}from"./utils/envs/replace-env-variables-deep.js";import{findRedirect as x}from"./utils/redirects/find-redirect.js";import{followRedirectChain as J}from"./utils/redirects/follow-redirect-chain.js";import{addWildcardRedirectToTree as W}from"./utils/redirects/add-wildcard-redirect-to-tree.js";import{telemetryTraceStep as $}from"../cli/telemetry/helpers/trace-step.js";const v={routesBySlug:"map",apiRoutes:"object",middleware:"object",routesByFsPath:"map",routesSharedData:"map",globalData:"object",config:"object",ssr:"object",searchFacets:"map",routesPartials:"map",mcpToolHandlers:"map"},m="markdown/partials",z="markdown/partials-deps",E="PLAN_GATES",Y=["OAUTH_CLIENT_ID","OAUTH_CLIENT_SECRET","ORGANIZATION_SLUG","ORGANIZATION_ID","ORG_ID"],Ae="userDefinedApiFunctions";class P{routesBySlug=new Map;replacedEnvVars={};unsetEnvVars=new Set;lifecycleContext;newRoutes=[];#e={};routesByFsPath=new Map;apiRoutes=[];middleware=[];routesSharedData=new Map;sharedDataDeps=new Map;sharedDataMarkdocComponents=new Map;routesDynamicComponents=new Map;routesPartials=new Map;ssr={preBodyTags:[],postBodyTags:[],headTags:[]};searchFacets=new Map;searchEngine;templates=new Map;browserPlugins=new Set;apiRoutesRequestHandlers=new Map;mcpToolHandlers=new Map;serverPropsGetters=new Map;pagePropsGetters=new Map;listeners=new Map;globalData={};#s=void 0;config={configFilePath:"",redirects:{},wildcardRedirectsTree:{},access:{rbac:{},requiresLogin:!1},directoryPermissions:{},devLogin:!1,ssoDirect:{}};#r;serverMode;serverOutDir;outdir;buildRevision=0;hasSitemap=!1;compilationErrors=[];#a;userCodeReady;#o=Promise.resolve();#i;#n=Promise.resolve();#c;#t=new Map;constructor({outdir:e,contentDir:s,serverMode:t=!1,serverOutDir:a}){this.#r=s,this.outdir=e,this.serverMode=t,this.serverOutDir=a,this.userCodeReady=new Promise(r=>{this.#a=r})}on(e,s){const t=this.listeners.get(e);t?t.add(s):this.listeners.set(e,new Set([s]))}queueEvent=(e,s,...t)=>{this.#t.set(e+String(s),[e,s,...t])};runListeners=(e,s,...t)=>{for(const a of this.listeners.get(e)||new Set)s?a(s,...t):a(...t)};startPluginsRun(){this.clear(),this.#o=new Promise(e=>{this.#i=e})}waitForPluginsLifecycle(){return Promise.all([this.#o,this.#n])}finishPluginsRun(){this.#i?.();for(const e of this.#t.values())this.runListeners(...e);this.#t.clear()}startEsbuildRun(){this.#n=new Promise(e=>{this.#c=e})}finishEsbuildRun(){this.#c?.()}get contentDir(){if(this.serverMode)throw new Error("contentDir should not be used in server mode");return this.#r}markUserCodeReady(){this.#a?.(!0)}async reloadMarkdocOptions(){await $("build.reload_markdoc_options",async()=>{const e=S.instance(),s=await j(this.serverOutDir),t=Object.fromEntries(Object.entries(s.tags).filter(([a])=>D[a]!=null?e.canAccessFeature(D[a]):!0));this.#s={...s,tags:t}})}get markdocOptions(){return{...this.#s,partials:this.getGlobalConfig(m),themeConfig:this.config.markdown}}setGlobalData=e=>{const s=this.globalData,t={...this.globalData,...e};this.globalData=t,JSON.stringify(t)!==JSON.stringify(s)&&this.queueEvent("global-data-updated",void 0,t)};getGlobalData=()=>this.globalData;getKv=async()=>F.getInstance({baseDbDir:this.serverOutDir});parseMarkdoc=async({input:e,context:s,deps:t,resource:a})=>{const{data:{info:r,ast:o},compoundHash:l}=await V(e,this.markdocOptions,{actions:this,context:s},a);for(const i of r.sharedDataDeps||[]){for(const n of t?.routeSlugs||[])this.addRouteSharedData(n,i,i);for(const n of t?.sharedDataIds||[]){const c=this.sharedDataDeps.get(n)||new Set;c.add(i),this.sharedDataDeps.set(n,c)}}for(const i of r.dynamicMarkdocComponents||[]){for(const n of t?.routeSlugs||[]){const c=this.routesDynamicComponents.get(n)||new Set;c.add(i),this.routesDynamicComponents.set(n,c)}for(const n of t?.sharedDataIds||[]){const c=this.sharedDataMarkdocComponents.get(n)||new Set;c.add(i),this.sharedDataMarkdocComponents.set(n,c)}}if(t?.routeSlugs&&r.partials?.length)for(const i of t.routeSlugs){const n=this.routesPartials.get(i)||[];for(const c of r.partials)n.includes(c)||n.push(c);this.routesPartials.set(i,n)}return{info:r,ast:o,compoundHash:l}};async loadOpenApiDefinitions(e){return(await e.cache.load(".","load-oas-docs")).data}async loadAsyncApiDefinitions(e){return(await e.cache.load(".","asyncapi-docs")).data}setSearchEngine(e){this.searchEngine=e}setSearchFacets=e=>{this.searchFacets=e};setGlobalConfig=e=>{const s=Object.keys(e);for(const o of s)for(const l in this.replacedEnvVars)if(l===o||l.startsWith(`${o}:`)){const i=l.split(":"),{error:n,value:c}=R(e,i);(n||c!==this.replacedEnvVars[l].replaced)&&delete this.replacedEnvVars[l]}const{resolvedObj:t,unsetEnvVars:a,replacedValues:r}=U(e);for(const o of a)this.unsetEnvVars.add(o);Object.assign(this.replacedEnvVars,r),Object.assign(this.config,t)};getConfig=()=>this.config;getGlobalConfig=e=>this.config[e];getSearchFacets=()=>this.searchFacets;addRedirect=(e,s,t={})=>{if(!S.instance().canAccessFeature("redirects")&&e!=="/")return;this.config.redirects||(this.config.redirects={});const o=h(e).toLowerCase();this.config.redirects[o]=s;const{trackOriginalSource:l=!0}=t,i=this.getGlobalConfig("originalRedirectSources");l&&Array.isArray(i)&&!i.includes(o)&&i.push(o),o.endsWith("*")&&W(this.config.wildcardRedirectsTree,o)};getRedirect=e=>{const s=h(e).toLowerCase(),t=x(s,this.config.redirects,this.config.wildcardRedirectsTree);if(!t)return null;if(y(t.to)){const a=h(t.to).toLowerCase();if(!a.endsWith("*")&&J(a,[s],this.config.redirects,this.config.wildcardRedirectsTree).type==="cycle")return null}return{to:t.to,type:t.type}};createSharedData=async(e,s,t)=>{if(t&&this.#e[e]===t)return e;const a=JSON.stringify(s),r=t??k(a);return this.#e[e]===r||(this.#e[e]=r,await B(e,a,this.outdir),this.queueEvent("shared-data-updated",e)),e};addRouteSharedData=(e,s,t)=>{const a=L(e),r=this.routesSharedData.get(a)||{};r[s]=t,this.routesSharedData.set(a,r),u.verbose(`Adding shared data to ${e}, ${s}, ${t}`)};getRouteSharedDataByFsPath=e=>{const s=this.routesByFsPath.get(e);return s?this.routesSharedData.get(s)||{}:{}};getPartialsForRoute=e=>{const s=this.getGlobalConfig(m)||{},t=this.routesPartials.get(e);if(!t||t.length===0)return{};const a=this.getGlobalConfig(z)||{},r=new Set(t),o=Array.from(t);for(let i=0;i<o.length;i++){const n=o[i],c=a[n]?.partials??[];for(const d of c)r.has(d)||(r.add(d),o.push(d))}const l={};for(const i of r)s[i]&&(l[i]=s[i]);return l};addRoute=e=>{const t={...K(e.fsPath,this.config.metadataGlobs),...e.metadata||{}};this.newRoutes.push({...e,metadata:t}),u.verbose("Created route %s",e.slug)};addRouteSharedDataToAllLocales=(e,s,t)=>{const a=[g,...this.lifecycleContext?.fs.localeFolders||[]].map(r=>({code:r,name:r}));for(const r of a){const o=A(e,g,r.code,a);this.addRouteSharedData(o,s,t)}};addApiRoute=e=>{this.apiRoutes.push(e),u.verbose("Created API route %s",e.slug)};addMcpTools=(e,s)=>{for(const t of s)this.mcpToolHandlers.set(t.name,{...t,importPath:e}),u.verbose("Created MCP tool %s",t.name)};getMcpTools=()=>Array.from(this.mcpToolHandlers.values());addMiddleware=e=>{this.middleware.push(e),u.verbose("Created middleware %s",e.id)};setResourceResponseHeaders=(e,s)=>{this.config.responseHeaders||(this.config.responseHeaders={});const t=new Set(s.map(o=>o.name.toLowerCase())),r=[...(this.config.responseHeaders[e]??[]).filter(o=>!t.has(o.name.toLowerCase())),...s];this.config.responseHeaders[e]=r};getRouteByFsPath=e=>{const s=this.routesByFsPath.get(e);return s?this.getRouteBySlug(s):void 0};getRouteBySlug=(e,s={})=>{const{followRedirect:t=!0}=s,a=this.getRedirect(e);return t&&a?this.routesBySlug.get(h(a.to)):this.routesBySlug.get(e)};hasRouteOrRedirectBySlug=e=>{if(this.routesBySlug.has(e))return!0;const s=this.getRedirect(e);if(!s)return!1;if(!y(s.to))return!0;const t=h(s.to);return this.routesBySlug.has(t)};getRoutesByTemplateId=e=>this.newRoutes.filter(s=>s.templateId===e);getAllRoutesForLocale=(e=g)=>{const s=Array.from(this.routesBySlug.values()),t=e.toLowerCase();return s.filter(a=>e===g?!q(a.fsPath):a.slug.startsWith(`/${t}`))};getAllRoutes=()=>Array.from(this.routesBySlug.values());getAllApiRoutes=()=>this.apiRoutes;getAllMiddleware=()=>this.middleware;getTemplate=e=>this.templates.get(e);getRequestHandler=e=>this.apiRoutesRequestHandlers.get(e);createTemplate=(e,s)=>(this.templates.set(e,s),e);addBrowserPlugin=e=>{this.browserPlugins.add(e)};createRequestHandler=(e,s)=>(this.apiRoutesRequestHandlers.set(e,s),e);clearRequestHandlersByPrefix=e=>{for(const s of this.apiRoutesRequestHandlers.keys())s.startsWith(e)&&this.apiRoutesRequestHandlers.delete(s)};registerServerPropsGetter=(e,s)=>(this.serverPropsGetters.set(e,s),e);registerPagePropsGetter=(e,s)=>{this.pagePropsGetters.set(e,s)};async writeRouteStaticData(e,s){const t=await this.resolveRouteStaticData(e,s,!1);t&&N(e.slug,t,this.outdir)}async resolveRouteStaticData(e,s,t){if(this.serverMode)return H(e.slug,this.outdir);const a={...this,contentDir:this.contentDir,parseMarkdoc:({input:c,context:d,resource:f})=>this.parseMarkdoc({input:c,context:d,deps:{routeSlugs:[e.slug]},resource:f})},r=await e.getStaticData?.(e,a)||{},o=new Set(this.routesDynamicComponents.get(e.slug)),l=this.routesSharedData.get(e.slug)||{};for(const c of Object.values(l)){const d=this.sharedDataMarkdocComponents.get(c);d&&d.forEach(p=>o.add(p));const f=this.sharedDataDeps.get(c);f&&f.forEach(p=>this.addRouteSharedData(e.slug,p,p))}const i=this.getGlobalConfig("seo"),n=r?.frontmatter||{};return{...r,frontmatter:{...n,seo:{...n?.seo,title:n?.seo?.title||await e.getNavText?.()}},props:{...r.props,dynamicMarkdocComponents:Array.from(o),metadata:{...r?.props?.metadata,...e.metadata},seo:{title:T,...i,...r.props?.seo},compilationErrors:this.compilationErrors},lastModified:t||!e.fsPath?null:await this.lifecycleContext?.fs.getLastModified(e.fsPath)}}addSsrComponents(e,s){if(!e?.length)return;const t=typeof e[0]=="string"?e.join(""):I(e);t&&(s==="head"?this.ssr.headTags.push(t):s==="preBody"?this.ssr.preBodyTags.push(t):this.ssr.postBodyTags.push(t))}clear=()=>{this.routesByFsPath.clear(),this.templates.clear(),this.newRoutes=[],this.routesBySlug.clear(),this.apiRoutes=[],this.middleware=[],this.routesSharedData.clear(),this.sharedDataDeps.clear(),this.sharedDataMarkdocComponents.clear(),this.routesDynamicComponents.clear(),this.routesPartials.clear(),this.config.redirects={},this.config.wildcardRedirectsTree={},this.config.directoryPermissions={},this.ssr={preBodyTags:[],postBodyTags:[],headTags:[]}};async toJson(){const e=[];for(const[t,a]of Object.entries(v))switch(a){case"map":const r=Array.from(this[t].entries());e.push([t,r]);break;case"object":t==="config"&&e.push([t,await this.getConfigWithEnvPlaceholders()]),e.push([t,this[t]]);break;default:throw new Error("Invalid format")}const s=Object.fromEntries(e);return s[E]=_.PLAN_GATES,s}static fromJson(e,s){const t=new P(s);for(const[r,o]of Object.entries(v))switch(o){case"map":t[r]=new Map(e[r]);break;case"object":if(r==="config"){t.setGlobalConfig(e[r]);break}t[r]=e[r];break;default:throw new Error("Invalid format")}t.config[m]=Z(t.config[m]||{});const a=e[E];return a&&G("PLAN_GATES",a),t}async getConfigWithEnvPlaceholders(){const e=JSON.parse(JSON.stringify(this.config));for(const s in this.replacedEnvVars){const{original:t}=this.replacedEnvVars[s],a=s.split(":"),r=a.pop(),{error:o,value:l}=R(e,a);if(o||!O(l)&&!Array.isArray(l)){await w.panicOnBuild(`Failed to replace env var with env name for ${s}`);continue}l[r]=t}return e}async reportUnsetEnvVars(){if(this.unsetEnvVars.size===0)return;const e=Array.from(this.unsetEnvVars).filter(t=>!Y.includes(t));if(e.length===0)return;const s=`Failed to resolve config. The following environment variables are not set: ${e.join(", ")}`;await w.panicOnBuildContentError(s)}}function Z(C){return M(C,e=>b.Ast.fromJSON(JSON.stringify(e)))}export{m as MARKDOC_PARTIALS_DATA_KEY,z as MARKDOC_PARTIALS_DEPS_KEY,P as Store,Ae as USER_DEFINED_API_FUNCTIONS_COUNTER_KEY};
|
|
1
|
+
import b from"@markdoc/markdoc";import{getPathnameForLocale as A}from"@redocly/theme/core/utils";import{DEFAULT_LOCALE_PLACEHOLDER as g}from"../constants/common.js";import{DEFAULT_TITLE as T}from"./constants/common.js";import{GATED_MARKDOC_TAGS as D}from"./constants/entitlements.js";import{isObject as O}from"../utils/guards/is-object.js";import{mapObject as M}from"../utils/object/map-object.js";import{getValueDeep as R}from"../utils/object/get-value-deep.js";import{removeTrailingSlash as L}from"../utils/url/remove-trailing-slash.js";import{normalizeRouteSlug as h}from"../utils/path/normalize-route-slug.js";import{isLocalLink as y}from"../utils/path/is-local-link.js";import{reporter as w}from"./tools/notifiers/reporter.js";import{logger as u}from"./tools/notifiers/logger.js";import{sha1 as k}from"./utils/crypto/sha1.js";import{envConfig as _,setEnv as G}from"./config/env-config.js";import{KvService as F}from"./persistence/kv/services/kv-service.js";import{writeSharedData as B}from"./utils/index.js";import{renderComponents as I}from"./ssr/render.js";import{readStaticData as H,writeStaticData as N}from"./utils/static-data.js";import{parseAndResolveMarkdoc as V}from"./plugins/markdown/compiler.js";import{getMarkdocOptions as j}from"./plugins/markdown/markdoc/markdoc-options.js";import{EntitlementsProvider as S}from"./entitlements/entitlements-provider.js";import{isL10nPath as q}from"./fs/utils/is-l10n-path.js";import{resolveGlobMapValue as K}from"./utils/globs.js";import{replaceEnvVariablesDeep as U}from"./utils/envs/replace-env-variables-deep.js";import{findRedirect as x}from"./utils/redirects/find-redirect.js";import{followRedirectChain as J}from"./utils/redirects/follow-redirect-chain.js";import{addWildcardRedirectToTree as W}from"./utils/redirects/add-wildcard-redirect-to-tree.js";import{telemetryTraceStep as $}from"../cli/telemetry/helpers/trace-step.js";const v={routesBySlug:"map",apiRoutes:"object",middleware:"object",routesByFsPath:"map",routesSharedData:"map",globalData:"object",config:"object",ssr:"object",searchFacets:"map",routesPartials:"map",mcpToolHandlers:"map"},m="markdown/partials",z="markdown/partials-deps",E="PLAN_GATES",Y=["OAUTH_CLIENT_ID","OAUTH_CLIENT_SECRET","ORGANIZATION_SLUG","ORGANIZATION_ID","ORG_ID"],Ae="userDefinedApiFunctions";class P{routesBySlug=new Map;replacedEnvVars={};unsetEnvVars=new Set;lifecycleContext;newRoutes=[];#e={};routesByFsPath=new Map;apiRoutes=[];middleware=[];routesSharedData=new Map;sharedDataDeps=new Map;sharedDataMarkdocComponents=new Map;routesDynamicComponents=new Map;routesPartials=new Map;ssr={preBodyTags:[],postBodyTags:[],headTags:[]};searchFacets=new Map;searchEngine;templates=new Map;browserPlugins=new Set;apiRoutesRequestHandlers=new Map;mcpToolHandlers=new Map;serverPropsGetters=new Map;pagePropsGetters=new Map;listeners=new Map;globalData={};#s=void 0;config={configFilePath:"",redirects:{},wildcardRedirectsTree:{},access:{rbac:{},requiresLogin:!1},directoryPermissions:{},devLogin:!1,ssoDirect:{}};#r;serverMode;serverOutDir;outdir;buildRevision=0;hasSitemap=!1;compilationErrors=[];#a;userCodeReady;#o=Promise.resolve();#i;#n=Promise.resolve();#c;#t=new Map;constructor({outdir:e,contentDir:s,serverMode:t=!1,serverOutDir:a}){this.#r=s,this.outdir=e,this.serverMode=t,this.serverOutDir=a,this.userCodeReady=new Promise(r=>{this.#a=r})}on(e,s){const t=this.listeners.get(e);t?t.add(s):this.listeners.set(e,new Set([s]))}queueEvent=(e,s,...t)=>{this.#t.set(e+String(s),[e,s,...t])};runListeners=(e,s,...t)=>{for(const a of this.listeners.get(e)||new Set)s?a(s,...t):a(...t)};startPluginsRun(){this.clear(),this.#o=new Promise(e=>{this.#i=e})}waitForPluginsLifecycle(){return Promise.all([this.#o,this.#n])}finishPluginsRun(){this.#i?.();for(const e of this.#t.values())this.runListeners(...e);this.#t.clear()}startEsbuildRun(){this.#n=new Promise(e=>{this.#c=e})}finishEsbuildRun(){this.#c?.()}get contentDir(){if(this.serverMode)throw new Error("contentDir should not be used in server mode");return this.#r}markUserCodeReady(){this.#a?.(!0)}async reloadMarkdocOptions(){await $("build.reload_markdoc_options",async()=>{const e=S.instance(),s=await j(this.serverOutDir),t=Object.fromEntries(Object.entries(s.tags).filter(([a])=>D[a]!=null?e.canAccessFeature(D[a]):!0));this.#s={...s,tags:t}})}get markdocOptions(){return{...this.#s,partials:this.getGlobalConfig(m),themeConfig:this.config.markdown}}setGlobalData=e=>{const s=this.globalData,t={...this.globalData,...e};this.globalData=t,JSON.stringify(t)!==JSON.stringify(s)&&this.queueEvent("global-data-updated",void 0,t)};getGlobalData=()=>this.globalData;getKv=async()=>F.getInstance({baseDbDir:this.serverOutDir});parseMarkdoc=async({input:e,context:s,deps:t,resource:a})=>{const{data:{info:r,ast:o},compoundHash:l}=await V(e,this.markdocOptions,{actions:this,context:s},a);for(const i of r.sharedDataDeps||[]){for(const n of t?.routeSlugs||[])this.addRouteSharedData(n,i,i);for(const n of t?.sharedDataIds||[]){const c=this.sharedDataDeps.get(n)||new Set;c.add(i),this.sharedDataDeps.set(n,c)}}for(const i of r.dynamicMarkdocComponents||[]){for(const n of t?.routeSlugs||[]){const c=this.routesDynamicComponents.get(n)||new Set;c.add(i),this.routesDynamicComponents.set(n,c)}for(const n of t?.sharedDataIds||[]){const c=this.sharedDataMarkdocComponents.get(n)||new Set;c.add(i),this.sharedDataMarkdocComponents.set(n,c)}}if(t?.routeSlugs&&r.partials?.length)for(const i of t.routeSlugs){const n=this.routesPartials.get(i)||[];for(const c of r.partials)n.includes(c)||n.push(c);this.routesPartials.set(i,n)}return{info:r,ast:o,compoundHash:l}};async loadOpenApiDefinitions(e){return(await e.cache.load(".","load-oas-docs")).data}async loadAsyncApiDefinitions(e){return(await e.cache.load(".","asyncapi-docs")).data}async loadGraphqlDefinitions(e){return(await e.cache.load(".","load-graphql-docs")).data}setSearchEngine(e){this.searchEngine=e}setSearchFacets=e=>{this.searchFacets=e};setGlobalConfig=e=>{const s=Object.keys(e);for(const o of s)for(const l in this.replacedEnvVars)if(l===o||l.startsWith(`${o}:`)){const i=l.split(":"),{error:n,value:c}=R(e,i);(n||c!==this.replacedEnvVars[l].replaced)&&delete this.replacedEnvVars[l]}const{resolvedObj:t,unsetEnvVars:a,replacedValues:r}=U(e);for(const o of a)this.unsetEnvVars.add(o);Object.assign(this.replacedEnvVars,r),Object.assign(this.config,t)};getConfig=()=>this.config;getGlobalConfig=e=>this.config[e];getSearchFacets=()=>this.searchFacets;addRedirect=(e,s,t={})=>{if(!S.instance().canAccessFeature("redirects")&&e!=="/")return;this.config.redirects||(this.config.redirects={});const o=h(e).toLowerCase();this.config.redirects[o]=s;const{trackOriginalSource:l=!0}=t,i=this.getGlobalConfig("originalRedirectSources");l&&Array.isArray(i)&&!i.includes(o)&&i.push(o),o.endsWith("*")&&W(this.config.wildcardRedirectsTree,o)};getRedirect=e=>{const s=h(e).toLowerCase(),t=x(s,this.config.redirects,this.config.wildcardRedirectsTree);if(!t)return null;if(y(t.to)){const a=h(t.to).toLowerCase();if(!a.endsWith("*")&&J(a,[s],this.config.redirects,this.config.wildcardRedirectsTree).type==="cycle")return null}return{to:t.to,type:t.type}};createSharedData=async(e,s,t)=>{if(t&&this.#e[e]===t)return e;const a=JSON.stringify(s),r=t??k(a);return this.#e[e]===r||(this.#e[e]=r,await B(e,a,this.outdir),this.queueEvent("shared-data-updated",e)),e};addRouteSharedData=(e,s,t)=>{const a=L(e),r=this.routesSharedData.get(a)||{};r[s]=t,this.routesSharedData.set(a,r),u.verbose(`Adding shared data to ${e}, ${s}, ${t}`)};getRouteSharedDataByFsPath=e=>{const s=this.routesByFsPath.get(e);return s?this.routesSharedData.get(s)||{}:{}};getPartialsForRoute=e=>{const s=this.getGlobalConfig(m)||{},t=this.routesPartials.get(e);if(!t||t.length===0)return{};const a=this.getGlobalConfig(z)||{},r=new Set(t),o=Array.from(t);for(let i=0;i<o.length;i++){const n=o[i],c=a[n]?.partials??[];for(const d of c)r.has(d)||(r.add(d),o.push(d))}const l={};for(const i of r)s[i]&&(l[i]=s[i]);return l};addRoute=e=>{const t={...K(e.fsPath,this.config.metadataGlobs),...e.metadata||{}};this.newRoutes.push({...e,metadata:t}),u.verbose("Created route %s",e.slug)};addRouteSharedDataToAllLocales=(e,s,t)=>{const a=[g,...this.lifecycleContext?.fs.localeFolders||[]].map(r=>({code:r,name:r}));for(const r of a){const o=A(e,g,r.code,a);this.addRouteSharedData(o,s,t)}};addApiRoute=e=>{this.apiRoutes.push(e),u.verbose("Created API route %s",e.slug)};addMcpTools=(e,s)=>{for(const t of s)this.mcpToolHandlers.set(t.name,{...t,importPath:e}),u.verbose("Created MCP tool %s",t.name)};getMcpTools=()=>Array.from(this.mcpToolHandlers.values());addMiddleware=e=>{this.middleware.push(e),u.verbose("Created middleware %s",e.id)};setResourceResponseHeaders=(e,s)=>{this.config.responseHeaders||(this.config.responseHeaders={});const t=new Set(s.map(o=>o.name.toLowerCase())),r=[...(this.config.responseHeaders[e]??[]).filter(o=>!t.has(o.name.toLowerCase())),...s];this.config.responseHeaders[e]=r};getRouteByFsPath=e=>{const s=this.routesByFsPath.get(e);return s?this.getRouteBySlug(s):void 0};getRouteBySlug=(e,s={})=>{const{followRedirect:t=!0}=s,a=this.getRedirect(e);return t&&a?this.routesBySlug.get(h(a.to)):this.routesBySlug.get(e)};hasRouteOrRedirectBySlug=e=>{if(this.routesBySlug.has(e))return!0;const s=this.getRedirect(e);if(!s)return!1;if(!y(s.to))return!0;const t=h(s.to);return this.routesBySlug.has(t)};getRoutesByTemplateId=e=>this.newRoutes.filter(s=>s.templateId===e);getAllRoutesForLocale=(e=g)=>{const s=Array.from(this.routesBySlug.values()),t=e.toLowerCase();return s.filter(a=>e===g?!q(a.fsPath):a.slug.startsWith(`/${t}`))};getAllRoutes=()=>Array.from(this.routesBySlug.values());getAllApiRoutes=()=>this.apiRoutes;getAllMiddleware=()=>this.middleware;getTemplate=e=>this.templates.get(e);getRequestHandler=e=>this.apiRoutesRequestHandlers.get(e);createTemplate=(e,s)=>(this.templates.set(e,s),e);addBrowserPlugin=e=>{this.browserPlugins.add(e)};createRequestHandler=(e,s)=>(this.apiRoutesRequestHandlers.set(e,s),e);clearRequestHandlersByPrefix=e=>{for(const s of this.apiRoutesRequestHandlers.keys())s.startsWith(e)&&this.apiRoutesRequestHandlers.delete(s)};registerServerPropsGetter=(e,s)=>(this.serverPropsGetters.set(e,s),e);registerPagePropsGetter=(e,s)=>{this.pagePropsGetters.set(e,s)};async writeRouteStaticData(e,s){const t=await this.resolveRouteStaticData(e,s,!1);t&&N(e.slug,t,this.outdir)}async resolveRouteStaticData(e,s,t){if(this.serverMode)return H(e.slug,this.outdir);const a={...this,contentDir:this.contentDir,parseMarkdoc:({input:c,context:d,resource:f})=>this.parseMarkdoc({input:c,context:d,deps:{routeSlugs:[e.slug]},resource:f})},r=await e.getStaticData?.(e,a)||{},o=new Set(this.routesDynamicComponents.get(e.slug)),l=this.routesSharedData.get(e.slug)||{};for(const c of Object.values(l)){const d=this.sharedDataMarkdocComponents.get(c);d&&d.forEach(p=>o.add(p));const f=this.sharedDataDeps.get(c);f&&f.forEach(p=>this.addRouteSharedData(e.slug,p,p))}const i=this.getGlobalConfig("seo"),n=r?.frontmatter||{};return{...r,frontmatter:{...n,seo:{...n?.seo,title:n?.seo?.title||await e.getNavText?.()}},props:{...r.props,dynamicMarkdocComponents:Array.from(o),metadata:{...r?.props?.metadata,...e.metadata},seo:{title:T,...i,...r.props?.seo},compilationErrors:this.compilationErrors},lastModified:t||!e.fsPath?null:await this.lifecycleContext?.fs.getLastModified(e.fsPath)}}addSsrComponents(e,s){if(!e?.length)return;const t=typeof e[0]=="string"?e.join(""):I(e);t&&(s==="head"?this.ssr.headTags.push(t):s==="preBody"?this.ssr.preBodyTags.push(t):this.ssr.postBodyTags.push(t))}clear=()=>{this.routesByFsPath.clear(),this.templates.clear(),this.newRoutes=[],this.routesBySlug.clear(),this.apiRoutes=[],this.middleware=[],this.routesSharedData.clear(),this.sharedDataDeps.clear(),this.sharedDataMarkdocComponents.clear(),this.routesDynamicComponents.clear(),this.routesPartials.clear(),this.config.redirects={},this.config.wildcardRedirectsTree={},this.config.directoryPermissions={},this.ssr={preBodyTags:[],postBodyTags:[],headTags:[]}};async toJson(){const e=[];for(const[t,a]of Object.entries(v))switch(a){case"map":const r=Array.from(this[t].entries());e.push([t,r]);break;case"object":t==="config"&&e.push([t,await this.getConfigWithEnvPlaceholders()]),e.push([t,this[t]]);break;default:throw new Error("Invalid format")}const s=Object.fromEntries(e);return s[E]=_.PLAN_GATES,s}static fromJson(e,s){const t=new P(s);for(const[r,o]of Object.entries(v))switch(o){case"map":t[r]=new Map(e[r]);break;case"object":if(r==="config"){t.setGlobalConfig(e[r]);break}t[r]=e[r];break;default:throw new Error("Invalid format")}t.config[m]=Z(t.config[m]||{});const a=e[E];return a&&G("PLAN_GATES",a),t}async getConfigWithEnvPlaceholders(){const e=JSON.parse(JSON.stringify(this.config));for(const s in this.replacedEnvVars){const{original:t}=this.replacedEnvVars[s],a=s.split(":"),r=a.pop(),{error:o,value:l}=R(e,a);if(o||!O(l)&&!Array.isArray(l)){await w.panicOnBuild(`Failed to replace env var with env name for ${s}`);continue}l[r]=t}return e}async reportUnsetEnvVars(){if(this.unsetEnvVars.size===0)return;const e=Array.from(this.unsetEnvVars).filter(t=>!Y.includes(t));if(e.length===0)return;const s=`Failed to resolve config. The following environment variables are not set: ${e.join(", ")}`;await w.panicOnBuildContentError(s)}}function Z(C){return M(C,e=>b.Ast.fromJSON(JSON.stringify(e)))}export{m as MARKDOC_PARTIALS_DATA_KEY,z as MARKDOC_PARTIALS_DEPS_KEY,P as Store,Ae as USER_DEFINED_API_FUNCTIONS_COUNTER_KEY};
|
|
@@ -9,6 +9,7 @@ import type { SearchDocument } from '../../types';
|
|
|
9
9
|
import type { RbacScopeItems, RedirectConfig, RedoclyConfig, ServerPropsContext, ServerPropsRequest, PageProps, PageStaticData, NavItem, ResolvedNavItem, Version, MdOptions, KvService } from '@redocly/config';
|
|
10
10
|
import type { LoaderFn } from '../fs';
|
|
11
11
|
import type { BundledDefinition } from '../../plugins/openapi-docs/load-definition';
|
|
12
|
+
import type { BundledDefinition as GraphqlBundledDefinition } from '../../plugins/graphql-docs/graphql-doc-loader';
|
|
12
13
|
import type { Cache } from '../../fs/cache';
|
|
13
14
|
import type { ContentFs } from '../../fs/content-fs';
|
|
14
15
|
import type { SearchEngine } from '../../plugins/search/engines/search-engine';
|
|
@@ -144,6 +145,7 @@ export type ProcessContentActions = {
|
|
|
144
145
|
addRouteSharedData(slug: string, dataKey: string, dataId: string): void;
|
|
145
146
|
addRouteSharedDataToAllLocales(slug: string, dataKey: string, dataId: string): void;
|
|
146
147
|
loadOpenApiDefinitions(context: LifecycleContext): Promise<BundledDefinition[]>;
|
|
148
|
+
loadGraphqlDefinitions(context: LifecycleContext): Promise<GraphqlBundledDefinition[]>;
|
|
147
149
|
setGlobalConfig: (data: Record<string, unknown>) => void;
|
|
148
150
|
setGlobalData: (data: GlobalData) => void;
|
|
149
151
|
getConfig: () => RedoclyConfig;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{KvService as l}from"../../persistence/kv/services/kv-service.js";import{DEFAULT_AUTHENTICATED_TEAM as
|
|
1
|
+
import{KvService as l}from"../../persistence/kv/services/kv-service.js";import{DEFAULT_AUTHENTICATED_TEAM as T}from"../../../constants/common.js";import{envConfig as s}from"../../config/env-config.js";import{CACHE_CONTROL_NO_STORE_HEADER_VALUE as h,JWT_SECRET_KEY as y}from"../../constants/common.js";import*as m from"../jwt/jwt.js";import{AlgorithmTypes as I}from"../jwt/types.js";const p=60,f=e=>["POST","PUT","DELETE","PATCH"].includes(e),E=e=>["GET"].includes(e);function R({serverOutDir:e,protectReadMethods:t=!0}){return async(r,a)=>await _(r,a,e,t)}const _=async(e,t,r,a=!0)=>{e.header("Cache-Control",h);const n=e.req.method,o=f(n)||E(n)&&a,i=e.req.header("apiKey");if(i)return await w(e,t,i,r);const u=e.req.header("authorization")?.replace("Bearer ","");return u?await C(e,t,u):o?e.json({message:"API key is required"},401):await t()},w=async(e,t,r,a)=>{if(!s.BH_API_URL||!s.ORGANIZATION_ID)return e.json({message:"API key validation service not configured"},500);try{const n=await l.getInstance({baseDbDir:a});let o=await g(n,r);if(o)return e.set("apiKeyTeams",o.teams),await t();const i=new URL(`/api/orgs/${s.ORGANIZATION_ID}/session`,s.BH_API_URL).toString(),c=await fetch(i,{method:"GET",headers:{Authorization:`Bearer ${r}`}});if(!c.ok)return e.json({message:"Invalid API key"},401);const A=(await c.json())?.user?.teams?.[s.ORGANIZATION_ID]??[],d=[T,...A];return e.set("apiKeyTeams",d),await n.set(["api-keys","reunite",r],{valid:!0,teams:d},{ttlInSeconds:p}),await t()}catch{return e.json({message:"API key validation failed"},400)}},C=async(e,t,r)=>{try{const a=await m.verify(r,y,I.HS256),n=m.decode(r).payload.isInternalConnection;return!a||!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{R as catalogAuthMiddleware};
|
|
@@ -1,9 +1,4 @@
|
|
|
1
1
|
import type { Hono } from 'hono';
|
|
2
2
|
import type { Store } from '../../../store';
|
|
3
|
-
/**
|
|
4
|
-
* Installs a single catch-all API route handler that dynamically looks up routes from Store.
|
|
5
|
-
*
|
|
6
|
-
* This enables hot-reload for API functions and mock server toggle without restart.
|
|
7
|
-
*/
|
|
8
3
|
export declare function installApiRoutes(router: Hono, store: Store): void;
|
|
9
4
|
//# sourceMappingURL=api-routes.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{TrieRouter as
|
|
1
|
+
import{TrieRouter as E}from"hono/router/trie-router";import{REDOCLY_ROUTE_RBAC as a}from"@redocly/config";import{withPathPrefix as _}from"@redocly/theme/core/utils";import{CACHE_CONTROL_NO_STORE_HEADER_VALUE as L}from"../../../constants/common.js";import{canAccessResource as O}from"../../../utils/rbac.js";import{handleUnauthorizedApiRequest as U}from"../../utils.js";import{handleApiRouteRequest as q}from"../../handle-api-route-request.js";import{sortApiFunctionRoutes as w}from"../../utils/sort-api-function-routes.js";function u(t){return t.headers.set("Cache-Control",L),t}function z(t,o){t.all("*",async(e,m)=>{const{method:h,path:r}=e.req,p=o.getAllApiRoutes(),R=w(p),i=new E;for(const c of R){const g=c.httpMethod?.toUpperCase()||"ALL",C=_(c.slug);i.add(g,C,c)}const s=i.match(h.toUpperCase(),r);if(!s||s[0].length===0)return m();const f=s[0],[n]=f[0],{isAuthenticated:l,claims:{email:A},teams:d}=e.get("auth");return O({...n,slug:r,[a]:{...n[a],slug:r}},{isAuthenticated:l,email:A,teams:d},o.config.access?.rbac,o.config.access?.requiresLogin)?u(await q(n,e,o)):u(U(e))})}export{z as installApiRoutes};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{CACHE_CONTROL_NO_STORE_HEADER_VALUE as i}from"../../constants/common.js";import{filterDataByAccessDeep as o}from"../../utils/rbac.js";function f(a){return async e=>{const{isAuthenticated:t,teams:c,claims:{email:n}}=e.get("auth"),r=o(a.getGlobalData(),{isAuthenticated:t,email:n,teams:c},a.config.access?.rbac,a.config.access?.requiresLogin);return e.json({...r},200,{"Cache-Control":i})}}export{f as appDataHandler};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import
|
|
1
|
+
import m from"path";import{REDOCLY_ROUTE_RBAC as U,REDOCLY_TEAMS_RBAC as b}from"@redocly/config";import{withoutPathPrefix as j,withPathPrefix as V}from"@redocly/theme/core/utils";import{CACHE_CONTROL_NO_STORE_HEADER_VALUE as M,CACHE_CONTROL_PUBLIC_HTML as W,DEFAULT_IMMUTABLE_CACHE_MAX_AGE as Z,X_REDOCLY_CACHE_CONTROL_HEADER as J,X_REDOCLY_CACHE_CONTROL_PUBLIC_HTML as K}from"../../constants/common.js";import{removeTrailingSlash as Q}from"../../../utils/url/remove-trailing-slash.js";import{findInIterable as x}from"../../../utils/collection/find-in-iterable.js";import{sanitizeRedirectPathname as ee}from"../../../utils/url/sanitize-redirect-pathname.js";import{envConfig as te}from"../../config/env-config.js";import{sanitizePath as ne}from"../../../utils/path/sanitize-path.js";import{normalizeRouteSlug as oe}from"../../../utils/path/normalize-route-slug.js";import{isPathInFolder as re}from"../../../utils/path/is-path-in-folder.js";import{getLlmsTxtMdPathBySlug as ae}from"../../utils/llmstxt/get-llms-txt-md-path-by-slug.js";import{removeLeadingSlash as D}from"../../../utils/url/remove-leading-slash.js";import{processRedirects as ie}from"./helpers/process-redirects.js";import{renderPage as se,getServerProps as ce}from"../../ssr/index.js";import{canAccessAsset as le,canAccessResource as H}from"../../utils/rbac.js";import{handleErrorPageRender as q,handleUnauthorized as v,handleUnauthorizedAsset as B}from"../utils.js";import{DEFAULT_MAX_AGE_FOR_MIME_TYPE as me,MIME_TYPES as ue}from"../mime-types.js";import{fileExistsAsync as F}from"../../utils/index.js";import{isAiAgentRequest as de}from"../../utils/ai-agent-detection.js";import{getRedirectRoute as ge}from"../utils/legacy-openapi-redirects.js";import{getContentTypeHeaderValue as fe}from"../utils/content-type.js";import{telemetry as pe}from"../../../cli/telemetry/index.js";import{telemetry as he}from"../../telemetry/index.js";function Xe(e,z,Y){return async n=>{const R=n.get("logger"),a=n.req,i=new URL(a.url),r=j(ne(decodeURIComponent(i.pathname))),A=m.parse(r).ext===".md",E=de({accept:a.header("accept"),signatureAgent:a.header("signature-agent"),signature:a.header("signature"),signatureInput:a.header("signature-input"),userAgent:a.header("user-agent")}),l=oe(r),o=(a.method==="GET"||a.method==="HEAD")&&!A?e.getRouteBySlug(l,{followRedirect:!1})||x(e.routesBySlug?.values(),t=>t.hasClientRoutes&&(r===t.slug||r.startsWith(t.slug+"/"))):void 0,L=e.getRedirect(l);if(L){const t=ie({redirect:L,reqUrlSearch:i.search});return he.sendRedirectMessage([{object:"redirect",from:l,templateId:t.type.toString()}]),n.newResponse(null,t.type,{Location:t.location})}const f=te.isProductionEnv?301:302;if(o?.metadata?.type==="openapi"){const t=ge(i.pathname);if(t)return R.info("Legacy OpenAPI docs redirect from "+i.pathname),n.newResponse(null,f,{Location:encodeURI(t)});if(i.pathname.match(/[A-Z]/))return R.warn("Redirect to lowercase route to avoid 404 error"),n.newResponse(null,f,{Location:encodeURI(i.pathname.toLowerCase())})}if(r.endsWith("/")&&r!=="/"){const t=ee(new URL(l||"/",n.req.url).pathname);return n.newResponse(null,f,{Location:encodeURI(V((t==="/"?"/":Q(t))+i.search))})}const u=o&&E?ae(o.slug):void 0,_=u?await F(m.resolve(e.outdir,D(u))):!1,{isAuthenticated:d,teams:p,claims:{email:h}}=n.get("auth");if(o&&!H(o,{isAuthenticated:d,email:h,teams:p},e.config.access?.rbac,e.config.access?.requiresLogin))return d?q(n,e,{slug:o.slug,[b]:o[b],[U]:o[U]},403):v(n,e,o.slug);if(o&&(!E||!_)){const t=await z(o),c=await ce(o,n,t,e),{html:X,statusCode:y,error:k}=await se(o,c,n,e,pe),O=e.config.access?.rbac,I=!e.config.access?.requiresLogin&&(!O||!Object.keys(O).length),S=y>=400||!!k||!!e.compilationErrors?.length,$=I&&!S;let g;return S?g=M:I?g=W:g="private",n.html(X,y,{"Cache-Control":g,...$&&{[J]:K}})}const w=u&&_?u:r,G=D(w),s=m.resolve(e.outdir,G);if(!re(s,e.outdir))return B(n);if(A){const t=r==="index.html.md"?"/":r.replace(/\.md$/,""),c=e.getRouteBySlug(t,{followRedirect:!1});if(c&&!H(c,{isAuthenticated:d,email:h,teams:p},e.config.access?.rbac,e.config.access?.requiresLogin))return v(n,e,r)}const P=e.getGlobalConfig("access");if(!le(w,P?.rbac||{},P?.requiresLogin||!1,e.getGlobalConfig("directoryPaths"),{isAuthenticated:d,email:h,teams:p}))return B(n);const T=ue[m.extname(s)]||"text/plain",C=s.match(/assets\/.*\.[a-f0-9]{8,}\..+/)||s.match(/runtime\/chunks\/.*/)?Z:me[T],N=C?{"Cache-Control":`public, max-age=${C}, immutable`,Expires:new Date(Date.now()+C*1e3).toUTCString()}:{"Cache-Control":M};if(await F(s)){const t=a.query("download")!=null,c=await Y(s);return n.newResponse(c,200,{"Content-Type":fe(T),"Access-Control-Allow-Origin":"*",...N,...t&&{"Content-Disposition":`attachment; filename="${m.basename(s)}"`}})}else return q(n,e,{slug:l},404)}}export{Xe as dynamicRouteHandler};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{DEV_LOGIN_SLUG as
|
|
1
|
+
import{DEV_LOGIN_SLUG as O,ServerRoutes as U}from"../../../constants/common.js";import{CACHE_CONTROL_NO_STORE_HEADER_VALUE as a,DEFAULT_TITLE as $}from"../../constants/common.js";import{findInIterable as F}from"../../../utils/collection/find-in-iterable.js";import{removeTrailingSlash as N}from"../../../utils/url/remove-trailing-slash.js";import{envConfig as S}from"../../config/env-config.js";import{canAccessResource as q,filterDataByAccessDeep as b,isResourcePubliclyAccessible as B}from"../../utils/rbac.js";import{getServerProps as H}from"../../ssr/index.js";import{readSharedData as G}from"../../utils/index.js";import{getRedirectLoginUrl as M}from"../utils/get-redirect-login-url.js";import{processRedirects as V}from"./helpers/process-redirects.js";import{removeErrorDetails as k}from"../utils/remove-error-details.js";import{telemetry as K}from"../../telemetry/index.js";function ae(e,s){return async(t,p)=>{const l=t.get("logger"),{req:u}=t,{pathname:d}=new URL(u.url),{seo:f,ssoDirect:h}=e.getConfig(),i=f?.title||$;if(e?.compilationErrors?.length&&S.isDevelopMode)return t.json({templateId:"compilation-error",props:{compilationErrors:e?.compilationErrors},sharedDataIds:{}},500,{"Cache-Control":a});const g=d.match(/page-data(.*)data.json$/);if(!g)return p();const c=decodeURI(g[1]),n=c==="/index/"?"/":N(c),o=e.getRouteBySlug(n,{followRedirect:!1})||F(e.routesBySlug.values(),r=>r.hasClientRoutes&&c.startsWith(r.slug+"/"));if(c===U.OIDC_CALLBACK+"/")return t.json({templateId:"403OIDC",sharedDataIds:{},props:{seo:{title:`${i} - Forbidden`}}},200,{"Cache-Control":a});const{isAuthenticated:C,teams:D,claims:{name:j,picture:v,email:I}}=t.get("auth"),R={isAuthenticated:C,email:I,teams:D},m={isAuthenticated:C,name:j,picture:v,email:I,teams:D},L=e.getRedirect(n);if(L){const r=V({redirect:L}).location;return K.sendRedirectMessage([{object:"redirect",from:n,templateId:"404"}]),t.json({templateId:"404",redirectTo:r,sharedDataIds:{},props:{}},301,{"Cache-Control":a})}if(!o){const r=e.getRouteBySlug(n,{followRedirect:!0});return l.error(`Page not found: ${d}`),t.json({templateId:"404",redirectTo:r?.slug,sharedDataIds:{},props:{seo:{title:`${i} - Not Found`}},userData:m},404,{"Cache-Control":a})}if(l.verbose(`Page viewed: ${o.slug}`),!q(o,R,e.config.access?.rbac,e.config.access?.requiresLogin)&&o.slug!==O){if(C)return t.json({templateId:"403",sharedDataIds:{},props:{seo:{title:`${i} - Forbidden`}},userData:m},403,{"Cache-Control":a});const r=Object.keys(h||{}).length>0;return t.json({templateId:"404",sharedDataIds:{},props:{seo:{title:`${i} - Not Found`}},userData:m,...r?{redirectTo:M(e,o.slug)}:{}},r?401:404,{"Cache-Control":a})}const A=b(o.versions,R,e.config.access?.rbac,e.config.access?.requiresLogin),T=e.routesSharedData.get(o.slug)||{},P=await s(o),y=await H(o,t,P,e),{sharedDataIds:_,...E}=y,w={templateId:o.templateId,versions:A,sharedDataIds:{...T,..._||{}},props:S.isProductionEnv?k(E):E,slug:o.slug,userData:m,isPublic:B(o,e.config)};return t.json(w,200,{"Cache-Control":a})}}function se(e){return async(s,t)=>{const p=s.get("logger"),{req:l}=s,{pathname:u}=new URL(l.url),d=u.match(/\/page-data\/shared\/(.*)\.json/);if(!d)return t();const f=decodeURIComponent(d[1]),h=await G(f,e.outdir),{isAuthenticated:i,teams:g,claims:{email:c}}=s.get("auth"),n=b(h,{isAuthenticated:i,email:c,teams:g},e.config.access?.rbac,e.config.access?.requiresLogin);return n?s.json(n,200,{"Cache-Control":a}):(p.error(`Shared data not found: ${u}`),s.text("Not Found",404,{"Cache-Control":a}))}}export{ae as pageDataHandler,se as sharedPageDataHandler};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{telemetryTraceStep as
|
|
1
|
+
import{telemetryTraceStep as C}from"../../telemetry/helpers/trace-step.js";import{CACHE_CONTROL_NO_STORE_HEADER_VALUE as T}from"../../constants/common.js";import{expandTeamsForRead as E}from"../../utils/rbac.js";function F(e){return async t=>(t.header("Cache-Control",T),await C("search",async s=>{const u=t.get("logger"),o=t.get("auth"),A=u.startTiming(),a=e.getConfig().access?.requiresLogin&&!o.isAuthenticated,r={...await t.req.json(),auth:{...o,teams:E(e.config.access?.rbac,o.teams)}};s?.setAttribute("engine",e?.searchEngine?.type),s?.setAttribute("query",r.query||""),s?.setAttribute("user",r.auth.claims.email??"anonymous"),s?.setAttribute("noAccess",a);const g=e.getSearchFacets(),i=a?{}:e.searchEngine?await e.searchEngine.search(r,g):{};let h=0;if(Object.keys(i).length){const f=i.documents;for(const[c,n]of Object.entries(f))h+=n.length}return u.infoTime(A,`Search with query "${r.query||""}". Total results: ${h}`),s?.setAttribute("resultsCount",h),t.json(i)}))}function j(e){return async t=>(t.header("Cache-Control",T),await C("search.facets",async s=>{const u=t.get("logger"),o=t.get("auth"),m=e.getConfig().access?.requiresLogin&&!o.isAuthenticated,a={...await t.req.json(),auth:o};s?.setAttribute("engine",e?.searchEngine?.type),s?.setAttribute("user",a.auth.claims.email??"anonymous"),s?.setAttribute("noAccess",m);const r=u.startTiming(),g=e.getSearchFacets(),i=m?{}:e.searchEngine?await e.searchEngine.countFacets(a,g):{},h=!!a.field;let f=[];if(h){const c=a.field,n=c&&g.get(c);if(n){const l={...n};l.values=i?.[c]||[],f.push(l)}}else{const c=new Map;for(const[n,l]of g){const y=i?.[n],d={...l};d.values=y||l.values.map(b=>({value:b,count:0})),c.set(n,d)}f=Array.from(c,([,n])=>n)}return u.verboseTime(r,"Search facets"),t.json(f)}))}export{j as searchFacetsHandler,F as searchHandler};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{setCookie as
|
|
1
|
+
import{setCookie as E}from"hono/cookie";import{withPathPrefix as l}from"@redocly/theme/core/utils";import{DEV_LOGIN_SLUG as b}from"../../constants/common.js";import{CACHE_CONTROL_NO_STORE_HEADER_VALUE as A}from"../constants/common.js";import{getAuthProviderLoginParams as y,buildLoginUrl as C}from"./auth.js";import{renderPage as O}from"../ssr/index.js";import{telemetry as R}from"../../cli/telemetry/index.js";async function T(r,t,o,n){const{isAuthenticated:a}=r.get("auth"),e=r.req.raw.headers.get("x-forwarded-host"),i=r.req.raw.headers.get("x-forwarded-proto"),U=e?`${i==="http"||i==="https"?i:"https"}://${e}`:new URL(r.req.url).origin,u=t.getConfig().ssoDirect,p=Object.keys(u||{}),s=n||p[0],g=u?.[s];if(a)return _(r,t,{slug:o},403);const d=s&&g?await y(s,g):void 0,m=d?{...d,extraParams:{...d.extraParams,prompt:"login"}}:void 0,{loginUrl:w,cookies:h={}}=m&&C(m,U,l(o))||{},f=t.globalData.auth?.devLogin||p.length>1?v(o):w;return Object.keys(h).forEach(c=>{E(r,c,h[c].value,h[c].options)}),f?r.newResponse(null,302,{Location:f}):r.text("Unauthorized",401)}const L={};async function _(r,t,o,n,a){let e=L[n];if(!e){const i={templateId:String(a||n),fsPath:"/",...o,baseSlug:o.slug};e=(await O(i,{},r,t,R)).html,L[n]=e}return r.html(e,n,{"Cache-Control":A})}function v(r){const t=new URLSearchParams({redirectTo:l(r)});return`${l(b)}?${t}`}async function j(r){return r.text("Forbidden",P(r))}function k(r){return r.json({message:"Forbidden"},P(r))}function P(r){const{isAuthenticated:t}=r.get("auth");return t?403:401}function G(r){const t=r?.match(/(?:^|:)(\d{1,3}(?:\.\d{1,3}){3})$/);return t?t[1]:r}export{v as getLoginUrlWithRedirect,_ as handleErrorPageRender,T as handleUnauthorized,k as handleUnauthorizedApiRequest,j as handleUnauthorizedAsset,G as normalizeIpAddress};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@redocly/realm",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.135.0-next.1",
|
|
4
4
|
"description": "",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -91,14 +91,14 @@
|
|
|
91
91
|
"xpath": "0.0.34",
|
|
92
92
|
"yaml-ast-parser": "0.0.43",
|
|
93
93
|
"zod": "^3.25.76",
|
|
94
|
-
"@redocly/
|
|
95
|
-
"@redocly/asyncapi-docs": "1.11.0",
|
|
96
|
-
"@redocly/portal-legacy-ui": "0.17.0",
|
|
97
|
-
"@redocly/portal-plugin-mock-server": "0.19.0",
|
|
98
|
-
"@redocly/graphql-docs": "1.11.0",
|
|
94
|
+
"@redocly/asyncapi-docs": "1.12.0-next.1",
|
|
99
95
|
"@redocly/config": "0.49.0",
|
|
100
|
-
"@redocly/
|
|
101
|
-
"@redocly/
|
|
96
|
+
"@redocly/graphql-docs": "1.12.0-next.1",
|
|
97
|
+
"@redocly/openapi-docs": "3.23.0-next.1",
|
|
98
|
+
"@redocly/portal-legacy-ui": "0.18.0-next.0",
|
|
99
|
+
"@redocly/portal-plugin-mock-server": "0.20.0-next.1",
|
|
100
|
+
"@redocly/realm-asyncapi-sdk": "0.13.0-next.0",
|
|
101
|
+
"@redocly/theme": "0.67.0-next.1"
|
|
102
102
|
},
|
|
103
103
|
"peerDependencies": {
|
|
104
104
|
"react": "^19.2.4",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{resolveParameters as h,resolveRequestBody as v,resolveResponses as x}from"../utils.js";import{isMcpEndpoint as E}from"./utils.js";import{loadApiDescription as g}from"./helpers/load-api-description.js";import{checkEndpointAndDeleteXMcp as P}from"../../utils/xmcp-utils.js";const S=async(s,i)=>{const{name:p,path:o,method:n,version:a}=s;let t;try{t=await g(p,i,a)}catch(y){return{content:[{type:"text",text:y.message}],isError:!0}}const c=o.startsWith("/")?o:`/${o}`,{title:d=""}=t.info||{},r=t.paths?.[c],m=n.toLowerCase();if(!r)return{content:[{type:"text",text:"Endpoint not found"}],isError:!0};const e=r[m];if(!E(e)||!P(e,"docs"))return{content:[{type:"text",text:"Endpoint not found"}],isError:!0};const u=r?.parameters||[],l=e.parameters||[],f={...e,parameters:h({pathParams:u,opParams:l,definition:t}),requestBody:v(e.requestBody,t),responses:x(e.responses,t)};return{content:[{type:"text",text:JSON.stringify({api:d,version:t.info?.version||"",servers:t.servers||[],endpoint:{path:o,method:n.toUpperCase(),...f},globalSecurity:t.security||[],securitySchemes:t.components?.securitySchemes||[]},null,2)}]}};var M={"get-endpoint-info":S};export{M as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{loadApiDescription as p}from"./helpers/load-api-description.js";import{getEndpointsFromPaths as c}from"./utils.js";const a=async(n,r)=>{const{name:o,version:i}=n;let t;try{t=await p(o,r,i)}catch(s){return{content:[{type:"text",text:s.message}],isError:!0}}const e=c(t);return e.length===0?{content:[{type:"text",text:"No endpoints found"}]}:{content:[{type:"text",text:JSON.stringify({api:t.info?.title||"",version:t.info?.version||"",servers:t.servers||[],endpoints:e},null,2)}]}};var l={"get-endpoints":a};export{l as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{loadApiDescription as s}from"./helpers/load-api-description.js";const p=async(e,i)=>{const{name:n,version:r}=e;let t;try{t=await s(n,i,r)}catch(o){return{content:[{type:"text",text:o.message}],isError:!0}}return{content:[{type:"text",text:JSON.stringify({api:t.info?.title||"",version:t.info?.version||"",definition:t},null,2)}]}};var a={"get-full-api-description":p};export{a as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{loadApiDescription as c}from"./helpers/load-api-description.js";const o=async(t,r)=>{const{name:s,version:i}=t;let e;try{e=await c(s,r,i)}catch(n){return{content:[{type:"text",text:n.message}],isError:!0}}return{content:[{type:"text",text:JSON.stringify({name:e.info?.title,version:e.info?.version,securitySchemes:e.components?.securitySchemes||[],security:e.security||[]},null,2)}]}};var y={"get-security-schemes":o};export{y as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{findApiDescriptionByNameAndVersion as t}from"../../utils.js";import{getApiDescriptionFromFs as a}from"../utils.js";async function u(r,i,s){const o=t(i.apiDescriptionsMap,r,s);if(!o)throw new Error(`No API found matching "${r}".`);const e=!!i?.config?.access?.requiresLogin,c=i?.config?.access?.rbac||{},n=await a({relativePath:o.relativePath||"",outdir:i.outdir||"",user:i.user,rbac:c,requiresLogin:e});if(!n)throw new Error(`No API found matching "${r}".`);return n}export{u as loadApiDescription};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{filterApiDescriptionsByName as f}from"../utils.js";const x=async(a,l)=>{const{filter:i,page:n=1,limit:e=300}=a;let t=Object.values(l.apiDescriptionsMap);i&&(t=f(t,i));const s=(n-1)*e,o=s+e,r=Math.ceil(t.length/e),c=t.length;return t=t.slice(s,o),t.length===0?{content:[{type:"text",text:"No APIs available"}]}:{content:[{type:"text",text:JSON.stringify({items:t.map(({relativePath:g,...p})=>p),limit:e,total:c,page:n,totalPages:r})}]}};var m={"list-apis":x};export{m as default};
|