@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.
Files changed (88) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/dist/client/app/Link.d.ts +1 -1
  3. package/dist/client/app/Link.js +1 -1
  4. package/dist/client/app/Sidebar/RequestAccessButton.js +2 -2
  5. package/dist/client/app/hooks/useLoginUrl.js +1 -1
  6. package/dist/client/app/hooks/useScrollTracker.js +1 -1
  7. package/dist/client/app/markdoc/custom-components/openapi/json-schema.d.ts +1 -0
  8. package/dist/client/app/markdoc/custom-components/openapi/json-schema.js +1 -1
  9. package/dist/client/app/search/useAiSearch.js +1 -1
  10. package/dist/client/app/utils/programmatic-scroll.d.ts +22 -0
  11. package/dist/client/app/utils/programmatic-scroll.js +1 -0
  12. package/dist/markdoc/helpers/get-inner-text.js +2 -2
  13. package/dist/markdoc/tags/json-schema.js +1 -1
  14. package/dist/server/constants/common.d.ts +4 -1
  15. package/dist/server/constants/common.js +1 -1
  16. package/dist/server/plugins/catalog-entities/database/remote-publish-lock-service.js +1 -1
  17. package/dist/server/plugins/graphql-docs/graphql-doc-loader.d.ts +5 -0
  18. package/dist/server/plugins/graphql-docs/graphql-doc-loader.js +1 -1
  19. package/dist/server/plugins/graphql-docs/index.js +1 -1
  20. package/dist/server/plugins/markdown/search/to-markdown.js +14 -14
  21. package/dist/server/plugins/mcp/docs-mcp/tool-schemas.d.ts +1 -0
  22. package/dist/server/plugins/mcp/docs-mcp/tool-schemas.js +1 -1
  23. package/dist/server/plugins/mcp/docs-mcp/tools/core/search.d.ts +6 -0
  24. package/dist/server/plugins/mcp/docs-mcp/tools/core/search.js +6 -0
  25. package/dist/server/plugins/mcp/docs-mcp/tools/core/utils.d.ts +3 -0
  26. package/dist/server/plugins/mcp/docs-mcp/tools/core/utils.js +11 -0
  27. package/dist/server/plugins/mcp/docs-mcp/tools/core/whoami.d.ts +6 -0
  28. package/dist/server/plugins/mcp/docs-mcp/tools/graphql/get-graphql-schema.d.ts +8 -0
  29. package/dist/server/plugins/mcp/docs-mcp/tools/graphql/get-graphql-schema.js +3 -0
  30. package/dist/server/plugins/mcp/docs-mcp/tools/graphql/get-graphql-type-list.d.ts +14 -0
  31. package/dist/server/plugins/mcp/docs-mcp/tools/graphql/get-graphql-type-list.js +1 -0
  32. package/dist/server/plugins/mcp/docs-mcp/tools/graphql/get-graphql-type.d.ts +10 -0
  33. package/dist/server/plugins/mcp/docs-mcp/tools/graphql/get-graphql-type.js +7 -0
  34. package/dist/server/plugins/mcp/docs-mcp/tools/graphql/list-graphql-apis.d.ts +10 -0
  35. package/dist/server/plugins/mcp/docs-mcp/tools/graphql/list-graphql-apis.js +1 -0
  36. package/dist/server/plugins/mcp/docs-mcp/tools/graphql/load-graphql-schema.d.ts +7 -0
  37. package/dist/server/plugins/mcp/docs-mcp/tools/graphql/load-graphql-schema.js +1 -0
  38. package/dist/server/plugins/mcp/docs-mcp/tools/graphql/tool-helpers.d.ts +14 -0
  39. package/dist/server/plugins/mcp/docs-mcp/tools/graphql/tool-helpers.js +1 -0
  40. package/dist/server/plugins/mcp/docs-mcp/tools/graphql/types.d.ts +10 -0
  41. package/dist/server/plugins/mcp/docs-mcp/tools/graphql/types.js +1 -0
  42. package/dist/server/plugins/mcp/docs-mcp/tools/graphql/utils.d.ts +16 -0
  43. package/dist/server/plugins/mcp/docs-mcp/tools/graphql/utils.js +3 -0
  44. package/dist/server/plugins/mcp/docs-mcp/tools/index.d.ts +28 -7
  45. package/dist/server/plugins/mcp/docs-mcp/tools/index.js +1 -1
  46. package/dist/server/plugins/mcp/docs-mcp/tools/{get-endpoint-info.d.ts → openapi/get-endpoint-info.d.ts} +1 -1
  47. package/dist/server/plugins/mcp/docs-mcp/tools/openapi/get-endpoint-info.js +1 -0
  48. package/dist/server/plugins/mcp/docs-mcp/tools/{get-endpoints.d.ts → openapi/get-endpoints.d.ts} +1 -1
  49. package/dist/server/plugins/mcp/docs-mcp/tools/openapi/get-endpoints.js +1 -0
  50. package/dist/server/plugins/mcp/docs-mcp/tools/{get-full-api-description.d.ts → openapi/get-full-api-description.d.ts} +1 -1
  51. package/dist/server/plugins/mcp/docs-mcp/tools/openapi/get-full-api-description.js +1 -0
  52. package/dist/server/plugins/mcp/docs-mcp/tools/{get-security-schemes.d.ts → openapi/get-security-schemes.d.ts} +1 -1
  53. package/dist/server/plugins/mcp/docs-mcp/tools/openapi/get-security-schemes.js +1 -0
  54. package/dist/server/plugins/mcp/docs-mcp/tools/{list-apis.d.ts → openapi/list-apis.d.ts} +1 -1
  55. package/dist/server/plugins/mcp/docs-mcp/tools/openapi/list-apis.js +1 -0
  56. package/dist/server/plugins/mcp/docs-mcp/tools/openapi/load-api-description.js +1 -0
  57. package/dist/server/plugins/mcp/docs-mcp/tools/{utils.d.ts → openapi/utils.d.ts} +1 -3
  58. package/dist/server/plugins/mcp/docs-mcp/tools/openapi/utils.js +1 -0
  59. package/dist/server/plugins/mcp/handlers/docs-mcp-handler.js +1 -1
  60. package/dist/server/plugins/mcp/index.js +1 -1
  61. package/dist/server/plugins/mcp/servers/docs-server.js +1 -1
  62. package/dist/server/plugins/mcp/types.d.ts +7 -0
  63. package/dist/server/plugins/mcp/utils.d.ts +7 -17
  64. package/dist/server/plugins/mcp/utils.js +1 -1
  65. package/dist/server/store.d.ts +2 -0
  66. package/dist/server/store.js +1 -1
  67. package/dist/server/types/plugins/common.d.ts +2 -0
  68. package/dist/server/web-server/middleware/catalogAuthMiddleware.js +1 -1
  69. package/dist/server/web-server/routes/api-routes/api-routes.d.ts +0 -5
  70. package/dist/server/web-server/routes/api-routes/api-routes.js +1 -1
  71. package/dist/server/web-server/routes/app-data.js +1 -1
  72. package/dist/server/web-server/routes/dynamic-route.js +1 -1
  73. package/dist/server/web-server/routes/page-data.js +1 -1
  74. package/dist/server/web-server/routes/search.js +1 -1
  75. package/dist/server/web-server/utils.js +1 -1
  76. package/package.json +8 -8
  77. package/dist/server/plugins/mcp/docs-mcp/tools/get-endpoint-info.js +0 -1
  78. package/dist/server/plugins/mcp/docs-mcp/tools/get-endpoints.js +0 -1
  79. package/dist/server/plugins/mcp/docs-mcp/tools/get-full-api-description.js +0 -1
  80. package/dist/server/plugins/mcp/docs-mcp/tools/get-security-schemes.js +0 -1
  81. package/dist/server/plugins/mcp/docs-mcp/tools/helpers/load-api-description.js +0 -1
  82. package/dist/server/plugins/mcp/docs-mcp/tools/list-apis.js +0 -1
  83. package/dist/server/plugins/mcp/docs-mcp/tools/search.d.ts +0 -6
  84. package/dist/server/plugins/mcp/docs-mcp/tools/search.js +0 -6
  85. package/dist/server/plugins/mcp/docs-mcp/tools/utils.js +0 -11
  86. package/dist/server/plugins/mcp/docs-mcp/tools/whoami.d.ts +0 -6
  87. /package/dist/server/plugins/mcp/docs-mcp/tools/{whoami.js → core/whoami.js} +0 -0
  88. /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-endpoints': import("../../types.js").McpToolHandler<{
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
- 'get-security-schemes': import("../../types.js").McpToolHandler<{
17
- name: string;
18
- version?: string;
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-apis': import("../../types.js").McpToolHandler<{
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
- search: import("../../types.js").McpToolHandler;
26
- whoami: import("../../types.js").McpToolHandler;
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 o from"./list-apis.js";import r from"./get-endpoints.js";import t from"./get-endpoint-info.js";import i from"./get-security-schemes.js";import m from"./get-full-api-description.js";import p from"./search.js";import e from"./whoami.js";var d={...o,...r,...t,...i,...m,...p,...e};export{d as default};
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};
@@ -1,4 +1,4 @@
1
- import type { McpToolHandler } from '../../types.js';
1
+ import type { McpToolHandler } from '../../../types.js';
2
2
  declare const _default: {
3
3
  'get-endpoint-info': McpToolHandler<{
4
4
  name: string;
@@ -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};
@@ -1,4 +1,4 @@
1
- import type { McpToolHandler } from '../../types.js';
1
+ import type { McpToolHandler } from '../../../types.js';
2
2
  declare const _default: {
3
3
  'get-endpoints': McpToolHandler<{
4
4
  name: string;
@@ -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};
@@ -1,4 +1,4 @@
1
- import type { McpToolHandler } from '../../types.js';
1
+ import type { McpToolHandler } from '../../../types.js';
2
2
  declare const _default: {
3
3
  'get-full-api-description': McpToolHandler<{
4
4
  name: string;
@@ -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};
@@ -1,4 +1,4 @@
1
- import type { McpToolHandler } from '../../types.js';
1
+ import type { McpToolHandler } from '../../../types.js';
2
2
  declare const _default: {
3
3
  'get-security-schemes': McpToolHandler<{
4
4
  name: string;
@@ -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};
@@ -1,4 +1,4 @@
1
- import type { McpToolHandler } from '../../types.js';
1
+ import type { McpToolHandler } from '../../../types.js';
2
2
  declare const _default: {
3
3
  'list-apis': McpToolHandler<{
4
4
  filter?: string;
@@ -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 '../../types';
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 C,toReqRes as S}from"fetch-to-node";import{logger as m}from"../../../tools/notifiers/logger.js";import{isObject as b}from"../../../../utils/guards/is-object.js";import{createDocsMcpServer as N}from"../servers/docs-server.js";import{filterApiDescriptionsByRbac as k}from"../utils.js";import{createMethodNotAllowedError as O,withErrorHandling as U}from"./errors.js";import{attachSseKeepalive as E}from"./sse-keepalive.js";import{McpServerType as H}from"../constants.js";import{constructInvalidTokenResponse as I,constructUnauthorizedResponse as j,handleMcpAuth as L,shouldHandleMcpAuth as J}from"../auth/auth-handlers.js";import{extractTokenFromAuthHeader as P}from"../utils/jwt.js";const d="X-Redocly-AI-Metadata";function $(r){if(r)try{const e=JSON.parse(r);if(b(e))return e;m.warn(`Ignoring ${d} header: not a JSON object.`)}catch{m.warn(`Ignoring ${d} header: invalid JSON.`)}}const z=async(r,e,h)=>{const u=!!e?.config?.access?.requiresLogin,f=e?.config?.access?.rbac||{};let s;const l=r.headers.get("Authorization");if(J(u,f)){const{isAuthenticated:t,isTokenValid:a,currentUser:n,accessToken:i}=await L(r,e);if(!t)return j(new URL(r.url).origin);if(!a)return I();n&&(e.user=n),s=i}else l&&(s=P(l||"")??void 0);let o;const g=async()=>{o&&(await o.cleanup(),o=void 0)};return await U(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 O();const t=h,a=t?.props?.config?.apiDescriptionsMap||{},n=t?.props?.config?.mcpDocsServerName||"Docs MCP server",{config:{mcp:i={}}}=e,M=k(a,e.user,f,u),A=e.config.products?Object.values(e.config.products).map(p=>p?.name):[],R=i.docs?.name||n,w=$(r.headers.get(d)),y=t?.props?.tools||[];o=await N({name:R,tools:y,context:{...e,accessToken:s,outdir:e.outdir||"",baseUrl:e.baseUrl||new URL(r.url).origin,apiDescriptionsMap:M,products:A,metadata:w}});const D=await r.json(),{req:T,res:c}=S(r),v=E(c);try{await o.transport.handleRequest(T,c,D)}catch(p){throw v.stop(),p}return C(c)},H.Docs,g)};var Z=z;export{Z as default};
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 y}from"node:url";import{dirname as S,join as m}from"node:path";import{logger as f}from"../../tools/notifiers/logger.js";import{reporter as b}from"../../tools/notifiers/reporter.js";import{isDefined as R}from"../../../utils/guards/is-defined.js";import{filterIgnoredApiDescriptions as w,getCleanedUpApiDescriptions as O,isMcpInRedirects as A}from"./utils.js";import{getDefaultToolSchemas as T}from"./docs-mcp/tool-schemas.js";import{telemetryTraceStep as j}from"../../../cli/telemetry/helpers/trace-step.js";const l="mcp-docs-server-handler",u=S(y(import.meta.url));async function E(){let e=!1;return{id:"mcp",async processContent(r,o){e||await j("build.plugin.mcp",async c=>{const t=await r.loadOpenApiDefinitions(o),n=await o.getConfig(),{mcp:s,redirects:g}=n;if(c?.setAttribute("config",JSON.stringify(s||{})),!(s?.hide||s?.docs?.hide)&&(A(g)&&await b.panicOnBuildContentError('The reserved route "/mcp" cannot be used in redirect configuration. Please remove any redirects involving "/mcp" from your redocly.yaml config.'),!s?.docs?.hide)){f.info("Configuring MCP servers...");const D=m(u,"./handlers/docs-mcp-handler.js"),h=O(w(t,s?.docs?.ignore||[])),a=new Map;for(const i of h){const p=i.definition.info?.title||"",d=i.definition.info?.version||"";a.set(`${p.toLowerCase()}@${d}`,{name:p,description:i.definition.info?.description||"",version:d,servers:i.definition.servers||[],relativePath:i.relativePath})}const v=Object.values(n.products||{}).map(i=>i?.name).filter(R),C=!!n?.access?.requiresLogin,M=n?.access?.rbac||{},P=T({products:v,requiresLogin:C,rbac:M});r.addMcpTools(m(u,"./docs-mcp/tools/index.js"),P),await L({actions:r,handlerPath:D,apiDescriptionsMap:Object.fromEntries(a),mcpConfig:s}),e=!0}})},async afterRoutesCreated(r,o){const c=await o.getConfig(),{mcp:t}=c;r.setGlobalData({mcpData:{docs:{enabled:!t?.hide&&!t?.docs?.hide,name:t?.docs?.name}}})}}}var B=E;async function L({actions:e,handlerPath:r,apiDescriptionsMap:o,mcpConfig:c}){e.createRequestHandler(l,r),e.addApiRoute({slug:"/mcp",requestHandlerId:l,httpMethod:"all",getStaticData:async()=>({props:{config:{apiDescriptionsMap:o,mcpDocsServerName:c?.docs?.name||"Docs MCP Server"},serverOutDir:e.serverOutDir,tools:e.getMcpTools().map(({importPath:t,...n})=>n)}})}),f.info("Registered Docs MCP Server endpoint at /mcp")}export{l as MCP_DOCS_SERVER_HANDLER_ID,B as default,E as mcpServerPlugin};
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 b}from"@redocly/mcp-typescript-sdk/server/mcp.js";import{StreamableHTTPServerTransport as g}from"@redocly/mcp-typescript-sdk/server/streamableHttp.js";import{logger as n}from"../../../tools/notifiers/logger.js";import{mcpToolWorkers as c,MCP_TOOL_WORKER_KEY as S,MCP_TOOL_IS_AVAILABLE_KEY as _}from"../../../workers/mcp-tool-worker-pool.js";async function w({name:e,tools:l,context:m}){const a=new b({name:e,version:new Date().toISOString().slice(0,10)},{capabilities:{logging:{}}}),t=new g({sessionIdGenerator:void 0}),i=M(m);for(const o of l){const u=async(r,d)=>{n.info(`MCP tool called: ${o.name}`);const I={toolName:o.name,args:r,context:i,extra:q(d)};return await c.exec(S,[I],{timeout:6e4})},f=a.tool(o.name,o.description,o.schema,u),p={toolName:o.name,context:i};let s=!1;try{s=await c.exec(_,[p],{timeout:1e4})}catch(r){n.error(`Failed to check MCP tool availability for "${o.name}": ${r instanceof Error?r.message:String(r)}`),s=!1}s||f.disable()}return await a.connect(t),{server:a,transport:t,cleanup:async()=>{t.close()}}}function q(e){return{sessionId:e.sessionId,authInfo:e.authInfo,requestId:e.requestId,requestInfo:e.requestInfo,_meta:e._meta}}function M(e){return{user:e.user,config:e.config,outdir:e.outdir,baseUrl:e.baseUrl,params:e.params,query:e.query,cookies:e.cookies,apiDescriptionsMap:e.apiDescriptionsMap,products:e.products,accessToken:e.accessToken,metadata:e.metadata}}export{w as createDocsMcpServer};
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 { ApiDescriptionInfo } from './types.js';
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
- * Filters out definitions that match ignored paths from redocly.yaml config.
42
- *
43
- * This function uses picomatch to check if any definition's relative path matches
44
- * any of the ignored path patterns specified in the redocly configuration.
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 f}from"node:path";import a from"picomatch";import{PUBLIC_API_DEFINITIONS_FOLDER as u,L10N_DIR_NAME as h,I18N_DIR_NAME as l}from"../../constants/common.js";import{RESERVED_ROUTES as p}from"../../plugins/get-reserved-routes.js";import{canDownloadApiDefinition as m}from"../../utils/rbac.js";function n(i){if(typeof i!="object"||i===null)return i;if(Array.isArray(i))return i.map(n);const r={};for(const t in i)if(Object.hasOwn(i,t)){if(t.toString().startsWith("x-parsed-"))continue;r[t]=n(i[t])}return r}function d(i){return i.reduce((r,t)=>(t.relativePath.startsWith(h)||t.relativePath.startsWith(l)||t.definition?.paths&&Object.keys(t.definition.paths).length>0&&r.push({...t,definition:n(t.definition)}),r),[])}function y(i,r,t,e){const o={};for(const[c,s]of Object.entries(i))m(f(u,s.relativePath),t,e,r)&&(o[c]=s);return o}function E(i,r){return i.filter(({relativePath:t})=>!a(r||[])(t))}function R(i={}){for(const[r,t]of Object.entries(i))if(r===p.mcp||(typeof t=="string"?t:t.to)===p.mcp)return!0;return!1}export{y as filterApiDescriptionsByRbac,E as filterIgnoredApiDescriptions,d as getCleanedUpApiDescriptions,R as isMcpInRedirects};
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};
@@ -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;
@@ -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 y}from"../../../constants/common.js";import{envConfig as s}from"../../config/env-config.js";import{JWT_SECRET_KEY as I}from"../../constants/common.js";import*as m from"../jwt/jwt.js";import{AlgorithmTypes as T}from"../jwt/types.js";const h=60,p=e=>["POST","PUT","DELETE","PATCH"].includes(e),f=e=>["GET"].includes(e);function K({serverOutDir:e,protectReadMethods:t=!0}){return async(r,a)=>await w(r,a,e,t)}const w=async(e,t,r,a=!0)=>{const n=e.req.method,i=p(n)||f(n)&&a,o=e.req.header("apiKey");if(o)return await g(e,t,o,r);const u=e.req.header("authorization")?.replace("Bearer ","");return u?await E(e,t,u):i?e.json({message:"API key is required"},401):await t()},g=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 i=await _(n,r);if(i)return e.set("apiKeyTeams",i.teams),await t();const o=new URL(`/api/orgs/${s.ORGANIZATION_ID}/session`,s.BH_API_URL).toString(),c=await fetch(o,{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=[y,...A];return e.set("apiKeyTeams",d),await n.set(["api-keys","reunite",r],{valid:!0,teams:d},{ttlInSeconds:h}),await t()}catch{return e.json({message:"API key validation failed"},400)}},E=async(e,t,r)=>{try{const a=await m.verify(r,I,T.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)}},_=async(e,t)=>{try{return await e.get(["api-keys","reunite",t])}catch{return null}};export{K as catalogAuthMiddleware};
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 q}from"hono/router/trie-router";import{REDOCLY_ROUTE_RBAC as i}from"@redocly/config";import{withPathPrefix as C}from"@redocly/theme/core/utils";import{canAccessResource as L}from"../../../utils/rbac.js";import{handleUnauthorizedApiRequest as U}from"../../utils.js";import{handleApiRouteRequest as P}from"../../handle-api-route-request.js";import{sortApiFunctionRoutes as w}from"../../utils/sort-api-function-routes.js";function B(a,t){a.all("*",async(e,u)=>{const{method:m,path:o}=e.req,p=t.getAllApiRoutes(),h=w(p),c=new q;for(const n of h){const A=n.httpMethod?.toUpperCase()||"ALL",g=C(n.slug);c.add(A,g,n)}const s=c.match(m.toUpperCase(),o);if(!s||s[0].length===0)return u();const l=s[0],[r]=l[0],{isAuthenticated:R,claims:{email:f},teams:d}=e.get("auth");return L({...r,slug:o,[i]:{...r[i],slug:o}},{isAuthenticated:R,email:f,teams:d},t.config.access?.rbac,t.config.access?.requiresLogin)?P(r,e,t):U(e)})}export{B as installApiRoutes};
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{CACHE_CONTROL_NO_CACHE_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
+ 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 l from"path";import{REDOCLY_ROUTE_RBAC as _,REDOCLY_TEAMS_RBAC as T}from"@redocly/config";import{withoutPathPrefix as G,withPathPrefix as Y}from"@redocly/theme/core/utils";import{CACHE_CONTROL_NO_CACHE_HEADER_VALUE as I,DEFAULT_IMMUTABLE_CACHE_MAX_AGE as $}from"../../constants/common.js";import{removeTrailingSlash as k}from"../../../utils/url/remove-trailing-slash.js";import{findInIterable as N}from"../../../utils/collection/find-in-iterable.js";import{sanitizeRedirectPathname as V}from"../../../utils/url/sanitize-redirect-pathname.js";import{envConfig as W}from"../../config/env-config.js";import{sanitizePath as X}from"../../../utils/path/sanitize-path.js";import{normalizeRouteSlug as j}from"../../../utils/path/normalize-route-slug.js";import{isPathInFolder as Z}from"../../../utils/path/is-path-in-folder.js";import{getLlmsTxtMdPathBySlug as J}from"../../utils/llmstxt/get-llms-txt-md-path-by-slug.js";import{removeLeadingSlash as S}from"../../../utils/url/remove-leading-slash.js";import{processRedirects as K}from"./helpers/process-redirects.js";import{renderPage as Q,getServerProps as x}from"../../ssr/index.js";import{canAccessAsset as ee,canAccessResource as U}from"../../utils/rbac.js";import{handleErrorPageRender as M,handleUnauthorized as b,handleUnauthorizedAsset as q}from"../utils.js";import{DEFAULT_MAX_AGE_FOR_MIME_TYPE as te,MIME_TYPES as ne}from"../mime-types.js";import{fileExistsAsync as v}from"../../utils/index.js";import{isAiAgentRequest as oe}from"../../utils/ai-agent-detection.js";import{getRedirectRoute as re}from"../utils/legacy-openapi-redirects.js";import{getContentTypeHeaderValue as ae}from"../utils/content-type.js";import{telemetry as ie}from"../../../cli/telemetry/index.js";import{telemetry as se}from"../../telemetry/index.js";function De(e,D,O){return async n=>{const A=n.get("logger"),a=n.req,i=new URL(a.url),r=G(X(decodeURIComponent(i.pathname))),R=l.parse(r).ext===".md",C=oe({accept:a.header("accept"),signatureAgent:a.header("signature-agent"),signature:a.header("signature"),signatureInput:a.header("signature-input"),userAgent:a.header("user-agent")}),m=j(r),o=(a.method==="GET"||a.method==="HEAD")&&!R?e.getRouteBySlug(m,{followRedirect:!1})||N(e.routesBySlug?.values(),t=>t.hasClientRoutes&&(r===t.slug||r.startsWith(t.slug+"/"))):void 0,E=e.getRedirect(m);if(E){const t=K({redirect:E,reqUrlSearch:i.search});return se.sendRedirectMessage([{object:"redirect",from:m,templateId:t.type.toString()}]),n.newResponse(null,t.type,{Location:t.location})}const f=W.isProductionEnv?301:302;if(o?.metadata?.type==="openapi"){const t=re(i.pathname);if(t)return A.info("Legacy OpenAPI docs redirect from "+i.pathname),n.newResponse(null,f,{Location:encodeURI(t)});if(i.pathname.match(/[A-Z]/))return A.warn("Redirect to lowercase route to avoid 404 error"),n.newResponse(null,f,{Location:encodeURI(i.pathname.toLowerCase())})}if(r.endsWith("/")&&r!=="/"){const t=V(new URL(m||"/",n.req.url).pathname);return n.newResponse(null,f,{Location:encodeURI(Y((t==="/"?"/":k(t))+i.search))})}const u=o&&C?J(o.slug):void 0,w=u?await v(l.resolve(e.outdir,S(u))):!1,{isAuthenticated:d,teams:g,claims:{email:p}}=n.get("auth");if(o&&!U(o,{isAuthenticated:d,email:p,teams:g},e.config.access?.rbac,e.config.access?.requiresLogin))return d?M(n,e,{slug:o.slug,[T]:o[T],[_]:o[_]},403):b(n,e,o.slug);if(o&&(!C||!w)){const t=await D(o),c=await x(o,n,t,e),{html:B,statusCode:z}=await Q(o,c,n,e,ie);return n.html(B,z,{"Cache-Control":I})}const L=u&&w?u:r,F=S(L),s=l.resolve(e.outdir,F);if(!Z(s,e.outdir))return q(n);if(R){const t=r==="index.html.md"?"/":r.replace(/\.md$/,""),c=e.getRouteBySlug(t,{followRedirect:!1});if(c&&!U(c,{isAuthenticated:d,email:p,teams:g},e.config.access?.rbac,e.config.access?.requiresLogin))return b(n,e,r)}const P=e.getGlobalConfig("access");if(!ee(L,P?.rbac||{},P?.requiresLogin||!1,e.getGlobalConfig("directoryPaths"),{isAuthenticated:d,email:p,teams:g}))return q(n);const y=ne[l.extname(s)]||"text/plain",h=s.match(/assets\/.*\.[a-f0-9]{8,}\..+/)||s.match(/runtime\/chunks\/.*/)?$:te[y],H=h?{"Cache-Control":`public, max-age=${h}, immutable`,Expires:new Date(Date.now()+h*1e3).toUTCString()}:{"Cache-Control":I};if(await v(s)){const t=a.query("download")!=null,c=await O(s);return n.newResponse(c,200,{"Content-Type":ae(y),"Access-Control-Allow-Origin":"*",...H,...t&&{"Content-Disposition":`attachment; filename="${l.basename(s)}"`}})}else return M(n,e,{slug:m},404)}}export{De as dynamicRouteHandler};
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 U,ServerRoutes as $}from"../../../constants/common.js";import{CACHE_CONTROL_NO_CACHE_HEADER_VALUE as a,DEFAULT_TITLE as F}from"../../constants/common.js";import{findInIterable as O}from"../../../utils/collection/find-in-iterable.js";import{removeTrailingSlash as N}from"../../../utils/url/remove-trailing-slash.js";import{envConfig as b}from"../../config/env-config.js";import{canAccessResource as q,filterDataByAccessDeep as j,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||F;if(e?.compilationErrors?.length&&b.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})||O(e.routesBySlug.values(),r=>r.hasClientRoutes&&c.startsWith(r.slug+"/"));if(c===$.OIDC_CALLBACK+"/")return t.json({templateId:"403OIDC",sharedDataIds:{},props:{seo:{title:`${i} - Forbidden`}}},200,{"Cache-Control":a});const{isAuthenticated:C,teams:D,claims:{name:v,picture:A,email:I}}=t.get("auth"),R={isAuthenticated:C,email:I,teams:D},m={isAuthenticated:C,name:v,picture:A,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!==U){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 S=j(o.versions,R,e.config.access?.rbac,e.config.access?.requiresLogin),P=e.routesSharedData.get(o.slug)||{},T=await s(o),y=await H(o,t,T,e),{sharedDataIds:_,...E}=y,w={templateId:o.templateId,versions:S,sharedDataIds:{...P,..._||{}},props:b.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=j(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
+ 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 d}from"../../telemetry/helpers/trace-step.js";import{expandTeamsForRead as p}from"../../utils/rbac.js";function C(e){return async t=>await d("search",async s=>{const u=t.get("logger"),o=t.get("auth"),y=u.startTiming(),a=e.getConfig().access?.requiresLogin&&!o.isAuthenticated,r={...await t.req.json(),auth:{...o,teams:p(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 f=0;if(Object.keys(i).length){const h=i.documents;for(const[c,n]of Object.entries(h))f+=n.length}return u.infoTime(y,`Search with query "${r.query||""}". Total results: ${f}`),s?.setAttribute("resultsCount",f),t.json(i)})}function F(e){return async t=>await d("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):{},f=!!a.field;let h=[];if(f){const c=a.field,n=c&&g.get(c);if(n){const l={...n};l.values=i?.[c]||[],h.push(l)}}else{const c=new Map;for(const[n,l]of g){const A=i?.[n],b={...l};b.values=A||l.values.map(T=>({value:T,count:0})),c.set(n,b)}h=Array.from(c,([,n])=>n)}return u.verboseTime(r,"Search facets"),t.json(h)})}export{F as searchFacetsHandler,C as searchHandler};
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 A}from"hono/cookie";import{withPathPrefix as l}from"@redocly/theme/core/utils";import{DEV_LOGIN_SLUG as E}from"../../constants/common.js";import{CACHE_CONTROL_NO_CACHE_HEADER_VALUE as b}from"../constants/common.js";import{getAuthProviderLoginParams as C,buildLoginUrl as y}from"./auth.js";import{renderPage as _}from"../ssr/index.js";import{telemetry as v}from"../../cli/telemetry/index.js";async function S(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 z(r,t,{slug:o},403);const d=s&&g?await C(s,g):void 0,m=d?{...d,extraParams:{...d.extraParams,prompt:"login"}}:void 0,{loginUrl:w,cookies:h={}}=m&&y(m,U,l(o))||{},f=t.globalData.auth?.devLogin||p.length>1?H(o):w;return Object.keys(h).forEach(c=>{A(r,c,h[c].value,h[c].options)}),f?r.newResponse(null,302,{Location:f}):r.text("Unauthorized",401)}const L={};async function z(r,t,o,n,a){let e=L[n];if(!e){const i={templateId:String(a||n),fsPath:"/",...o,baseSlug:o.slug};e=(await _(i,{},r,t,v)).html,L[n]=e}return r.html(e,n,{"Cache-Control":b})}function H(r){const t=new URLSearchParams({redirectTo:l(r)});return`${l(E)}?${t}`}async function T(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{H as getLoginUrlWithRedirect,z as handleErrorPageRender,S as handleUnauthorized,k as handleUnauthorizedApiRequest,T as handleUnauthorizedAsset,G as normalizeIpAddress};
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.134.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/openapi-docs": "3.22.0",
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/theme": "0.66.0",
101
- "@redocly/realm-asyncapi-sdk": "0.12.0"
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};