@redocly/redoc 0.137.0-next.11 → 0.137.0-next.12

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 (62) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/cli/build/index.js +1 -1
  3. package/dist/client/app/Sidebar/useActions.js +1 -1
  4. package/dist/client/app/Sidebar/useSidebarItems.js +1 -1
  5. package/dist/client/app/hooks/catalog/useCatalogFilter.js +1 -1
  6. package/dist/client/app/seo/SeoTags.js +1 -1
  7. package/dist/server/esbuild/esbuild-logger.d.ts +2 -2
  8. package/dist/server/esbuild/esbuild-logger.js +3 -3
  9. package/dist/server/plugins/api-docs/search/get-ai-search-documents.d.ts +1 -1
  10. package/dist/server/plugins/api-docs/search/get-ai-search-documents.js +33 -33
  11. package/dist/server/plugins/mcp/codemode/capabilities/fetch/index.js +5 -4
  12. package/dist/server/plugins/mcp/codemode/capabilities/types.d.ts +5 -2
  13. package/dist/server/plugins/mcp/codemode/capabilities/utils.js +4 -4
  14. package/dist/server/plugins/mcp/codemode/prompts.d.ts +1 -1
  15. package/dist/server/plugins/mcp/codemode/prompts.js +7 -6
  16. package/dist/server/plugins/mcp/codemode/sandbox/create-sandbox-setup.d.ts +2 -2
  17. package/dist/server/plugins/mcp/codemode/sandbox/create-sandbox-setup.js +1 -11
  18. package/dist/server/plugins/mcp/codemode/sandbox/polyfills/console.d.ts +2 -0
  19. package/dist/server/plugins/mcp/codemode/sandbox/polyfills/console.js +5 -0
  20. package/dist/server/plugins/mcp/codemode/sandbox/polyfills/index.d.ts +1 -0
  21. package/dist/server/plugins/mcp/codemode/sandbox/polyfills/index.js +2 -2
  22. package/dist/server/plugins/mcp/codemode/sandbox/tool-input-validator.d.ts +5 -0
  23. package/dist/server/plugins/mcp/codemode/sandbox/tool-input-validator.js +1 -0
  24. package/dist/server/plugins/mcp/codemode/sandbox/unknown-tool-hint.d.ts +8 -0
  25. package/dist/server/plugins/mcp/codemode/sandbox/unknown-tool-hint.js +2 -0
  26. package/dist/server/plugins/mcp/codemode/tools/describe-tools.js +3 -1
  27. package/dist/server/plugins/mcp/codemode/tools/execute.js +1 -1
  28. package/dist/server/plugins/mcp/codemode/tools/manage-credentials.js +2 -2
  29. package/dist/server/plugins/mcp/docs-mcp/tool-schemas.js +1 -1
  30. package/dist/server/plugins/mcp/docs-mcp/tools/core/search.js +2 -2
  31. package/dist/server/plugins/mcp/docs-mcp/tools/core/types.d.ts +2 -2
  32. package/dist/server/plugins/mcp/docs-mcp/tools/graphql/get-graphql-type.js +5 -5
  33. package/dist/server/plugins/mcp/docs-mcp/tools/graphql/types.d.ts +2 -1
  34. package/dist/server/plugins/mcp/docs-mcp/tools/openapi/list-apis.js +1 -1
  35. package/dist/server/plugins/mcp/docs-mcp/tools/openapi/load-api-description.d.ts +4 -2
  36. package/dist/server/plugins/mcp/docs-mcp/tools/openapi/load-api-description.js +1 -1
  37. package/dist/server/plugins/mcp/docs-mcp/tools/openapi/types.d.ts +6 -2
  38. package/dist/server/plugins/mcp/docs-mcp/utils/api-titles.d.ts +6 -0
  39. package/dist/server/plugins/mcp/docs-mcp/utils/api-titles.js +1 -0
  40. package/dist/server/plugins/mcp/gateway-mcp/fetch/ssrf-guard.js +1 -1
  41. package/dist/server/plugins/mcp/gateway-mcp/fetch/url-placeholders.d.ts +5 -0
  42. package/dist/server/plugins/mcp/gateway-mcp/fetch/url-placeholders.js +1 -0
  43. package/dist/server/plugins/mcp/servers/docs-server.js +1 -1
  44. package/dist/server/plugins/mcp/servers/mcp-server.js +2 -2
  45. package/dist/server/plugins/mcp/types.d.ts +1 -0
  46. package/dist/server/plugins/mcp/utils/available-sandbox-tools.js +1 -1
  47. package/dist/server/plugins/search/ai-indexer/prepare-semantic-documents.js +1 -1
  48. package/dist/server/plugins/search/llmstxt/create-llms-txt-generator.js +1 -1
  49. package/dist/server/plugins/search/llmstxt/index.d.ts +3 -1
  50. package/dist/server/plugins/search/llmstxt/index.js +9 -9
  51. package/dist/server/sandbox/sandbox.js +2 -2
  52. package/dist/server/sandbox/types.d.ts +8 -0
  53. package/dist/server/sandbox/utils/execution-budget.js +1 -1
  54. package/dist/server/sandbox/utils/return-last-expression.d.ts +6 -0
  55. package/dist/server/sandbox/utils/return-last-expression.js +1 -0
  56. package/dist/server/sandbox/utils/setup-host-functions.d.ts +1 -0
  57. package/dist/server/sandbox/utils/setup-host-functions.js +2 -2
  58. package/dist/server/store.js +1 -1
  59. package/dist/server/web-server/routes/dynamic-route.js +1 -1
  60. package/dist/server/web-server/routes/mcp-routes/mcp-oauth.js +1 -1
  61. package/dist/server/web-server/routes/mcp-routes/mcp-server-card.js +1 -1
  62. package/package.json +6 -6
@@ -1 +1 @@
1
- import{shouldHandleMcpAuth as d}from"../../../utils/rbac/should-handle-mcp-auth.js";import{CREATE_ANONYMOUS_SESSION_TOOL_NAME as m}from"../constants.js";import{GRAPHQL_TYPE_KINDS as o,GRAPHQL_LIST_SCOPES as h}from"./tools/graphql/constants.js";import{OPERATION_METHODS as p}from"./tools/openapi/constants.js";const i={type:"string",nullable:!0},n={limit:{type:"number"},total:{type:"number"},page:{type:"number"},totalPages:{type:"number"}},r={codemodeType:"OpenApiServer[]"},s={codemodeType:"OpenApiSecurityRequirement[]"},l={codemodeType:"Record<string, OpenApiSecurityScheme>"},y={codemodeType:"OpenApiDocument"},f={codemodeType:"OpenApiOperation & { path: string; method: string }"},g={type:"object",additionalProperties:!1,required:[],properties:{filter:{type:"string",description:"Matches part of an API name, or of a description when no name matches",minLength:1,nullable:!0},page:{type:"number",description:"Page number",minimum:1,default:1,nullable:!0},limit:{type:"number",description:"Number of APIs per page. Default is 300",minimum:1,default:300,nullable:!0}}},a={type:"object",required:["name"],additionalProperties:!1,properties:{name:{type:"string",description:"API name, or a unique part of it",minLength:1},version:{type:"string",description:"API version",nullable:!0},filePath:{type:"string",description:"API definition file path",nullable:!0}}},b={type:"object",required:["name","path","method"],additionalProperties:!1,properties:{name:{type:"string",description:"API name, or a unique part of it",minLength:1},path:{type:"string",description:"Endpoint path (e.g. /api/v1/users)",minLength:1},method:{type:"string",description:"HTTP method (GET, POST, PUT, DELETE, etc.)",enum:[...p.map(e=>e.toUpperCase()),...p],minLength:1},version:{type:"string",description:"API version (required when multiple APIs share the same name but differ by version)",nullable:!0},filePath:{type:"string",description:"API definition file path",nullable:!0}}},S={type:"object",required:[],additionalProperties:!1,properties:{}},v={type:"object",required:[],additionalProperties:!1,properties:{}};function H(e){const t=[{name:"list-apis",title:"List APIs",description:"Lists the APIs documented in this project",schema:g,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",properties:{items:{type:"array",items:{type:"object",properties:{name:{type:"string"},description:i,version:i,servers:r,filePath:{type:"string",description:"API definition file path"},...e.hasCallableApis?{callable:{type:"boolean",description:"true = the documented hosts of this API are reachable via `fetch`; false = documentation only"}}:{}}}},...n}}},{name:"get-endpoints",title:"Get endpoints",description:"Get all endpoints for a specific API",schema:a,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",properties:{api:{type:"string"},version:{type:"string"},servers:r,endpoints:{type:"array",items:{type:"object",properties:{path:{type:"string"},method:{type:"string"},summary:i,description:i,security:s}}}}}},{name:"get-endpoint-info",title:"Get endpoint info",description:"Get comprehensive information about specific endpoint including parameters, security, and examples",schema:b,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",properties:{api:{type:"string"},version:{type:"string"},servers:r,endpoint:f,globalSecurity:s,securitySchemes:l}}},{name:"get-security-schemes",title:"Get security schemes",description:"Get the security schemes for a specific API",schema:a,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",properties:{name:i,version:i,securitySchemes:l,security:s}}},{name:"get-full-api-description",title:"Get full API description",description:"Get the complete OpenAPI description",schema:a,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",properties:{api:{type:"string"},version:{type:"string"},definition:y}}},T(e.products,e.locales)];return d(e.requiresLogin,e.rbac)&&t.push({name:"whoami",title:"Who am I",description:"Get information about the currently authenticated user",schema:S,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",properties:{email:{type:"string"},name:{type:"string"},subject:{type:"string"},clientId:{type:"string"},scope:{type:"string"},issuedAt:{type:"string"},expiresAt:{type:"string"}}}}),e.hasGraphqlApis&&t.push(...O()),e.elicitationEnabled&&t.push({name:m,title:"Create anonymous session",description:"Create an anonymous session handle for storing upstream API credentials. Pass the returned sessionHandle to execute when an API needs credentials and the caller is not signed in. Treat it as a secret and reuse it across calls.",schema:v,annotations:{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!1,openWorldHint:!1},outputSchema:{type:"object",required:["sessionHandle"],properties:{sessionHandle:{type:"string"}}}}),t}const A={type:"object",required:[],additionalProperties:!1,properties:{filter:{type:"string",description:"GraphQL schema name (or part of it)",minLength:1,nullable:!0},page:{type:"number",description:"Page number",minimum:1,default:1,nullable:!0},limit:{type:"number",description:"Number of results per page. Default is 300",minimum:1,default:300,nullable:!0}}},P={type:"object",required:["name"],additionalProperties:!1,properties:{name:{type:"string",description:"GraphQL schema name",minLength:1},kind:{type:"string",description:'Optional: return only a single category of schema members. With scope "fields", restricts to the fields of that parent category ("objects", "interfaces", or "inputs" only).',enum:[...o],nullable:!0},scope:{type:"string",description:'Optional: what each list item is. "members" (default) lists top-level types and operations. "fields" flattens every field of every object/interface/input type into "ParentType.fieldName" entries with their descriptions \u2014 combine with `filter` to search nested fields anywhere in the schema.',enum:[...h],nullable:!0},filter:{type:"string",description:'Optional: only members whose name or description contains this substring, case-insensitive (e.g. "custom tags")',minLength:1,nullable:!0},referencesType:{type:"string",description:'Optional: only members that reference this type directly or transitively (via return, field, argument, union-member or input-field types). Finds cross-cutting members that never name it \u2014 e.g. referencesType "Book" surfaces a search query returning a union that includes Book.',minLength:1,nullable:!0},page:{type:"number",description:"Page number",minimum:1,default:1,nullable:!0},limit:{type:"number",description:"Number of results per page. Default is 300",minimum:1,default:300,nullable:!0}}},L={type:"object",required:["name","type"],additionalProperties:!1,properties:{name:{type:"string",description:"GraphQL schema name",minLength:1},type:{type:"string",description:"Name of the type, operation, or directive",minLength:1},includeReferencedTypes:{type:"boolean",description:"Also include the SDL of every type referenced transitively. Gives the whole subgraph at once, but can be large for highly-connected types.",default:!1,nullable:!0}}},q={type:"object",required:["name"],additionalProperties:!1,properties:{name:{type:"string",description:"GraphQL schema name",minLength:1}}};function O(){return[{name:"list-graphql-apis",title:"List GraphQL APIs",description:"Lists available GraphQL schemas with their context and purpose",schema:A,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",properties:{items:{type:"array",items:{type:"object",properties:{name:{type:"string"},description:i}}},...n}}},{name:"get-graphql-type-list",title:"Get GraphQL type list",description:'List all operations and types in a GraphQL schema as a flat, paginated list. Each item is tagged with its kind (query, object, enum, \u2026) and carries a one-line description; operations also include their return type and argument signature \u2014 use it to decide which members to fetch in detail. Narrow the result with `kind` (one category), `filter` (case-insensitive substring of the member name or description, e.g. "book"), or `referencesType` (only members that use a given type, directly or transitively) to explore a domain cheaply instead of pulling the full schema. To search nested fields \u2014 not just type names \u2014 set scope "fields": it flattens every field of every object/interface/input type into "ParentType.fieldName" entries with their descriptions, so `filter` finds things like an input field whose docstring mentions your keyword.',schema:P,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",properties:{name:{type:"string"},items:{type:"array",items:{type:"object",properties:{kind:{type:"string",enum:o},name:{type:"string"},description:i,type:{type:"string"},args:{type:"string"},directives:{type:"string"}}}},...n}}},{name:"get-graphql-type",title:"Get GraphQL type",description:'Get the SDL for a single GraphQL type, operation (query/mutation/subscription field), or directive. Without includeReferencedTypes, the SDL is followed by a one-level manifest of every directly referenced type\'s field names (e.g. "input ActionOperationInput { addTags, removeTags }"), so you can see what nested types contain before fetching them. Set includeReferencedTypes to instead pull in the full SDL of every type it references transitively \u2014 the whole structural subgraph in one call, ideal for complete exploration of an entity (e.g. Book and all the types it touches). That traversal only follows what the target depends on; to go the other direction and find the members that use a type, call get-graphql-type-list with `referencesType`.',schema:L,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"string"}},{name:"get-graphql-schema",title:"Get GraphQL schema",description:"Get the complete GraphQL schema as SDL \u2014 the whole type graph in one call. Returns everything, so it can be very large and token-expensive for big schemas; prefer get-graphql-type-list (filter/paginate) plus targeted get-graphql-type calls, and reach for this only for small schemas or when you truly need the full SDL.",schema:q,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"string"}}]}function T(e,t){const c=e&&e.length>0,u=t&&t.length>0;return{name:"search",title:"Search documentation",description:"Search across the documentation to fetch relevant content for a given query",schema:{type:"object",required:["query"],additionalProperties:!1,properties:{query:{type:"string",description:"Search query. Should be a single word or that phrase that is presented in a documentation.",minLength:1},...c?{product:{type:"string",description:"Optional product name to filter search results by specific product.",enum:e,nullable:!0}}:{},...u?{locale:{type:"string",description:"Optional locale code to filter search results by documentation language (e.g. 'en', 'ja'). Use the locale matching the language of the user's request. Defaults to the project's default locale.",enum:t,nullable:!0}}:{}}},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!1,openWorldHint:!1},outputSchema:{type:"string"}}}const E=new Set(H({requiresLogin:!0,hasGraphqlApis:!0,elicitationEnabled:!0}).map(e=>e.name));export{E as ALL_DEFAULT_TOOL_NAMES,H as getDefaultToolSchemas};
1
+ import{SEMANTIC_SEARCH_API_URL as m}from"../../../constants/common.js";import{shouldHandleMcpAuth as h}from"../../../utils/rbac/should-handle-mcp-auth.js";import{CREATE_ANONYMOUS_SESSION_TOOL_NAME as y}from"../constants.js";import{GRAPHQL_TYPE_KINDS as o,GRAPHQL_LIST_SCOPES as f}from"./tools/graphql/constants.js";import{OPERATION_METHODS as p}from"./tools/openapi/constants.js";const i={type:"string",nullable:!0},n={limit:{type:"number"},total:{type:"number"},page:{type:"number"},totalPages:{type:"number"}},r={codemodeType:"OpenApiServer[]"},s={codemodeType:"OpenApiSecurityRequirement[]"},l={codemodeType:"Record<string, OpenApiSecurityScheme>"},g={codemodeType:"OpenApiDocument"},b={codemodeType:"OpenApiOperation & { path: string; method: string }"},v={type:"object",additionalProperties:!1,required:[],properties:{filter:{type:"string",description:"Matches part of an API name, or of a description when no name matches",minLength:1,nullable:!0},page:{type:"number",description:"Page number",minimum:1,default:1,nullable:!0},limit:{type:"number",description:"Number of APIs per page. Default is 300",minimum:1,default:300,nullable:!0}}},a={type:"object",required:[],additionalProperties:!1,properties:{name:{type:"string",description:"API name, or a unique part of it. Omit when `filePath` is given.",minLength:1,nullable:!0},apiName:{type:"string",description:"Alias of `name`",nullable:!0},api:{type:"string",description:"Alias of `name`",nullable:!0},version:{type:"string",description:"API version",nullable:!0},filePath:{type:"string",description:"API definition file path, as returned by `listApis`",nullable:!0}}},S={type:"object",required:["path","method"],additionalProperties:!1,properties:{name:{type:"string",description:"API name, or a unique part of it. Omit when `filePath` is given.",minLength:1,nullable:!0},apiName:{type:"string",description:"Alias of `name`",nullable:!0},api:{type:"string",description:"Alias of `name`",nullable:!0},path:{type:"string",description:"Endpoint path (e.g. /api/v1/users)",minLength:1},method:{type:"string",description:"HTTP method (GET, POST, PUT, DELETE, etc.)",enum:[...p.map(e=>e.toUpperCase()),...p],minLength:1},version:{type:"string",description:"API version (required when multiple APIs share the same name but differ by version)",nullable:!0},filePath:{type:"string",description:"API definition file path, as returned by `listApis`",nullable:!0}}},A={type:"object",required:[],additionalProperties:!1,properties:{}},H={type:"object",required:[],additionalProperties:!1,properties:{}};function P(e){const t=[{name:"list-apis",title:"List APIs",description:"Lists the APIs documented in this project",schema:v,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",properties:{items:{type:"array",items:{type:"object",properties:{name:{type:"string"},description:i,version:i,servers:r,filePath:{type:"string",description:"API definition file path"},ambiguousTitle:{type:"boolean",description:"true = another API shares this title; pass `filePath`, or `version` when the copies differ by version"},...e.hasCallableApis?{callable:{type:"boolean",description:"true = the documented hosts of this API are reachable via `fetch`; false = documentation only"}}:{}}}},...n}}},{name:"get-endpoints",title:"Get endpoints",description:"Get all endpoints for a specific API",schema:a,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",properties:{api:{type:"string"},version:{type:"string"},servers:r,endpoints:{type:"array",items:{type:"object",properties:{path:{type:"string"},method:{type:"string"},summary:i,description:i,security:s}}}}}},{name:"get-endpoint-info",title:"Get endpoint info",description:"Get comprehensive information about specific endpoint including parameters, security, and examples",schema:S,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",properties:{api:{type:"string"},version:{type:"string"},servers:r,endpoint:b,globalSecurity:s,securitySchemes:l}}},{name:"get-security-schemes",title:"Get security schemes",description:"Get the security schemes for a specific API",schema:a,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",properties:{name:i,version:i,securitySchemes:l,security:s}}},{name:"get-full-api-description",title:"Get full API description",description:"Get the complete OpenAPI description",schema:a,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",properties:{api:{type:"string"},version:{type:"string"},definition:g}}},...m?[c(e.products,e.locales)]:[]];return h(e.requiresLogin,e.rbac)&&t.push({name:"whoami",title:"Who am I",description:"Get information about the currently authenticated user",schema:A,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",properties:{email:{type:"string"},name:{type:"string"},subject:{type:"string"},clientId:{type:"string"},scope:{type:"string"},issuedAt:{type:"string"},expiresAt:{type:"string"}}}}),e.hasGraphqlApis&&t.push(...G()),e.elicitationEnabled&&t.push({name:y,title:"Create anonymous session",description:"Create an anonymous session handle for storing upstream API credentials. Pass the returned sessionHandle to execute when an API needs credentials and the caller is not signed in. Treat it as a secret and reuse it across calls.",schema:H,annotations:{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!1,openWorldHint:!1},outputSchema:{type:"object",required:["sessionHandle"],properties:{sessionHandle:{type:"string"}}}}),t}const L={type:"object",required:[],additionalProperties:!1,properties:{filter:{type:"string",description:"GraphQL schema name (or part of it)",minLength:1,nullable:!0},page:{type:"number",description:"Page number",minimum:1,default:1,nullable:!0},limit:{type:"number",description:"Number of results per page. Default is 300",minimum:1,default:300,nullable:!0}}},O={type:"object",required:["name"],additionalProperties:!1,properties:{name:{type:"string",description:"GraphQL schema name",minLength:1},kind:{type:"string",description:'Optional: return only a single category of schema members. With scope "fields", restricts to the fields of that parent category ("objects", "interfaces", or "inputs" only).',enum:[...o,null],nullable:!0},scope:{type:"string",description:'Optional: what each list item is. "members" (default) lists top-level types and operations. "fields" flattens every field of every object/interface/input type into "ParentType.fieldName" entries with their descriptions \u2014 combine with `filter` to search nested fields anywhere in the schema.',enum:[...f,null],nullable:!0},filter:{type:"string",description:'Optional: only members whose name or description contains this substring, case-insensitive (e.g. "custom tags")',minLength:1,nullable:!0},referencesType:{type:"string",description:'Optional: only members that reference this type directly or transitively (via return, field, argument, union-member or input-field types). Finds cross-cutting members that never name it \u2014 e.g. referencesType "Book" surfaces a search query returning a union that includes Book.',minLength:1,nullable:!0},page:{type:"number",description:"Page number",minimum:1,default:1,nullable:!0},limit:{type:"number",description:"Number of results per page. Default is 300",minimum:1,default:300,nullable:!0}}},T={type:"object",required:["name"],additionalProperties:!1,properties:{name:{type:"string",description:"GraphQL schema name",minLength:1},type:{type:"string",description:"Name of the type, operation, or directive",minLength:1,nullable:!0},typeName:{type:"string",description:"Alias of `type`",nullable:!0},includeReferencedTypes:{type:"boolean",description:"Also include the SDL of every type referenced transitively. Gives the whole subgraph at once, but can be large for highly-connected types.",default:!1,nullable:!0}}},q={type:"object",required:["name"],additionalProperties:!1,properties:{name:{type:"string",description:"GraphQL schema name",minLength:1}}};function G(){return[{name:"list-graphql-apis",title:"List GraphQL APIs",description:"Lists available GraphQL schemas with their context and purpose",schema:L,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",properties:{items:{type:"array",items:{type:"object",properties:{name:{type:"string"},description:i}}},...n}}},{name:"get-graphql-type-list",title:"Get GraphQL type list",description:'List all operations and types in a GraphQL schema as a flat, paginated list. Each item is tagged with its kind (query, object, enum, \u2026) and carries a one-line description; operations also include their return type and argument signature \u2014 use it to decide which members to fetch in detail. Narrow the result with `kind` (one category), `filter` (case-insensitive substring of the member name or description, e.g. "book"), or `referencesType` (only members that use a given type, directly or transitively) to explore a domain cheaply instead of pulling the full schema. To search nested fields \u2014 not just type names \u2014 set scope "fields": it flattens every field of every object/interface/input type into "ParentType.fieldName" entries with their descriptions, so `filter` finds things like an input field whose docstring mentions your keyword.',schema:O,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"object",properties:{name:{type:"string"},items:{type:"array",items:{type:"object",properties:{kind:{type:"string",enum:o},name:{type:"string"},description:i,type:{type:"string"},args:{type:"string"},directives:{type:"string"}}}},...n}}},{name:"get-graphql-type",title:"Get GraphQL type",description:'Get the SDL for a single GraphQL type, operation (query/mutation/subscription field), or directive. Without includeReferencedTypes, the SDL is followed by a one-level manifest of every directly referenced type\'s field names (e.g. "input ActionOperationInput { addTags, removeTags }"), so you can see what nested types contain before fetching them. Set includeReferencedTypes to instead pull in the full SDL of every type it references transitively \u2014 the whole structural subgraph in one call, ideal for complete exploration of an entity (e.g. Book and all the types it touches). That traversal only follows what the target depends on; to go the other direction and find the members that use a type, call get-graphql-type-list with `referencesType`.',schema:T,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"string"}},{name:"get-graphql-schema",title:"Get GraphQL schema",description:"Get the complete GraphQL schema as SDL \u2014 the whole type graph in one call. Returns everything, so it can be very large and token-expensive for big schemas; prefer get-graphql-type-list (filter/paginate) plus targeted get-graphql-type calls, and reach for this only for small schemas or when you truly need the full SDL.",schema:q,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1},outputSchema:{type:"string"}}]}function c(e,t){const u=e&&e.length>0,d=t&&t.length>0;return{name:"search",title:"Search documentation",description:"Search across the documentation to fetch relevant content for a given query",schema:{type:"object",required:["query"],additionalProperties:!1,properties:{query:{type:"string",description:"Search query. Should be a single word or that phrase that is presented in a documentation.",minLength:1},...u?{product:{type:"string",description:"Optional product name to filter search results by specific product.",enum:[...e,null],nullable:!0}}:{},...d?{locale:{type:"string",description:"Optional locale code to filter search results by documentation language (e.g. 'en', 'ja'). Use the locale matching the language of the user's request. Defaults to the project's default locale.",enum:[...t,null],nullable:!0}}:{}}},annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!1,openWorldHint:!1},outputSchema:{type:"string"}}}const D=new Set([...P({requiresLogin:!0,hasGraphqlApis:!0,elicitationEnabled:!0}).map(e=>e.name),c().name]);export{D as ALL_DEFAULT_TOOL_NAMES,P as getDefaultToolSchemas};
@@ -1,6 +1,6 @@
1
- import{removeTrailingSlash as g,withPathPrefix as y,withoutPathPrefix as E}from"@redocly/theme/core/utils";import{ServerRoutes as L}from"../../../../../../constants/api.js";import{DEFAULT_LOCALE_PLACEHOLDER as S}from"../../../../../../constants/common.js";const w=async(n,t)=>{const{query:e,product:c,locale:l}=n,u=t.config.l10n?.defaultLocale||S,h=JSON.stringify({query:e,product:c,locale:l||u}),f=`${t.internalBaseUrl||t.baseUrl}${y(L.SEMANTIC_SEARCH)}`,o=t.accessToken?`authorization=${String(t.accessToken).replace(/^Bearer /,"")}`:"";try{const s=await fetch(f,{method:"POST",credentials:"include",headers:{"Content-Type":"application/json",...o?{Cookie:o}:{}},body:h});if(!s.ok)return{content:[{type:"text",text:"Error retrieving search results."}],isError:!0};const p=await s.json(),d=new Set(t.searchIgnoredRoutes??[]),a=(p||[]).filter(r=>!R(r.url,d));if(a.length===0)return{content:[{type:"text",text:"No results found."}]};const m=r=>{try{return new URL(r,t.baseUrl).toString()}catch{return r}},i=a.map(r=>`### [${r.title}](${m(r.url)})
1
+ import{removeTrailingSlash as g,withPathPrefix as y,withoutPathPrefix as E}from"@redocly/theme/core/utils";import{ServerRoutes as L}from"../../../../../../constants/api.js";import{DEFAULT_LOCALE_PLACEHOLDER as S}from"../../../../../../constants/common.js";const w=async(n,t)=>{const{query:e,product:o,locale:l}=n,u=t.config.l10n?.defaultLocale||S,h=JSON.stringify({query:e,...o?{product:o}:{},locale:l||u}),f=`${t.internalBaseUrl||t.baseUrl}${y(L.SEMANTIC_SEARCH)}`,s=t.accessToken?`authorization=${String(t.accessToken).replace(/^Bearer /,"")}`:"";try{const a=await fetch(f,{method:"POST",credentials:"include",headers:{"Content-Type":"application/json",...s?{Cookie:s}:{}},body:h});if(!a.ok)return{content:[{type:"text",text:"Error retrieving search results."}],isError:!0};const p=await a.json(),d=new Set(t.searchIgnoredRoutes??[]),i=(p||[]).filter(r=>!R(r.url,d));if(i.length===0)return{content:[{type:"text",text:"No results found."}]};const m=r=>{try{return new URL(r,t.baseUrl).toString()}catch{return r}},c=i.map(r=>`### [${r.title}](${m(r.url)})
2
2
 
3
3
  ${r.content}
4
4
  `).join(`
5
5
 
6
- `).trim();return{content:[{type:"text",text:i.length?i:"No results found."}]}}catch{return{content:[{type:"text",text:"Error retrieving search results."}],isError:!0}}};function R(n,t){if(t.size===0)return!1;let e;try{e=new URL(n,"https://relative.invalid").pathname}catch{return!1}e=g(E(e));try{e=decodeURI(e)}catch{}return t.has(e)}var v={search:w};export{v as default};
6
+ `).trim();return{content:[{type:"text",text:c.length?c:"No results found."}]}}catch{return{content:[{type:"text",text:"Error retrieving search results."}],isError:!0}}};function R(n,t){if(t.size===0)return!1;let e;try{e=new URL(n,"https://relative.invalid").pathname}catch{return!1}e=g(E(e));try{e=decodeURI(e)}catch{}return t.has(e)}var v={search:w};export{v as default};
@@ -1,7 +1,7 @@
1
1
  export type SearchArgs = {
2
2
  query: string;
3
- product?: string;
4
- locale?: string;
3
+ product?: string | null;
4
+ locale?: string | null;
5
5
  };
6
6
  export type WhoamiArgs = Record<string, never>;
7
7
  //# sourceMappingURL=types.d.ts.map
@@ -1,10 +1,10 @@
1
- import{respondWithGraphqlSchema as d}from"./tool-helpers.js";import{printTypeOrField as y,printTypeOrFieldWithReferences as a,referencedTypeManifest as $}from"./utils.js";const m=(r,c)=>d(r.name,c,({name:p,schema:n})=>{const{type:e,includeReferencedTypes:l}=r;if(l){const{sdl:t,referencedCount:s}=a(n,e);return`# Schema: ${p}
2
- # Type: ${e} (+ ${s} referenced types)
1
+ import{respondWithGraphqlSchema as s}from"./tool-helpers.js";import{printTypeOrField as d,printTypeOrFieldWithReferences as a,referencedTypeManifest as m}from"./utils.js";const h=(n,i)=>s(n.name,i,({name:p,schema:t})=>{const{includeReferencedTypes:c}=n,e=n.type??n.typeName;if(!e)throw new Error("Pass `type`: the name of the type, operation, or directive.");if(c){const{sdl:r,referencedCount:l}=a(t,e);return`# Schema: ${p}
2
+ # Type: ${e} (+ ${l} referenced types)
3
3
 
4
- ${t}`}const o=`# Schema: ${p}
4
+ ${r}`}const o=`# Schema: ${p}
5
5
  # Type: ${e}
6
6
 
7
- ${y(n,e)}`,f=$(n,e);if(f.length===0)return o;const i=["# Referenced types (one level, names only; fetch a type or set includeReferencedTypes for full SDL):",...f.map(t=>`# ${t}`)].join(`
7
+ ${d(t,e)}`,f=m(t,e);if(f.length===0)return o;const y=["# Referenced types (one level, names only; fetch a type or set includeReferencedTypes for full SDL):",...f.map(r=>`# ${r}`)].join(`
8
8
  `);return`${o}
9
9
 
10
- ${i}`});var h={"get-graphql-type":m};export{h as default};
10
+ ${y}`});var T={"get-graphql-type":h};export{T as default};
@@ -28,7 +28,8 @@ export type GetGraphqlTypeListArgs = {
28
28
  };
29
29
  export type GetGraphqlTypeArgs = {
30
30
  name: string;
31
- type: string;
31
+ type?: string;
32
+ typeName?: string;
32
33
  includeReferencedTypes?: boolean;
33
34
  };
34
35
  export type GetGraphqlSchemaArgs = {
@@ -1 +1 @@
1
- import{isFetchCapable as d}from"../../../gateway-mcp/callable-apis.js";import{filterApiDescriptionsByName as g}from"../../utils/api-name-matching.js";const h=async(n,i)=>{const{filter:s,page:l=1,limit:e=300}=n,o=d(i);let t=Object.values(i.apiDescriptionsMap);s&&(t=g(t,s));const a=(l-1)*e,c=a+e,p=Math.ceil(t.length/e),r=t.length;return t=t.slice(a,c),{content:[{type:"text",text:JSON.stringify({items:t.map(({relativePath:f,fetchEligible:m,...u})=>({filePath:f,...u,...o?{callable:m===!0}:{}})),limit:e,total:r,page:l,totalPages:p})}]}};var y={"list-apis":h};export{y as default};
1
+ import{isFetchCapable as d}from"../../../gateway-mcp/callable-apis.js";import{filterApiDescriptionsByName as h}from"../../utils/api-name-matching.js";import{apiTitleKey as y,countApiTitles as x}from"../../utils/api-titles.js";const A=async(c,i)=>{const{filter:s,page:l=1,limit:e=300}=c,p=d(i),n=Object.values(i.apiDescriptionsMap),r=x(n);let t=n;s&&(t=h(t,s));const a=(l-1)*e,m=a+e,u=Math.ceil(t.length/e),f=t.length;return t=t.slice(a,m),{content:[{type:"text",text:JSON.stringify({items:t.map(({relativePath:g,fetchEligible:b,...o})=>({filePath:g,...o,...(r.get(y(o.name))??0)>1?{ambiguousTitle:!0}:{},...p?{callable:b===!0}:{}})),limit:e,total:f,page:l,totalPages:u})}]}};var I={"list-apis":A};export{I as default};
@@ -1,7 +1,9 @@
1
1
  import type { OpenAPIDefinition } from '@redocly/api-docs';
2
2
  import type { McpToolContext } from '../../../types.js';
3
- export declare function loadApiDescription({ name, version, filePath }: {
4
- name: string;
3
+ export declare function loadApiDescription(args: {
4
+ name?: string;
5
+ apiName?: string;
6
+ api?: string;
5
7
  version?: string;
6
8
  filePath?: string;
7
9
  }, context: McpToolContext): Promise<OpenAPIDefinition>;
@@ -1 +1 @@
1
- import{describeAvailableApis as c,findApiDescriptionByNameAndVersion as u}from"../../utils/api-name-matching.js";import{getApiDescriptionFromFs as d}from"./utils.js";async function l({name:r,version:n,filePath:o},i){const e=o?Object.values(i.apiDescriptionsMap).find(s=>s.relativePath===o):u(i.apiDescriptionsMap,r,n);if(!e){if(o)throw new Error(`No API found with filePath "${o}". File paths are returned by the list-apis tool.`);const s=c(i.apiDescriptionsMap,r);throw new Error(s?`No API found matching "${r}". Available APIs: ${s}.`:`No API found matching "${r}".`)}const t=!!i?.config?.access?.requiresLogin,p=i?.config?.access?.rbac||{},a=await d({relativePath:e.relativePath||"",outdir:i.outdir||"",user:i.user,rbac:p,requiresLogin:t});if(!a)throw new Error(`No API found matching "${o||r}".`);return a}export{l as loadApiDescription};
1
+ import{describeAvailableApis as l,findApiDescriptionByNameAndVersion as h}from"../../utils/api-name-matching.js";import{getApiDescriptionFromFs as u}from"./utils.js";async function P(o,i){const{version:p,filePath:e}=o,r=o.name??o.apiName??o.api;if(!e&&!r)throw new Error("Pass `name` (the API title, or a unique part of it) or `filePath` from list-apis.");const t=Object.values(i.apiDescriptionsMap),n=e?t.find(a=>a.relativePath===e):t.find(a=>a.relativePath===r)??h(i.apiDescriptionsMap,r??"",p);if(!n){if(e)throw new Error(`No API found with filePath "${e}". File paths are returned by the list-apis tool.`);const a=l(i.apiDescriptionsMap,r??"");throw new Error(a?`No API found matching "${r}". Available APIs: ${a}.`:`No API found matching "${r}".`)}const c=!!i?.config?.access?.requiresLogin,f=i?.config?.access?.rbac||{},s=await u({relativePath:n.relativePath||"",outdir:i.outdir||"",user:i.user,rbac:f,requiresLogin:c});if(!s)throw new Error(`No API found matching "${e||r}".`);return s}export{P as loadApiDescription};
@@ -4,12 +4,16 @@ export type ListApisArgs = {
4
4
  limit?: number;
5
5
  };
6
6
  export type ApiNameVersionArgs = {
7
- name: string;
7
+ name?: string;
8
+ apiName?: string;
9
+ api?: string;
8
10
  version?: string;
9
11
  filePath?: string;
10
12
  };
11
13
  export type GetEndpointInfoArgs = {
12
- name: string;
14
+ name?: string;
15
+ apiName?: string;
16
+ api?: string;
13
17
  path: string;
14
18
  method: string;
15
19
  version?: string;
@@ -0,0 +1,6 @@
1
+ import type { ApiDescriptionInfo } from '../../types.js';
2
+ /** The form the API lookup compares titles in, so a collision here is a collision there. */
3
+ export declare function apiTitleKey(name: string): string;
4
+ /** How many APIs carry each title, keyed by `apiTitleKey`, so a shared title is detectable. */
5
+ export declare function countApiTitles(apis: ApiDescriptionInfo[]): Map<string, number>;
6
+ //# sourceMappingURL=api-titles.d.ts.map
@@ -0,0 +1 @@
1
+ function r(t){return t.trim().toLowerCase()}function c(t){const e=new Map;for(const{name:o}of t){const n=r(o);e.set(n,(e.get(n)??0)+1)}return e}export{r as apiTitleKey,c as countApiTitles};
@@ -1 +1 @@
1
- import{isIP as l}from"node:net";import{isHostAllowed as i}from"./allowed-hosts.js";import{isBlockedIp as a}from"./ssrf-blocklist.js";import{GatewayFetchBlockedError as c,GatewayFetchUserError as s}from"./fetch-errors.js";function m(o,r){let t;try{t=new URL(o)}catch{throw new s(`Invalid URL: ${o}`)}if(t.protocol!=="http:"&&t.protocol!=="https:")throw new s(`Only http(s) URLs are allowed, got ${t.protocol}`);if(t.username||t.password)throw new s("URLs must not contain embedded credentials");const e=n(t.hostname);if(d(e)||!i(e,r))throw new c(`Host "${e}" is not allowed`,e);return t}function d(o){const r=n(o.toLowerCase()).split("%")[0];return r==="localhost"||r.endsWith(".localhost")?!0:l(r)!==0?a(r):!1}function n(o){return o.replace(/^\[|\]$/g,"")}export{m as assertUrlAllowed,d as isBlockedAddress};
1
+ import{isIP as d}from"node:net";import{isHostAllowed as h}from"./allowed-hosts.js";import{isBlockedIp as w}from"./ssrf-blocklist.js";import{GatewayFetchBlockedError as p,GatewayFetchUserError as r}from"./fetch-errors.js";import{findUnresolvedPlaceholders as a,unresolvedPlaceholderMessage as i}from"./url-placeholders.js";function v(o,t){let e;try{e=new URL(o)}catch{throw new r(`Invalid URL: ${o}`)}if(e.protocol!=="http:"&&e.protocol!=="https:")throw new r(`Only http(s) URLs are allowed, got ${e.protocol}`);if(e.username||e.password)throw new r("URLs must not contain embedded credentials");const n=a(e.hostname);if(n.length>0)throw new r(i(n));const s=c(e.hostname);if(f(s)||!h(s,t))throw new p(`Host "${s}" is not allowed`,s);const l=a(e.pathname);if(l.length>0)throw new r(i(l));return e}function f(o){const t=c(o.toLowerCase()).split("%")[0];return t==="localhost"||t.endsWith(".localhost")?!0:d(t)!==0?w(t):!1}function c(o){return o.replace(/^\[|\]$/g,"")}export{v as assertUrlAllowed,f as isBlockedAddress};
@@ -0,0 +1,5 @@
1
+ /** Collect the placeholder names one part of a URL still carries. */
2
+ export declare function findUnresolvedPlaceholders(urlPart: string): string[];
3
+ /** The refusal a caller reads when it left a placeholder in the URL. */
4
+ export declare function unresolvedPlaceholderMessage(names: readonly string[]): string;
5
+ //# sourceMappingURL=url-placeholders.d.ts.map
@@ -0,0 +1 @@
1
+ const o=/\{([^}/]+)\}/g,t=/^[A-Za-z_][A-Za-z0-9_]*$/;function n(e){const a=e.replace(/%7B/gi,"{").replace(/%7D/gi,"}"),l=new Set;for(const[,r]of a.matchAll(o))t.test(r)&&l.add(r);return[...l]}function s(e){const a=e.length>1?"placeholders":"placeholder",l=e.map(r=>`"${r}"`).join(", ");return`Unresolved ${a} ${l} in the URL. This is not a credentials problem. Replace every placeholder with a real value. Use the server variable default, or ask the user.`}export{n as findUnresolvedPlaceholders,s as unresolvedPlaceholderMessage};
@@ -1 +1 @@
1
- import{logger as S}from"../../../tools/notifiers/logger.js";import{mcpToolWorkers as M,MCP_TOOL_IS_AVAILABLE_KEY as v}from"../../../workers/mcp-tool-worker-pool.js";import{CREATE_ANONYMOUS_SESSION_TOOL_NAME as k}from"../constants.js";import{isAnonymousSessionToolAvailable as C}from"../docs-mcp/tools/core/create-anonymous-session.js";import{isManageApiCredentialsToolAvailable as L,manageApiCredentials as y,manageApiCredentialsSchema as D}from"../codemode/tools/manage-credentials.js";import{EXECUTE_TOOL_SCHEMA as A}from"../codemode/tools/execute-schema.js";import{EXECUTE_TOOL_NAME as w,CODE_MODE_TOOL_NAMES as N,FETCH_TOOL_NAME as x}from"../codemode/constants.js";import{buildCodeModeInstructions as H,buildExecuteDescription as I}from"../codemode/prompts.js";import{toToolListEntries as U}from"../codemode/build-tool-list.js";import{composeExecuteAnnotations as F,getActiveCapabilities as P}from"../codemode/capabilities/index.js";import{describeToolsSchema as R,describeTools as z}from"../codemode/tools/describe-tools.js";import{availableSandboxTools as W}from"../utils/available-sandbox-tools.js";import{toRegisterToolConfig as _}from"../utils/tool-registration.js";import{createMcpServer as X,createToolDispatch as Y,extractSerializableContext as $}from"./mcp-server.js";function g(c,r){const o=r.schema;if(C(c))return o;const{sessionHandle:f,...m}=o.properties;return{...o,properties:m}}async function ae({name:c,tools:r,context:o,skills:f=[],getKv:m}){const l=$(o),a=o.mcpMode==="code",s=a?P(o):[],T=s.some(e=>e.id===x),p=a?await W(r.filter(e=>!N.has(e.name)),l):[],b=U(p,s),O=a&&L(o),n=X(c,a?H(T,b):void 0),E={getClientCapabilities:()=>n.server.getClientCapabilities(),getKv:m},d=Y(l,E),u=async e=>{try{return await M.exec(v,[{toolName:e,context:l}],{timeout:1e4})}catch(i){return S.error(`Failed to check MCP tool availability for "${e}": ${i instanceof Error?i.message:String(i)}`),!1}};if(a){const e=[{tool:{...A,description:I(T,b),schema:g(o,A),annotations:F(s)},callback:d(w)},{tool:R(p,s),callback:z(p,u,s,o)}],i=r.find(t=>t.name===k);if(i&&C(o)&&e.push({tool:i,callback:d(i.name)}),O){const t=D(o);e.push({tool:{...t,schema:g(o,t)},callback:y(l,E)})}for(const{tool:t,callback:h}of e)n.registerTool(t.name,_(t),h)}else await Promise.all(r.map(async e=>{const i=n.registerTool(e.name,_(e),d(e.name));await u(e.name)||i.disable()}));for(const e of f)n.registerResource(e.slug,e.uri,{title:e.name,description:e.description,mimeType:"text/markdown"},async()=>({contents:[{uri:e.uri,mimeType:"text/markdown",text:e.content}]}));return n}export{ae as createDocsMcpServer};
1
+ import{logger as g}from"../../../tools/notifiers/logger.js";import{mcpToolWorkers as M,MCP_TOOL_IS_AVAILABLE_KEY as v}from"../../../workers/mcp-tool-worker-pool.js";import{CREATE_ANONYMOUS_SESSION_TOOL_NAME as k}from"../constants.js";import{isAnonymousSessionToolAvailable as C}from"../docs-mcp/tools/core/create-anonymous-session.js";import{isManageApiCredentialsToolAvailable as L,manageApiCredentials as y,manageApiCredentialsSchema as x}from"../codemode/tools/manage-credentials.js";import{EXECUTE_TOOL_SCHEMA as h}from"../codemode/tools/execute-schema.js";import{EXECUTE_TOOL_NAME as D,CODE_MODE_TOOL_NAMES as w,FETCH_TOOL_NAME as N}from"../codemode/constants.js";import{buildCodeModeInstructions as H,buildExecuteDescription as I}from"../codemode/prompts.js";import{toToolListEntries as U}from"../codemode/build-tool-list.js";import{composeExecuteAnnotations as F,getActiveCapabilities as P}from"../codemode/capabilities/index.js";import{describeToolsSchema as R,describeTools as z}from"../codemode/tools/describe-tools.js";import{availableSandboxTools as W}from"../utils/available-sandbox-tools.js";import{toRegisterToolConfig as A}from"../utils/tool-registration.js";import{createMcpServer as X,createToolDispatch as Y,extractSerializableContext as $}from"./mcp-server.js";function S(s,t){const o=t.schema;if(C(s))return o;const{sessionHandle:f,...p}=o.properties;return{...o,properties:p}}function j(s){return Object.fromEntries(s.map(t=>[t.name,t.schema]))}async function se({name:s,tools:t,context:o,skills:f=[],getKv:p}){const n=$(o),r=o.mcpMode==="code",c=r?P(o):[],T=c.some(e=>e.id===N),m=r?await W(t.filter(e=>!w.has(e.name)),n):[],b=U(m,c),O=r&&L(o),l=X(s,r?H(T,b):void 0),E={getClientCapabilities:()=>l.server.getClientCapabilities(),getKv:p},d=Y(r?{...n,sandboxToolSchemas:j(m)}:n,E),u=async e=>{try{return await M.exec(v,[{toolName:e,context:n}],{timeout:1e4})}catch(i){return g.error(`Failed to check MCP tool availability for "${e}": ${i instanceof Error?i.message:String(i)}`),!1}};if(r){const e=[{tool:{...h,description:I(T,b),schema:S(o,h),annotations:F(c)},callback:d(D)},{tool:R(m,c),callback:z(m,u,c,o)}],i=t.find(a=>a.name===k);if(i&&C(o)&&e.push({tool:i,callback:d(i.name)}),O){const a=x(o);e.push({tool:{...a,schema:S(o,a)},callback:y(n,E)})}for(const{tool:a,callback:_}of e)l.registerTool(a.name,A(a),_)}else await Promise.all(t.map(async e=>{const i=l.registerTool(e.name,A(e),d(e.name));await u(e.name)||i.disable()}));for(const e of f)l.registerResource(e.slug,e.uri,{title:e.name,description:e.description,mimeType:"text/markdown"},async()=>({contents:[{uri:e.uri,mimeType:"text/markdown",text:e.content}]}));return l}export{se as createDocsMcpServer};
@@ -1,5 +1,5 @@
1
- import{McpServer as j}from"@modelcontextprotocol/server";import{logger as b}from"../../../tools/notifiers/logger.js";import{mcpToolWorkers as D,MCP_TOOL_WORKER_KEY as F}from"../../../workers/mcp-tool-worker-pool.js";import{secretStore as K}from"../gateway-mcp/secret-store.js";import{readAuthRequiredMeta as L,stripAuthRequiredMeta as M,upstreamAuthKey as S}from"../gateway-mcp/upstream-auth.js";import{buildCredentialsToolHint as H,buildSchemeChoiceHint as B,buildUpstreamCredentialFallback as q,buildUpstreamCredentialInputRequired as P,isCredentialElicitationDeclined as $,schemeLabelOf as x}from"../gateway-mcp/elicitation.js";import{DEFAULT_SCHEME_NAME as T,resolveUpstreamApiAuth as N,schemeChoicesOf as v}from"../gateway-mcp/upstream-auth-scheme.js";import{MISSING_SESSION_HANDLE_MESSAGE as G,resolveSecretSubject as V}from"../gateway-mcp/subject.js";const W=6e4,E=new Map;function Y(e,t){const r=E.get(e);if(r)return r;const n=t().finally(()=>{E.delete(e)});return E.set(e,n),n}function pe(e,t){return new j({name:e,version:new Date().toISOString().slice(0,10)},{capabilities:{logging:{}},...t?{instructions:t}:{}})}function de(e,t){return r=>async(n,s)=>{b.info(`MCP tool called: ${r}`);const i=e.elicitationEnabled??!1,c=s.mcpReq.envelope!==void 0,a=i?V(e.user,n.sessionHandle):{kind:"anonymous"},o=a.kind==="resolved"?a.subject:void 0;if(a.kind==="invalid")return{content:[{type:"text",text:a.message}],isError:!0};const p=async()=>{if(!(!i||!o||!t?.getKv))try{const m=await t.getKv();return await K.getSecretsForSubject(m,o)}catch(m){b.warn(`gateway mcp secret store error, continuing unauthenticated: ${String(m)}`);return}};let u;const l=async()=>{u=await p();const m={toolName:r,args:n,context:{...e,upstreamSecrets:u},extra:re(s)};return await D.exec(F,[m],{timeout:W})};let d=await l();const f=L(d);if(f.length>0&&i&&!o)return M({...d,content:[{type:"text",text:G}],isError:!0});if(f.length>0&&i&&o&&t?.getKv){b.info(`gateway mcp credentials prompt: era=${c?"2026-07-28":"2025"} clientElicitation=${Q(t)}`);const m=await t.getKv(),h=await X(e,f),k=f.map(_=>Z(_,h)),y=z(u),g=c?await ee(e,s,k,o,m,y,h,t):await te(e,k,o,m,y,h);switch(g.kind){case"inputRequired":return g.result;case"retry":d=await l();break;case"prependText":d={...d,content:[{type:"text",text:g.text},...d.content],isError:!0};break;case"none":break}}return M(d)}}function J(e){return!!e?.getClientCapabilities()?.elicitation?.url}function Q(e){const t=e?.getClientCapabilities()?.elicitation;if(!t)return"none";const r=[t.form?"form":void 0,t.url?"url":void 0].filter(Boolean);return r.length>0?r.join("+"):"none"}async function X(e,t){const r=new Map;for(const n of new Set(t.map(s=>s.api)))r.set(n,await N(e,n));return r}function Z(e,t){const r=t.get(e.api);if(!r)return{...e,scheme:e.scheme??T};const n=e.scheme&&r.schemes[e.scheme]?e.scheme:r.defaultScheme;return{...e,scheme:n}}function z(e){const t=new Set;for(const[r,n]of Object.entries(e??{}))for(const s of Object.keys(n))t.add(S({api:r,scheme:s}));return t}function R(e,t){return e.status===401&&!t.has(S(e))}function A(e,t){const r=t.get(e.api),n=e.sentScheme??e.scheme;return r&&n?x(r.schemes,n):void 0}function I(e,t){const r=t.get(e.api);return!r||!e.schemes?.length?[]:v(r,e.schemes)}function C(e,t){return I(e,t).length>1}function w(e,t){return e.map(r=>H(r,A(r,t))).join(`
1
+ import{McpServer as j}from"@modelcontextprotocol/server";import{logger as b}from"../../../tools/notifiers/logger.js";import{mcpToolWorkers as D,MCP_TOOL_WORKER_KEY as F}from"../../../workers/mcp-tool-worker-pool.js";import{secretStore as K}from"../gateway-mcp/secret-store.js";import{readAuthRequiredMeta as L,stripAuthRequiredMeta as T,upstreamAuthKey as S}from"../gateway-mcp/upstream-auth.js";import{buildCredentialsToolHint as H,buildSchemeChoiceHint as B,buildUpstreamCredentialFallback as M,buildUpstreamCredentialInputRequired as P,isCredentialElicitationDeclined as $,schemeLabelOf as x}from"../gateway-mcp/elicitation.js";import{DEFAULT_SCHEME_NAME as q,resolveUpstreamApiAuth as N,schemeChoicesOf as v}from"../gateway-mcp/upstream-auth-scheme.js";import{MISSING_SESSION_HANDLE_MESSAGE as G,resolveSecretSubject as V}from"../gateway-mcp/subject.js";const W=6e4,E=new Map;function Y(e,t){const r=E.get(e);if(r)return r;const n=t().finally(()=>{E.delete(e)});return E.set(e,n),n}function de(e,t){return new j({name:e,version:new Date().toISOString().slice(0,10)},{capabilities:{logging:{}},...t?{instructions:t}:{}})}function pe(e,t){return r=>async(n,s)=>{b.info(`MCP tool called: ${r}`);const i=e.elicitationEnabled??!1,c=s.mcpReq.envelope!==void 0,a=i?V(e.user,n.sessionHandle):{kind:"anonymous"},o=a.kind==="resolved"?a.subject:void 0;if(a.kind==="invalid")return{content:[{type:"text",text:a.message}],isError:!0};const d=async()=>{if(!(!i||!o||!t?.getKv))try{const m=await t.getKv();return await K.getSecretsForSubject(m,o)}catch(m){b.warn(`gateway mcp secret store error, continuing unauthenticated: ${String(m)}`);return}};let u;const l=async()=>{u=await d();const m={toolName:r,args:n,context:{...e,upstreamSecrets:u},extra:re(s)};return await D.exec(F,[m],{timeout:W})};let p=await l();const f=L(p);if(f.length>0&&i&&!o)return T({...p,content:[{type:"text",text:G}],isError:!0});if(f.length>0&&i&&o&&t?.getKv){b.info(`gateway mcp credentials prompt: era=${c?"2026-07-28":"2025"} clientElicitation=${Q(t)}`);const m=await t.getKv(),h=await X(e,f),k=f.map(_=>Z(_,h)),y=z(u),g=c?await ee(e,s,k,o,m,y,h,t):await te(e,k,o,m,y,h);switch(g.kind){case"inputRequired":return g.result;case"retry":p=await l();break;case"prependText":p={...p,content:[{type:"text",text:g.text},...p.content],isError:!0};break;case"none":break}}return T(p)}}function J(e){return!!e?.getClientCapabilities()?.elicitation?.url}function Q(e){const t=e?.getClientCapabilities()?.elicitation;if(!t)return"none";const r=[t.form?"form":void 0,t.url?"url":void 0].filter(Boolean);return r.length>0?r.join("+"):"none"}async function X(e,t){const r=new Map;for(const n of new Set(t.map(s=>s.api)))r.set(n,await N(e,n));return r}function Z(e,t){const r=t.get(e.api);if(!r)return{...e,scheme:e.scheme??q};const n=e.scheme&&r.schemes[e.scheme]?e.scheme:r.defaultScheme;return{...e,scheme:n}}function z(e){const t=new Set;for(const[r,n]of Object.entries(e??{}))for(const s of Object.keys(n))t.add(S({api:r,scheme:s}));return t}function R(e,t){return e.status===401&&!t.has(S(e))}function A(e,t){const r=t.get(e.api),n=e.sentScheme??e.scheme;return r&&n?x(r.schemes,n):void 0}function I(e,t){const r=t.get(e.api);return!r||!e.schemes?.length?[]:v(r,e.schemes)}function C(e,t){return I(e,t).length>1}function w(e,t){return e.map(r=>H(r,A(r,t))).join(`
2
2
 
3
3
  `)}function U(e,t,r){const n=e.map(s=>B(s,I(s,r)));return t.length>0&&n.push(w(t,r)),n.join(`
4
4
 
5
- `)}function O(e,t,r,n,s){const[i,...c]=t,a=s.get(i.api),o=i.scheme??a?.defaultScheme??T,p=A(i,s);return{subject:r,baseUrl:e.baseUrl??"",target:{api:i.api,name:i.name,scheme:o,...p?{schemeLabel:p}:{}},auth:a?.schemes[o]??{kind:"raw"},...a?{apiAuth:a}:{},kv:n,hasExistingSecret:!1,reason:{kind:"authFailure",status:i.status,...i.detail?{detail:i.detail}:{},otherApiNames:c.map(u=>u.name)}}}async function ee(e,t,r,n,s,i,c,a){if($(t.mcpReq.inputResponses))return{kind:"none"};const o=r.filter(l=>R(l,i));if(o.length===0)return{kind:"prependText",text:w(r,c)};const p=o.filter(l=>C(l,c));if(p.length>0){const l=r.filter(d=>!p.includes(d));return{kind:"prependText",text:U(p,l,c)}}const u=O(e,o,n,s,c);return J(a)?{kind:"inputRequired",result:await P(u)}:{kind:"prependText",text:await q(u)}}async function te(e,t,r,n,s,i){const c=t.filter(u=>R(u,s));if(c.length===0)return{kind:"prependText",text:w(t,i)};const a=c.filter(u=>C(u,i));if(a.length>0){const u=t.filter(l=>!a.includes(l));return{kind:"prependText",text:U(a,u,i)}}const o=O(e,c,r,n,i);return{kind:"prependText",text:await Y(`${r}:${S(c[0])}`,()=>q(o))}}function re(e){return{sessionId:e.sessionId,authInfo:e.http?.authInfo,requestId:e.mcpReq.id,_meta:e.mcpReq._meta}}function me(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,upstreamAuthorization:e.upstreamAuthorization,mcpMode:e.mcpMode,elicitationEnabled:e.elicitationEnabled,gatewayFetchBudgetPerExec:e.gatewayFetchBudgetPerExec,clientIp:e.clientIp,client:e.client,clientVersion:e.clientVersion,upstreamSecrets:e.upstreamSecrets,searchIgnoredRoutes:e.searchIgnoredRoutes,internalBaseUrl:e.internalBaseUrl,fs:void 0}}export{pe as createMcpServer,de as createToolDispatch,me as extractSerializableContext};
5
+ `)}function O(e,t,r,n,s){const[i,...c]=t,a=s.get(i.api),o=i.scheme??a?.defaultScheme??q,d=A(i,s);return{subject:r,baseUrl:e.baseUrl??"",target:{api:i.api,name:i.name,scheme:o,...d?{schemeLabel:d}:{}},auth:a?.schemes[o]??{kind:"raw"},...a?{apiAuth:a}:{},kv:n,hasExistingSecret:!1,reason:{kind:"authFailure",status:i.status,...i.detail?{detail:i.detail}:{},otherApiNames:c.map(u=>u.name)}}}async function ee(e,t,r,n,s,i,c,a){if($(t.mcpReq.inputResponses))return{kind:"none"};const o=r.filter(l=>R(l,i));if(o.length===0)return{kind:"prependText",text:w(r,c)};const d=o.filter(l=>C(l,c));if(d.length>0){const l=r.filter(p=>!d.includes(p));return{kind:"prependText",text:U(d,l,c)}}const u=O(e,o,n,s,c);return J(a)?{kind:"inputRequired",result:await P(u)}:{kind:"prependText",text:await M(u)}}async function te(e,t,r,n,s,i){const c=t.filter(u=>R(u,s));if(c.length===0)return{kind:"prependText",text:w(t,i)};const a=c.filter(u=>C(u,i));if(a.length>0){const u=t.filter(l=>!a.includes(l));return{kind:"prependText",text:U(a,u,i)}}const o=O(e,c,r,n,i);return{kind:"prependText",text:await Y(`${r}:${S(c[0])}`,()=>M(o))}}function re(e){return{sessionId:e.sessionId,authInfo:e.http?.authInfo,requestId:e.mcpReq.id,_meta:e.mcpReq._meta}}function me(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,upstreamAuthorization:e.upstreamAuthorization,mcpMode:e.mcpMode,elicitationEnabled:e.elicitationEnabled,gatewayFetchBudgetPerExec:e.gatewayFetchBudgetPerExec,clientIp:e.clientIp,client:e.client,clientVersion:e.clientVersion,upstreamSecrets:e.upstreamSecrets,searchIgnoredRoutes:e.searchIgnoredRoutes,internalBaseUrl:e.internalBaseUrl,sandboxToolSchemas:e.sandboxToolSchemas,fs:void 0}}export{de as createMcpServer,pe as createToolDispatch,me as extractSerializableContext};
@@ -107,6 +107,7 @@ export type McpToolContext = Omit<ApiFunctionsContext, 'telemetry' | 'getKv' | k
107
107
  upstreamSecrets?: UpstreamSecrets;
108
108
  searchIgnoredRoutes?: string[];
109
109
  internalBaseUrl?: string;
110
+ sandboxToolSchemas?: Record<string, Record<string, unknown>>;
110
111
  fs?: McpToolFileSystem;
111
112
  };
112
113
  export type McpToolHandler<TArgs extends ToolArgs = ToolArgs> = (args: TArgs, context: McpToolContext, extra: McpToolExtra) => Promise<McpToolWorkerResponse | McpToolJsonValue>;
@@ -1 +1 @@
1
- import{logger as i}from"../../../tools/notifiers/logger.js";import{mcpToolWorkers as a,MCP_TOOL_AVAILABILITY_KEY as m}from"../../../workers/mcp-tool-worker-pool.js";async function p(o,t){if(o.length===0)return o;const l=o.map(r=>r.name);let e;try{e=await a.exec(m,[{toolNames:l,context:t}],{timeout:1e4})}catch(r){return i.error(`Failed to resolve MCP tool availability: ${r instanceof Error?r.message:String(r)}`),o}return!e||typeof e!="object"?o:o.filter(r=>e[r.name]!==!1)}export{p as availableSandboxTools};
1
+ import{logger as a}from"../../../tools/notifiers/logger.js";import{mcpToolWorkers as n,MCP_TOOL_AVAILABILITY_KEY as m}from"../../../workers/mcp-tool-worker-pool.js";async function p(t,l){if(t.length===0)return t;const e=t.map(o=>o.name);let r;try{r=await n.exec(m,[{toolNames:e,context:l}],{timeout:1e4})}catch(o){return i(t,o instanceof Error?o.message:String(o))}return!r||typeof r!="object"?i(t,"the worker returned no availability map"):t.filter(o=>r[o.name]!==!1)}function i(t,l){const e=t.filter(r=>r.hasAvailabilityGate);return e.length===0?t:(a.warn(`MCP tool availability is unknown (${l}); the sandbox tool list drops the gated tools: ${e.map(r=>r.name).join(", ")}.`),t.filter(r=>!r.hasAvailabilityGate))}export{p as availableSandboxTools};
@@ -1 +1 @@
1
- import p from"node:path";import{existsSync as O}from"node:fs";import{writeFile as h,access as y,rm as v,constants as b}from"fs/promises";import{REDOCLY_TEAMS_RBAC as N}from"@redocly/config";import{DEFAULT_LOCALE_PLACEHOLDER as P}from"../../../../constants/common.js";import{AI_INDEX_EXPORT_FOLDER as X}from"../../../constants/plugins/search.js";import{LLMS_TXT_FILE_NAME as $}from"../../../constants/common.js";import{envConfig as j}from"../../../config/env-config.js";import{logger as n}from"../../../tools/notifiers/logger.js";import{shaHexShort as B}from"../../../utils/crypto/sha-hex-short.js";import{promiseMapLimit as D}from"../../../utils/async/promise-map-limit.js";import{getLlmsTxtMdPathBySlug as G}from"../../../utils/llmstxt/get-llms-txt-md-path-by-slug.js";import{validateLLMsTxtConfig as H,generateLLMsTxt as k}from"../llmstxt/index.js";import{buildPageLlmsTxtMd as J}from"../llmstxt/build-page-llms-txt-md.js";import{getLlmsTxtExcludeMatcher as K}from"../llmstxt/get-llms-txt-exclude-matcher.js";import{isIncludedInLlmsTxt as U}from"../llmstxt/is-included-in-llms-txt.js";import{getRouteStaticData as V}from"../../../utils/get-route-static-data.js";import{getRouteAiDocumentsStore as W}from"../../../utils/get-route-ai-documents-store.js";import{ensureDir as R}from"../../../utils/fs.js";import{extractTeamsFromScopeItems as Y,getRbacTeamsListForResource as q}from"../../../utils/rbac.js";const _=20,S="llms.txt:";async function ht(t,m,{embeddingsEnabled:e,writeLlmstxtFiles:l}){const c=p.join(t.outdir,$);if(!l){try{await y(c,b.W_OK),await v(c)}catch{}if(!e)return}e&&n.info("Preparing semantic documents..."),l&&n.info(`${S} Generating llms.txt files...`);const g=n.startTiming(),r=n.startTiming(),s=t.getGlobalConfig("seo"),f=s?.llmstxt,T=p.resolve(t.outdir,X),u=t.getConfig(),A=u.access?.rbac??{},M=t.getAllRoutes(),C=u?.l10n?.defaultLocale||u?.i18n?.defaultLocale||P,E=K(s),L=[];if(await D(M,_,async o=>{if(o.excludeFromSearch)return;const w=await V(o,t),x=await W(o,w,m,t);if(x){if(l)for(const i of await x.getLLMsTxts()){if(E(i.fsPath))continue;const d=G(i.slug),a=p.join(t.outdir,d);R(a),await h(a,J(i,s)),U(i,o,u)&&L.push(i)}if(e&&j.isBuildMode){const i=await x.getSearchDocuments();if(!i.length)return;const d=z(o,A),a=o.versions?.find(({active:F})=>F),I=a&&{folder:a.folderId,label:a.label,default:a.default};await Q(i,o.fsPath,d,T,C,I)}}}),e&&n.infoTime(r,"Semantic search documents prepared"),L.length)try{H(f);const o=await k(L,f,{title:s?.title,description:s?.description},m);R(c),await h(c,o),n.infoTime(g,`${S} files generated`)}catch(o){n.error(`${S} Failed to generate llms.txt file. ${o.message}`)}}function z(t,m){const e=Y(t?.[N]);return e?.length?e:q(t,m)}async function Q(t,m,e,l,c,g){await D(t,_,async r=>{const s=`${B(m+r.content)}.json`,f=R(p.join(l,s)),T=r.locale===P?c:r.locale;O(f)||await h(f,JSON.stringify({...r,rbacTeams:r.rbacTeams??e??[],version:g,locale:T}),"utf-8")})}export{ht as prepareSemanticDocuments};
1
+ import p from"node:path";import{existsSync as O}from"node:fs";import{writeFile as h,access as y,rm as v,constants as b}from"fs/promises";import{REDOCLY_TEAMS_RBAC as N}from"@redocly/config";import{DEFAULT_LOCALE_PLACEHOLDER as P}from"../../../../constants/common.js";import{AI_INDEX_EXPORT_FOLDER as X}from"../../../constants/plugins/search.js";import{LLMS_TXT_FILE_NAME as $}from"../../../constants/common.js";import{envConfig as j}from"../../../config/env-config.js";import{logger as n}from"../../../tools/notifiers/logger.js";import{shaHexShort as B}from"../../../utils/crypto/sha-hex-short.js";import{promiseMapLimit as D}from"../../../utils/async/promise-map-limit.js";import{getLlmsTxtMdPathBySlug as G}from"../../../utils/llmstxt/get-llms-txt-md-path-by-slug.js";import{validateLLMsTxtConfig as U,generateLLMsTxt as H}from"../llmstxt/index.js";import{buildPageLlmsTxtMd as k}from"../llmstxt/build-page-llms-txt-md.js";import{getLlmsTxtExcludeMatcher as J}from"../llmstxt/get-llms-txt-exclude-matcher.js";import{isIncludedInLlmsTxt as K}from"../llmstxt/is-included-in-llms-txt.js";import{getRouteStaticData as V}from"../../../utils/get-route-static-data.js";import{getRouteAiDocumentsStore as W}from"../../../utils/get-route-ai-documents-store.js";import{ensureDir as R}from"../../../utils/fs.js";import{extractTeamsFromScopeItems as Y,getRbacTeamsListForResource as q}from"../../../utils/rbac.js";const _=20,S="llms.txt:";async function ht(t,m,{embeddingsEnabled:e,writeLlmstxtFiles:l}){const c=p.join(t.outdir,$);if(!l){try{await y(c,b.W_OK),await v(c)}catch{}if(!e)return}e&&n.info("Preparing semantic documents..."),l&&n.info(`${S} Generating llms.txt files...`);const g=n.startTiming(),s=n.startTiming(),i=t.getGlobalConfig("seo"),f=i?.llmstxt,T=p.resolve(t.outdir,X),u=t.getConfig(),A=u.access?.rbac??{},M=t.getAllRoutes(),C=u?.l10n?.defaultLocale||u?.i18n?.defaultLocale||P,E=J(i),L=[];if(await D(M,_,async o=>{if(o.excludeFromSearch)return;const w=await V(o,t),x=await W(o,w,m,t);if(x){if(l)for(const r of await x.getLLMsTxts()){if(E(r.fsPath))continue;const d=G(r.slug),a=p.join(t.outdir,d);R(a),await h(a,k(r,i)),K(r,o,u)&&L.push(r)}if(e&&j.isBuildMode){const r=await x.getSearchDocuments();if(!r.length)return;const d=z(o,A),a=o.versions?.find(({active:F})=>F),I=a&&{folder:a.folderId,label:a.label,default:a.default};await Q(r,o.fsPath,d,T,C,I)}}}),e&&n.infoTime(s,"Semantic search documents prepared"),L.length)try{U(f);const o=await H(L,f,{title:i?.title,description:i?.description,siteUrl:i?.siteUrl},m);R(c),await h(c,o),n.infoTime(g,`${S} files generated`)}catch(o){n.error(`${S} Failed to generate llms.txt file. ${o.message}`)}}function z(t,m){const e=Y(t?.[N]);return e?.length?e:q(t,m)}async function Q(t,m,e,l,c,g){await D(t,_,async s=>{const i=`${B(m+s.content)}.json`,f=R(p.join(l,i)),T=s.locale===P?c:s.locale;O(f)||await h(f,JSON.stringify({...s,rbacTeams:s.rbacTeams??e??[],version:g,locale:T}),"utf-8")})}export{ht as prepareSemanticDocuments};
@@ -1 +1 @@
1
- import p from"node:path";import{logger as f}from"../../../tools/notifiers/logger.js";import{promiseMapLimit as x}from"../../../utils/async/promise-map-limit.js";import{getLlmsTxtMdPathBySlug as L}from"../../../utils/llmstxt/get-llms-txt-md-path-by-slug.js";import{getRouteStaticData as T}from"../../../utils/get-route-static-data.js";import{getRouteAiDocumentsStore as w}from"../../../utils/get-route-ai-documents-store.js";import{generateLLMsTxt as h,validateLLMsTxtConfig as M}from"./index.js";import{buildPageLlmsTxtMd as S}from"./build-page-llms-txt-md.js";import{getLlmsTxtExcludeMatcher as m}from"./get-llms-txt-exclude-matcher.js";import{isIncludedInLlmsTxt as R}from"./is-included-in-llms-txt.js";import{EntitlementsProvider as C}from"../../../entitlements/entitlements-provider.js";const A=20;function v(i,c){const a=new WeakMap,l=()=>{const t=i.getGlobalConfig("seo");return C.instance().canAccessFeature("seo")===!0&&t?.llmstxt?.hide!==!0},d=async t=>{if(t.excludeFromSearch)return[];const e=i,n=await T(t,e);return await(await w(t,n,c,e))?.getLLMsTxts()??[]},u=t=>{const e=a.get(t);if(e)return e;const n=d(t).catch(o=>(a.delete(t),f.warn(`Failed to generate Markdown for LLMs of "${t.slug}". ${o}`),[]));return a.set(t,n),n},g=t=>{const e=t==="/index.html.md"?"/":t.replace(/\.md$/,"");for(let n=e;n.startsWith("/");){const o=i.getRouteBySlug(n,{followRedirect:!1});if(o?.getAiDocumentsStore)return o;const r=p.posix.dirname(n);if(r===n)return;n=r}};return{async getPageMarkdown(t){if(!l())return;const e=g(t);if(!e)return;const n=i.getGlobalConfig("seo"),o=m(n),r=(await u(e)).find(s=>L(s.slug)===t&&!o(s.fsPath));if(r)return{route:e,content:S(r,n)}},async getLlmsTxt(){if(!l())return;const t=i.getConfig(),e=i.getGlobalConfig("seo"),n=m(e),o=[];if(await x(i.getAllRoutes(),A,async r=>{for(const s of await u(r))!n(s.fsPath)&&R(s,r,t)&&o.push(s)}),!!o.length)try{return M(e?.llmstxt),await h(o,e?.llmstxt,{title:e?.title,description:e?.description},c)}catch(r){f.error(`Failed to generate llms.txt. ${r}`);return}}}}export{v as createLlmsTxtGenerator};
1
+ import p from"node:path";import{logger as f}from"../../../tools/notifiers/logger.js";import{promiseMapLimit as x}from"../../../utils/async/promise-map-limit.js";import{getLlmsTxtMdPathBySlug as L}from"../../../utils/llmstxt/get-llms-txt-md-path-by-slug.js";import{getRouteStaticData as T}from"../../../utils/get-route-static-data.js";import{getRouteAiDocumentsStore as w}from"../../../utils/get-route-ai-documents-store.js";import{generateLLMsTxt as h,validateLLMsTxtConfig as M}from"./index.js";import{buildPageLlmsTxtMd as S}from"./build-page-llms-txt-md.js";import{getLlmsTxtExcludeMatcher as m}from"./get-llms-txt-exclude-matcher.js";import{isIncludedInLlmsTxt as R}from"./is-included-in-llms-txt.js";import{EntitlementsProvider as C}from"../../../entitlements/entitlements-provider.js";const A=20;function v(i,c){const a=new WeakMap,l=()=>{const t=i.getGlobalConfig("seo");return C.instance().canAccessFeature("seo")===!0&&t?.llmstxt?.hide!==!0},d=async t=>{if(t.excludeFromSearch)return[];const e=i,n=await T(t,e);return await(await w(t,n,c,e))?.getLLMsTxts()??[]},u=t=>{const e=a.get(t);if(e)return e;const n=d(t).catch(o=>(a.delete(t),f.warn(`Failed to generate Markdown for LLMs of "${t.slug}". ${o}`),[]));return a.set(t,n),n},g=t=>{const e=t==="/index.html.md"?"/":t.replace(/\.md$/,"");for(let n=e;n.startsWith("/");){const o=i.getRouteBySlug(n,{followRedirect:!1});if(o?.getAiDocumentsStore)return o;const r=p.posix.dirname(n);if(r===n)return;n=r}};return{async getPageMarkdown(t){if(!l())return;const e=g(t);if(!e)return;const n=i.getGlobalConfig("seo"),o=m(n),r=(await u(e)).find(s=>L(s.slug)===t&&!o(s.fsPath));if(r)return{route:e,content:S(r,n)}},async getLlmsTxt(){if(!l())return;const t=i.getConfig(),e=i.getGlobalConfig("seo"),n=m(e),o=[];if(await x(i.getAllRoutes(),A,async r=>{for(const s of await u(r))!n(s.fsPath)&&R(s,r,t)&&o.push(s)}),!!o.length)try{return M(e?.llmstxt),await h(o,e?.llmstxt,{title:e?.title,description:e?.description,siteUrl:e?.siteUrl},c)}catch(r){f.error(`Failed to generate llms.txt. ${r}`);return}}}}export{v as createLlmsTxtGenerator};
@@ -4,11 +4,13 @@ import type { LLMsTxt } from './types';
4
4
  export declare function generateLLMsTxt(llmstxts: LLMsTxt[], llmstxtConfig: SeoConfig['llmstxt'] | undefined, fallbackConfig: {
5
5
  title?: string;
6
6
  description?: string;
7
+ siteUrl: string | undefined;
7
8
  } | undefined, context: LifecycleContext): Promise<string>;
8
- export declare function llmsTxtLink({ title, description, slug, }: {
9
+ export declare function llmsTxtLink({ title, description, slug, siteUrl, }: {
9
10
  title: LLMsTxt['title'];
10
11
  description: LLMsTxt['description'];
11
12
  slug: LLMsTxt['slug'];
13
+ siteUrl?: string;
12
14
  }): string;
13
15
  export declare function validateLLMsTxtConfig(llmstxtConfig: SeoConfig['llmstxt']): void;
14
16
  //# sourceMappingURL=index.d.ts.map
@@ -1,13 +1,13 @@
1
- import d from"picomatch";import{dirname as T,resolve as x}from"node:path";import{access as $,readFile as E,constants as F}from"fs/promises";import{removeTrailingSlash as w}from"../../../../utils/url/remove-trailing-slash.js";import{logger as g}from"../../../tools/notifiers/logger.js";import{withPathPrefix as y}from"@redocly/theme/core/utils";import{envConfig as I}from"../../../config/env-config.js";import{getLlmsTxtMdPathBySlug as v}from"../../../utils/llmstxt/get-llms-txt-md-path-by-slug.js";const a="llms.txt",u="Table of contents";async function D(t,e,n={title:a,description:void 0},o){if(!e)return{title:n.title||a,description:n.description,details:void 0,sections:[{title:u,description:void 0,llmstxts:t}]};const s=e.title||n.title||a,r=e.description||n.description,i=await M(e,o),c=e.sections?.map(l=>{const{title:f,description:h,excludeFiles:m,includeFiles:L}=l,P=p(t,{excludeFiles:m,includeFiles:L});return{title:f,description:h,llmstxts:P}});return{title:s,description:r,details:i,sections:c||[{title:u,description:void 0,llmstxts:p(t,{includeFiles:["**/*"],excludeFiles:[]})}]}}async function M(t,e){const n=await e.getConfig();if(t?.details?.path&&n.configPath)try{const o=e.fs.getFileInfo(n.configPath);if(!o)throw new Error(`Config file ${n.configPath} not found`);const s=x(e.fs.cwd,T(o.relativePath),t.details.path);return await $(s,F.R_OK),E(s,"utf-8")}catch{throw new Error(`${t.details.path} is not accessible`)}if(t?.details?.content)return t.details.content}function p(t,e){const{excludeFiles:n,includeFiles:o}=e,s=n?.map(i=>d(i)),r=o?.map(i=>d(i));return t.filter(i=>s?.some(l=>l(i.fsPath))?!1:r?.some(l=>l(i.fsPath)))}async function j(t,e,n={title:a,description:void 0},o){const s=await D(t,e,n,o),r=[`# ${s.title}
1
+ import d from"picomatch";import{dirname as T,resolve as $}from"node:path";import{access as x,readFile as E,constants as F}from"fs/promises";import{removeTrailingSlash as w}from"../../../../utils/url/remove-trailing-slash.js";import{logger as g}from"../../../tools/notifiers/logger.js";import{withPathPrefix as U}from"@redocly/theme/core/utils";import{envConfig as y}from"../../../config/env-config.js";import{getLlmsTxtMdPathBySlug as I}from"../../../utils/llmstxt/get-llms-txt-md-path-by-slug.js";const a="llms.txt",u="Table of contents";async function v(e,i,n={title:a,description:void 0},r){if(!i)return{title:n.title||a,description:n.description,details:void 0,sections:[{title:u,description:void 0,llmstxts:e}]};const s=i.title||n.title||a,l=i.description||n.description,t=await D(i,r),o=i.sections?.map(c=>{const{title:f,description:h,excludeFiles:m,includeFiles:L}=c,P=p(e,{excludeFiles:m,includeFiles:L});return{title:f,description:h,llmstxts:P}});return{title:s,description:l,details:t,sections:o||[{title:u,description:void 0,llmstxts:p(e,{includeFiles:["**/*"],excludeFiles:[]})}]}}async function D(e,i){const n=await i.getConfig();if(e?.details?.path&&n.configPath)try{const r=i.fs.getFileInfo(n.configPath);if(!r)throw new Error(`Config file ${n.configPath} not found`);const s=$(i.fs.cwd,T(r.relativePath),e.details.path);return await x(s,F.R_OK),E(s,"utf-8")}catch{throw new Error(`${e.details.path} is not accessible`)}if(e?.details?.content)return e.details.content}function p(e,i){const{excludeFiles:n,includeFiles:r}=i,s=n?.map(t=>d(t)),l=r?.map(t=>d(t));return e.filter(t=>s?.some(c=>c(t.fsPath))?!1:l?.some(c=>c(t.fsPath)))}async function b(e,i,n={title:a,description:void 0,siteUrl:void 0},r){const s=await v(e,i,n,r),l=n.siteUrl,t=[`# ${s.title}
2
2
 
3
- `];return s.description&&r.push(`> ${s.description}
3
+ `];return s.description&&t.push(`> ${s.description}
4
4
 
5
- `),s.details&&r.push(`${s.details}
5
+ `),s.details&&t.push(`${s.details}
6
6
 
7
- `),s.sections.forEach(i=>{if(!i.llmstxts.length){g.warn(`llms.txt: No links found for section "${i.title}". Please check the includeFiles/excludeFiles patterns.`);return}r.push(`## ${i.title}
8
- `),i.description?r.push(`${i.description.replace(/\n+$/,"")}
7
+ `),s.sections.forEach(o=>{if(!o.llmstxts.length){g.warn(`llms.txt: No links found for section "${o.title}". Please check the includeFiles/excludeFiles patterns.`);return}t.push(`## ${o.title}
8
+ `),o.description?t.push(`${o.description.replace(/\n+$/,"")}
9
9
 
10
- `):r.push(`
11
- `),i.llmstxts.forEach(c=>{r.push(` - ${_({title:c.title,description:c.description,slug:v(c.slug)})}`)}),r.push(`
12
- `)}),r.join("")}function _({title:t,description:e,slug:n}){const o=e?.replace(/\s+/g," ").trim();return`[${t}](${w(I.REDOCLY_PUBLIC_URL||"")}${encodeURI(y(n))})${o?`: ${o}`:""}
13
- `}function K(t){if(t?.details?.path&&t?.details?.content)throw new Error('"details.path" and "details.content" are mutually exclusive. Please use only one of them.')}export{j as generateLLMsTxt,_ as llmsTxtLink,K as validateLLMsTxtConfig};
10
+ `):t.push(`
11
+ `),o.llmstxts.forEach(c=>{t.push(` - ${M({title:c.title,description:c.description,slug:I(c.slug),siteUrl:l})}`)}),t.push(`
12
+ `)}),t.join("")}function M({title:e,description:i,slug:n,siteUrl:r}){const l=`${w(r?.trim()||y.REDOCLY_PUBLIC_URL||"")}${encodeURI(U(n))}`,t=i?.replace(/\s+/g," ").trim();return`[${e}](${l})${t?`: ${t}`:""}
13
+ `}function j(e){if(e?.details?.path&&e?.details?.content)throw new Error('"details.path" and "details.content" are mutually exclusive. Please use only one of them.')}export{b as generateLLMsTxt,M as llmsTxtLink,j as validateLLMsTxtConfig};
@@ -1,3 +1,3 @@
1
- import p from"@jitl/quickjs-singlefile-mjs-release-sync";import{newQuickJSWASMModuleFromVariant as _,newVariant as E}from"quickjs-emscripten-core";import{createExecutionBudget as S}from"./utils/execution-budget.js";import{returnsFromTopLevel as A}from"./utils/returns-from-top-level.js";import{DEFAULT_MAX_LIFETIME_MS as y,DEFAULT_TIMEOUT_MS as b,INITIAL_TOTAL_MEMORY_BYTES as h,MAX_ALLOCATION_BYTES as L,MAX_RESULT_BYTES as g,MAX_STACK_SIZE_BYTES as w,MAX_TOTAL_MEMORY_BYTES as x,WASM_PAGE_BYTES as d}from"./constants/sandbox.js";let c;function I(){return c??=_(E(p,{wasmMemory:new WebAssembly.Memory({initial:h/d,maximum:x/d})}))}async function P(t,l={}){const{timeoutMs:m=b,maxLifetimeMs:f=y,setupContext:M}=l,e=(await I()).newContext();let n,i,r;try{e.runtime.setMemoryLimit(L),e.runtime.setMaxStackSize(w),n=S(e,m,f),i=M?.(e,n)??void 0,r=e.unwrapResult(e.evalCode(`(async () => {
1
+ import T from"@jitl/quickjs-singlefile-mjs-release-sync";import{newQuickJSWASMModuleFromVariant as p,newVariant as _}from"quickjs-emscripten-core";import{createExecutionBudget as S}from"./utils/execution-budget.js";import{returnsFromTopLevel as A}from"./utils/returns-from-top-level.js";import{DEFAULT_MAX_LIFETIME_MS as x,DEFAULT_TIMEOUT_MS as b,INITIAL_TOTAL_MEMORY_BYTES as y,MAX_ALLOCATION_BYTES as g,MAX_RESULT_BYTES as L,MAX_STACK_SIZE_BYTES as h,MAX_TOTAL_MEMORY_BYTES as w,WASM_PAGE_BYTES as f}from"./constants/sandbox.js";let M;function I(){return M??=p(_(T,{wasmMemory:new WebAssembly.Memory({initial:y/f,maximum:w/f})}))}async function j(t,s={}){const{timeoutMs:n=b,maxLifetimeMs:u=x,setupContext:E}=s,e=(await I()).newContext();let r,l,a;try{e.runtime.setMemoryLimit(g),e.runtime.setMaxStackSize(h),r=S(e,n,u),l=E?.(e,r)??void 0,a=e.unwrapResult(e.evalCode(`(async () => {
2
2
  ${t}
3
- })()`));const o=e.resolvePromise(r);e.runtime.executePendingJobs();const T=await Promise.race([o,n.aborted]),u=e.unwrapResult(T),s=e.dump(u);if(u.dispose(),s===void 0)return{error:A(e,t)?"The code returned undefined: the `return` ran but produced no value. Read fields off the declared return types \u2014 a field name that does not exist reads as undefined \u2014 and do not `return;` or `return undefined`.":"The code returned undefined because nothing was returned. Add a top-level `return`: a value computed inside a function or IIFE is discarded unless you return it, and a promise chain has to be returned to be awaited."};const a=JSON.stringify(s??null).length;return a>g?{error:`Result is too large (${a} bytes); return less data`}:{result:s}}catch(o){return{error:v(o)}}finally{n?.dispose(),r?.dispose();try{i?.()}catch{}try{e.dispose()}catch{c=void 0}}}function v(t){return t instanceof Error?t.message:String(t)}export{P as runInSandbox};
3
+ })()`,R));const i=e.resolvePromise(a);e.runtime.executePendingJobs();const d=await Promise.race([i,r.aborted]),o=e.unwrapResult(d),c=e.dump(o);if(o.dispose(),c===void 0)return{error:A(e,t)?"The code returned undefined: the `return` ran but produced no value. Read fields off the declared return types \u2014 a field name that does not exist reads as undefined \u2014 and do not `return;` or `return undefined`.":"The code returned undefined because nothing was returned. Add a top-level `return` of the value to send back."};const m=JSON.stringify(c??null).length;return m>L?{error:`Result is too large (${m} bytes); return less data`}:{result:c}}catch(i){const d=r?.expiredMessage();if(d!==void 0)return{error:d};const o=v(i);return{error:O(i),...o?{errorPosition:o}:{}}}finally{r?.dispose(),a?.dispose();try{l?.()}catch{}try{e.dispose()}catch{M=void 0}}}function O(t){return t instanceof Error?t.message:String(t)}const R="sandbox-code.js",k=/sandbox-code\.js:(\d+):(\d+)/;function v(t){const s=t.cause?.stack,n=typeof s=="string"?k.exec(s):null;if(!n)return;const u=Number(n[1])-1;return u>=1?{line:u,column:Number(n[2])}:void 0}export{j as runInSandbox};
@@ -1,7 +1,13 @@
1
1
  import type { QuickJSContext } from 'quickjs-emscripten-core';
2
+ /** 1-based position in the submitted code where the guest error was thrown. */
3
+ export type GuestPosition = {
4
+ line: number;
5
+ column: number;
6
+ };
2
7
  export type SandboxResult = {
3
8
  result?: unknown;
4
9
  error?: string;
10
+ errorPosition?: GuestPosition;
5
11
  };
6
12
  export type ExecutionBudget = {
7
13
  /**
@@ -13,6 +19,8 @@ export type ExecutionBudget = {
13
19
  hostCall<T>(work: () => Promise<T>): Promise<T>;
14
20
  /** Rejects when a wall-clock deadline fires */
15
21
  aborted: Promise<never>;
22
+ /** The message of the deadline that fired, or `undefined` while the run is still in budget */
23
+ expiredMessage(): string | undefined;
16
24
  dispose(): void;
17
25
  };
18
26
  export type SetupSandboxContext = (context: QuickJSContext, budget: ExecutionBudget) => void | (() => void);
@@ -1 +1 @@
1
- function f(c,t,i){const d=Date.now()+i;let l=Date.now()+t,u=t,a=()=>{};const T=new Promise((e,o)=>{a=r=>o(new Error(r))});let n;const m=()=>{clearTimeout(n),n=setTimeout(()=>a(`Execution timed out after ${t}ms`),t)};c.runtime.setInterruptHandler(()=>{const e=Date.now();return e>l||e>d}),m();const w=setTimeout(()=>a(`Exceeded the maximum lifetime of ${i}ms`),i);let s=0;return{hostCall:e=>{u=l-Date.now(),s++,clearTimeout(n);const o=()=>{c.alive&&(l=Date.now()+u,--s===0&&m())},r=e();return r.then(o,o),r},aborted:T,dispose(){clearTimeout(n),clearTimeout(w)}}}export{f as createExecutionBudget};
1
+ function h(c,i,l){const u=`Execution timed out after ${i}ms`,m=`Exceeded the maximum lifetime of ${l}ms`,w=Date.now()+l;let s=Date.now()+i,d=i,e,a=()=>{};const p=new Promise((t,r)=>{a=n=>{e=n,r(new Error(n))}});let o;const f=()=>{clearTimeout(o),o=setTimeout(()=>a(u),i)};c.runtime.setInterruptHandler(()=>{const t=Date.now();return t>s?e=u:t>w&&(e=m),e!==void 0}),f();const D=setTimeout(()=>a(m),l);let T=0;return{hostCall:t=>{d=s-Date.now(),T++,clearTimeout(o);const r=()=>{c.alive&&(s=Date.now()+d,--T===0&&f())},n=t();return n.then(r,r),n},aborted:p,expiredMessage:()=>e,dispose(){clearTimeout(o),clearTimeout(D)}}}export{h as createExecutionBudget};
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Prefixes the last top-level statement with `return ` when it is a bare expression, so sandbox
3
+ * code reads like a REPL. Code that ends in anything else stays byte-identical.
4
+ */
5
+ export declare function returnLastExpression(code: string): string;
6
+ //# sourceMappingURL=return-last-expression.d.ts.map
@@ -0,0 +1 @@
1
+ import{parse as e}from"acorn";function i(t){let r;try{r=e(t,{ecmaVersion:"latest",sourceType:"script",allowAwaitOutsideFunction:!0,allowReturnOutsideFunction:!0}).body.at(-1)}catch{return t}return r?.type!=="ExpressionStatement"||r.directive!==void 0?t:`${t.slice(0,r.start)}return ${t.slice(r.start)}`}export{i as returnLastExpression};
@@ -10,6 +10,7 @@ export declare function setupHostFunctions(context: QuickJSContext, hostFunction
10
10
  globalName?: string;
11
11
  budget?: ExecutionBudget;
12
12
  maxCalls?: number;
13
+ maxOutputBytes?: number;
13
14
  messages?: {
14
15
  outputTooLarge?: (bytes: number) => string;
15
16
  callLimitExceeded?: (max: number) => string;
@@ -1,5 +1,5 @@
1
- import{DEFAULT_GLOBAL_NAME as v,MAX_HOST_OUTPUT_BYTES as _}from"../constants/host-functions.js";import{evalGuestCode as E}from"./eval-guest-code.js";function w(e,o,s){const l=s?.globalName??v,u=s?.maxCalls,f=s?.messages?.outputTooLarge??(n=>`Host function output is too large (${n} bytes); request narrower data instead`),m=s?.messages?.callLimitExceeded??(n=>`Exceeded the limit of ${n} host calls`),d=s?.budget?.hostCall??(n=>n()),c=new Set;let S=0;return e.newFunction("__invoke",(n,a)=>{const h=e.getString(n),p=JSON.parse(e.getString(a)),r=e.newPromise();return c.add(r),u!==void 0&&++S>u?e.newError(m(u)).consume(r.reject):d(()=>Promise.resolve().then(()=>o[h](p))).then(t=>{if(!e.alive)return;let i;try{i=JSON.stringify(t??null)}catch(g){const b=g instanceof Error?g.message:String(g);e.newError(`Host function output is not serializable: ${b}`).consume(r.reject);return}i.length>_?e.newError(f(i.length)).consume(r.reject):e.newString(i).consume(r.resolve)},t=>{if(!e.alive)return;const i=t instanceof Error?t.message:String(t);e.newError(i).consume(r.reject)}),r.settled.then(()=>{e.alive&&e.runtime.executePendingJobs()}),r.handle}).consume(n=>e.setProp(e.global,"__invoke",n)),E(e,O(Object.keys(o),l)),function(){for(const a of c)a.alive&&a.dispose()}}function O(e,o){const s=e.map(l=>`${JSON.stringify(l)}: (input) => invoke(${JSON.stringify(l)}, JSON.stringify(input ?? {})).then(JSON.parse)`).join(", ");return`(() => {
1
+ import{DEFAULT_GLOBAL_NAME as v,MAX_HOST_OUTPUT_BYTES as _}from"../constants/host-functions.js";import{evalGuestCode as E}from"./eval-guest-code.js";function w(e,o,n){const l=n?.globalName??v,u=n?.maxCalls,m=n?.maxOutputBytes??_,f=n?.messages?.outputTooLarge??(s=>`Host function output is too large (${s} bytes); request narrower data instead`),d=n?.messages?.callLimitExceeded??(s=>`Exceeded the limit of ${s} host calls`),p=n?.budget?.hostCall??(s=>s()),c=new Set;let S=0;return e.newFunction("__invoke",(s,a)=>{const h=e.getString(s),O=JSON.parse(e.getString(a)),r=e.newPromise();return c.add(r),u!==void 0&&++S>u?e.newError(d(u)).consume(r.reject):p(()=>Promise.resolve().then(()=>o[h](O))).then(i=>{if(!e.alive)return;let t;try{t=JSON.stringify(i??null)}catch(g){const b=g instanceof Error?g.message:String(g);e.newError(`Host function output is not serializable: ${b}`).consume(r.reject);return}t.length>m?e.newError(f(t.length)).consume(r.reject):e.newString(t).consume(r.resolve)},i=>{if(!e.alive)return;const t=i instanceof Error?i.message:String(i);e.newError(t).consume(r.reject)}),r.settled.then(()=>{e.alive&&e.runtime.executePendingJobs()}),r.handle}).consume(s=>e.setProp(e.global,"__invoke",s)),E(e,y(Object.keys(o),l)),function(){for(const a of c)a.alive&&a.dispose()}}function y(e,o){const n=e.map(l=>`${JSON.stringify(l)}: (input) => invoke(${JSON.stringify(l)}, JSON.stringify(input ?? {})).then(JSON.parse)`).join(", ");return`(() => {
2
2
  const invoke = globalThis.__invoke;
3
3
  delete globalThis.__invoke;
4
- globalThis[${JSON.stringify(o)}] = Object.freeze({ ${s} });
4
+ globalThis[${JSON.stringify(o)}] = Object.freeze({ ${n} });
5
5
  })();`}export{w as setupHostFunctions};
@@ -1 +1 @@
1
- import C 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 R}from"./constants/entitlements.js";import{MARKDOC_PARTIALS_DATA_KEY as m,MARKDOC_PARTIALS_DEPS_KEY as M}from"./constants/common.js";import{isObject as O}from"../utils/guards/is-object.js";import{mapObject as k}from"../utils/object/map-object.js";import{getValueDeep as y}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 D}from"../utils/path/is-local-link.js";import{reporter as S}from"./tools/notifiers/reporter.js";import{logger as u}from"./tools/notifiers/logger.js";import{sha1 as H}from"./utils/crypto/sha1.js";import{envConfig as G,setEnv as _}from"./config/env-config.js";import{KvService as B}from"./persistence/kv/services/kv-service.js";import{SandboxContext as F}from"./utils/sandbox-context.js";import{writeSharedData as I}from"./utils/index.js";import{renderComponents as N}from"./ssr/render.js";import{readStaticData as V,writeStaticData as q}from"./utils/static-data.js";import{parseAndResolveMarkdoc as j}from"./plugins/markdown/compiler.js";import{getMarkdocOptions as U}from"./plugins/markdown/markdoc/markdoc-options.js";import{EntitlementsProvider as w}from"./entitlements/entitlements-provider.js";import{isL10nPath as x}from"./fs/utils/is-l10n-path.js";import{resolveGlobMapValue as K}from"./utils/globs.js";import{replaceEnvVariablesDeep as J}from"./utils/envs/replace-env-variables-deep.js";import{findRedirect as W}from"./utils/redirects/find-redirect.js";import{followRedirectChain as $}from"./utils/redirects/follow-redirect-chain.js";import{addWildcardRedirectToTree as z}from"./utils/redirects/add-wildcard-redirect-to-tree.js";import{telemetryTraceStep as Y}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",skills:"map"},E="PLAN_GATES",Z=["OAUTH_CLIENT_ID","OAUTH_CLIENT_SECRET","ORGANIZATION_SLUG","ORGANIZATION_ID","ORG_ID"],Oe="userDefinedApiFunctions";class P{routesBySlug=new Map;replacedEnvVars={};unsetEnvVars=new Set;lifecycleContext;newRoutes=[];#t={};routesByFsPath=new Map;apiRoutes=[];middleware=[];routesSharedData=new Map;sharedDataDeps=new Map;sharedDataMarkdocComponents=new Map;routesDynamicComponents=new Map;routesPartials=new Map;ssr={preBodyTags:[],postBodyTags:[],headTags:[]};searchFacets=new Map;searchEngine;templates=new Map;browserPlugins=new Set;apiRoutesRequestHandlers=new Map;mcpToolHandlers=new Map;skills=new Map;serverPropsGetters=new Map;pagePropsGetters=new Map;listeners=new Map;globalData={};#o=void 0;config={configFilePath:"",redirects:{},wildcardRedirectsTree:{},access:{rbac:{},requiresLogin:!1},directoryPermissions:{},devLogin:!1,ssoDirect:{}};#i;serverMode;serverOutDir;outdir;buildRevision=0;hasSitemap=!1;compilationErrors=[];#n;userCodeReady;#s=Promise.resolve();#c;#l=Promise.resolve();#d;#u=Promise.resolve();#h;#e=!1;#r=0;#f=0;#a=new Map;constructor({outdir:e,contentDir:t,serverMode:s=!1,serverOutDir:r}){this.#i=t,this.outdir=e,this.serverMode=s,this.serverOutDir=r,F.register({serverOutDir:r,readRoots:[e,process.cwd()]}),this.userCodeReady=new Promise(a=>{this.#n=a})}on(e,t){const s=this.listeners.get(e);s?s.add(t):this.listeners.set(e,new Set([t]))}queueEvent=(e,t,...s)=>{this.#a.set(e+String(t),[e,t,...s])};runListeners=(e,t,...s)=>{for(const r of this.listeners.get(e)||new Set)t?r(t,...s):r(...s)};startPluginsRun(){this.clear(),this.#s=new Promise(e=>{this.#c=e})}waitForPluginsLifecycle(){return Promise.all([this.#s,this.#l,this.#u])}waitForPluginsRun(){return this.#s}finishPluginsRun(){this.#c?.();for(const e of this.#a.values())this.runListeners(...e);this.#a.clear()}startEsbuildRun(){this.#l=new Promise(e=>{this.#d=e})}finishEsbuildRun(){this.#d?.()}markRequestHandlersEntryOutdated(){this.#r++,!this.#e&&(this.#e=!0,this.#u=new Promise(e=>{this.#h=e}))}noteRequestHandlersEntryBuildStart(){this.#f=this.#r}markRequestHandlersEntryUpdated(){this.#e&&(this.#r>this.#f||(this.#e=!1,this.#h?.()))}get contentDir(){if(this.serverMode)throw new Error("contentDir should not be used in server mode");return this.#i}markUserCodeReady(){this.#n?.(!0)}async reloadMarkdocOptions(){await Y("com.redocly.build.reloadMarkdocOptions",async()=>{const e=w.instance(),t=await U(this.serverOutDir),s=Object.fromEntries(Object.entries(t.tags).filter(([r])=>R[r]!=null?e.canAccessFeature(R[r]):!0));this.#o={...t,tags:s}})}get markdocOptions(){return{...this.#o,partials:this.getGlobalConfig(m),themeConfig:this.config.markdown}}setGlobalData=e=>{const t=this.globalData,s={...this.globalData,...e};this.globalData=s,JSON.stringify(s)!==JSON.stringify(t)&&this.queueEvent("global-data-updated",void 0,s)};getGlobalData=()=>this.globalData;getKv=async()=>B.getInstance({baseDbDir:this.serverOutDir});parseMarkdoc=async({input:e,context:t,deps:s,resource:r})=>{const{data:{info:a,ast:o},compoundHash:l}=await j(e,this.markdocOptions,{actions:this,context:t},r);for(const i of a.sharedDataDeps||[]){for(const n of s?.routeSlugs||[])this.addRouteSharedData(n,i,i);for(const n of s?.sharedDataIds||[]){const c=this.sharedDataDeps.get(n)||new Set;c.add(i),this.sharedDataDeps.set(n,c)}}for(const i of a.dynamicMarkdocComponents||[]){for(const n of s?.routeSlugs||[]){const c=this.routesDynamicComponents.get(n)||new Set;c.add(i),this.routesDynamicComponents.set(n,c)}for(const n of s?.sharedDataIds||[]){const c=this.sharedDataMarkdocComponents.get(n)||new Set;c.add(i),this.sharedDataMarkdocComponents.set(n,c)}}if(s?.routeSlugs&&a.partials?.length)for(const i of s.routeSlugs){const n=this.routesPartials.get(i)||[];for(const c of a.partials)n.includes(c)||n.push(c);this.routesPartials.set(i,n)}return{info:a,ast:o,compoundHash:l}};async loadApiDocuments(e){return(await e.cache.load(".","api-docs")).data}setSearchEngine(e){this.searchEngine=e}setSearchFacets=e=>{this.searchFacets=e};setGlobalConfig=e=>{const t=Object.keys(e);for(const o of t)for(const l in this.replacedEnvVars)if(l===o||l.startsWith(`${o}:`)){const i=l.split(":"),{error:n,value:c}=y(e,i);(n||c!==this.replacedEnvVars[l].replaced)&&delete this.replacedEnvVars[l]}const{resolvedObj:s,unsetEnvVars:r,replacedValues:a}=J(e);for(const o of r)this.unsetEnvVars.add(o);Object.assign(this.replacedEnvVars,a),Object.assign(this.config,s)};getConfig=()=>this.config;getGlobalConfig=e=>this.config[e];getSearchFacets=()=>this.searchFacets;addRedirect=(e,t,s={})=>{if(!w.instance().canAccessFeature("redirects")&&e!=="/")return;this.config.redirects||(this.config.redirects={});const o=h(e).toLowerCase();this.config.redirects[o]=t;const{trackOriginalSource:l=!0}=s,i=this.getGlobalConfig("originalRedirectSources");l&&Array.isArray(i)&&!i.includes(o)&&i.push(o),o.endsWith("*")&&z(this.config.wildcardRedirectsTree,o)};getRedirect=e=>{const t=h(e).toLowerCase(),s=W(t,this.config.redirects,this.config.wildcardRedirectsTree);if(!s)return null;if(D(s.to)){const r=h(s.to).toLowerCase();if(!r.endsWith("*")&&$(r,[t],this.config.redirects,this.config.wildcardRedirectsTree).type==="cycle")return null}return{to:s.to,type:s.type}};createSharedData=async(e,t,s)=>{if(s&&this.#t[e]===s)return e;const r=JSON.stringify(t),a=s??H(r);return this.#t[e]===a||(this.#t[e]=a,await I(e,r,this.outdir),this.queueEvent("shared-data-updated",e)),e};addRouteSharedData=(e,t,s)=>{const r=L(e),a=this.routesSharedData.get(r)||{};a[t]=s,this.routesSharedData.set(r,a),u.verbose(`Adding shared data to ${e}, ${t}, ${s}`)};getRouteSharedDataByFsPath=e=>{const t=this.routesByFsPath.get(e);return t?this.routesSharedData.get(t)||{}:{}};getPartialsForRoute=e=>{const t=this.getGlobalConfig(m)||{},s=this.routesPartials.get(e);if(!s||s.length===0)return{};const r=this.getGlobalConfig(M)||{},a=new Set(s),o=Array.from(s);for(let i=0;i<o.length;i++){const n=o[i],c=r[n]?.partials??[];for(const d of c)a.has(d)||(a.add(d),o.push(d))}const l={};for(const i of a)t[i]&&(l[i]=t[i]);return l};addRoute=e=>{const s={...K(e.fsPath,this.config.metadataGlobs),...e.metadata||{}};this.newRoutes.push({...e,metadata:s}),u.verbose("Created route %s",e.slug)};addRouteSharedDataToAllLocales=(e,t,s)=>{const r=[g,...this.lifecycleContext?.fs.localeFolders||[]].map(a=>({code:a,name:a}));for(const a of r){const o=A(e,g,a.code,r);this.addRouteSharedData(o,t,s)}};addApiRoute=e=>{this.apiRoutes.push(e),u.verbose("Created API route %s",e.slug)};addMcpTools=(e,t)=>{for(const s of t){const r=this.mcpToolHandlers.get(s.name);r&&r.importPath!==e&&u.warn('MCP tool "%s" from %s overwrites the tool registered from %s',s.name,e,r.importPath),this.mcpToolHandlers.set(s.name,{...s,importPath:e}),u.verbose("Created MCP tool %s",s.name)}};getMcpTools=()=>Array.from(this.mcpToolHandlers.values());markGatedMcpTools=e=>{for(const t of e){const s=this.mcpToolHandlers.get(t);s&&this.mcpToolHandlers.set(t,{...s,hasAvailabilityGate:!0})}};addSkills=e=>{for(const t of e)this.skills.set(t.slug,t),u.verbose("Discovered skill %s",t.slug)};getSkills=()=>Array.from(this.skills.values());removeMcpTools=e=>{for(const t of e)this.mcpToolHandlers.delete(t)};addMiddleware=e=>{this.middleware.push(e),u.verbose("Created middleware %s",e.id)};setResourceResponseHeaders=(e,t)=>{this.config.responseHeaders||(this.config.responseHeaders={});const s=new Set(t.map(o=>o.name.toLowerCase())),a=[...(this.config.responseHeaders[e]??[]).filter(o=>!s.has(o.name.toLowerCase())),...t];this.config.responseHeaders[e]=a};getRouteByFsPath=e=>{const t=this.routesByFsPath.get(e);return t?this.getRouteBySlug(t):void 0};getRouteBySlug=(e,t={})=>{const{followRedirect:s=!0}=t,r=this.getRedirect(e);return s&&r?this.routesBySlug.get(h(r.to)):this.routesBySlug.get(e)};hasRouteOrRedirectBySlug=e=>{if(this.routesBySlug.has(e))return!0;const t=this.getRedirect(e);if(!t)return!1;if(!D(t.to))return!0;const s=h(t.to);return this.routesBySlug.has(s)};getRoutesByTemplateId=e=>this.newRoutes.filter(t=>t.templateId===e);getAllRoutesForLocale=(e=g)=>{const t=Array.from(this.routesBySlug.values()),s=e.toLowerCase();return t.filter(r=>e===g?!x(r.fsPath):r.slug.startsWith(`/${s}`))};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,t)=>(this.templates.set(e,t),e);addBrowserPlugin=e=>{this.browserPlugins.add(e)};createRequestHandler=(e,t)=>(this.apiRoutesRequestHandlers.set(e,t),e);clearRequestHandlersByPrefix=e=>{for(const t of this.apiRoutesRequestHandlers.keys())t.startsWith(e)&&this.apiRoutesRequestHandlers.delete(t)};registerServerPropsGetter=(e,t)=>(this.serverPropsGetters.set(e,t),e);registerPagePropsGetter=(e,t)=>{this.pagePropsGetters.set(e,t)};async writeRouteStaticData(e,t){const s=await this.resolveRouteStaticData(e,t,!1);s&&q(e.slug,s,this.outdir)}async resolveRouteStaticData(e,t,s){if(this.serverMode)return V(e.slug,this.outdir);const r={...this,contentDir:this.contentDir,parseMarkdoc:({input:c,context:d,resource:f})=>this.parseMarkdoc({input:c,context:d,deps:{routeSlugs:[e.slug]},resource:f})},a=await e.getStaticData?.(e,r)||{},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=a?.frontmatter||{};return{...a,frontmatter:{...n,seo:{...n?.seo,title:n?.seo?.title||await e.getNavText?.()}},props:{...a.props,dynamicMarkdocComponents:Array.from(o),metadata:{...a?.props?.metadata,...e.metadata},seo:{title:T,...i,...a.props?.seo},compilationErrors:this.compilationErrors},lastModified:s||!e.fsPath?null:await this.lifecycleContext?.fs.getLastModified(e.fsPath)}}addSsrComponents(e,t){if(!e?.length)return;const s=typeof e[0]=="string"?e.join(""):N(e);s&&(t==="head"?this.ssr.headTags.push(s):t==="preBody"?this.ssr.preBodyTags.push(s):this.ssr.postBodyTags.push(s))}clear=()=>{this.routesByFsPath.clear(),this.templates.clear(),this.newRoutes=[],this.routesBySlug.clear(),this.apiRoutes=[],this.middleware=[],this.routesSharedData.clear(),this.sharedDataDeps.clear(),this.sharedDataMarkdocComponents.clear(),this.routesDynamicComponents.clear(),this.routesPartials.clear(),this.skills.clear(),this.config.redirects={},this.config.wildcardRedirectsTree={},this.config.directoryPermissions={},this.ssr={preBodyTags:[],postBodyTags:[],headTags:[]}};async toJson(){const e=[];for(const[s,r]of Object.entries(v))switch(r){case"map":const a=Array.from(this[s].entries());e.push([s,a]);break;case"object":if(s==="config"){e.push([s,await this.getConfigWithEnvPlaceholders()]);break}e.push([s,this[s]]);break;default:throw new Error("Invalid format")}const t=Object.fromEntries(e);return t[E]=G.PLAN_GATES,t}static fromJson(e,t){const s=new P(t);for(const[a,o]of Object.entries(v))switch(o){case"map":s[a]=new Map(e[a]);break;case"object":if(a==="config"){s.setGlobalConfig(e[a]);break}s[a]=e[a];break;default:throw new Error("Invalid format")}s.config[m]=Q(s.config[m]||{});const r=e[E];return r&&_("PLAN_GATES",r),s}async getConfigWithEnvPlaceholders(){const e=JSON.parse(JSON.stringify(this.config));for(const t in this.replacedEnvVars){const{original:s}=this.replacedEnvVars[t],r=t.split(":"),a=r.pop(),{error:o,value:l}=y(e,r);if(o||!O(l)&&!Array.isArray(l)){await S.panicOnBuild(`Failed to replace env var with env name for ${t}`);continue}l[a]=s}return e}async reportUnsetEnvVars(){if(this.unsetEnvVars.size===0)return;const e=Array.from(this.unsetEnvVars).filter(s=>!Z.includes(s));if(e.length===0)return;const t=`Failed to resolve config. The following environment variables are not set: ${e.join(", ")}`;await S.panicOnBuildContentError(t)}}function Q(b){return k(b,e=>C.Ast.fromJSON(JSON.stringify(e)))}export{P as Store,Oe as USER_DEFINED_API_FUNCTIONS_COUNTER_KEY};
1
+ import A from"@markdoc/markdoc";import{getPathnameForLocale as T}from"@redocly/theme/core/utils";import{DEFAULT_LOCALE_PLACEHOLDER as g}from"../constants/common.js";import{DEFAULT_TITLE as M}from"./constants/common.js";import{GATED_MARKDOC_TAGS as R}from"./constants/entitlements.js";import{MARKDOC_PARTIALS_DATA_KEY as m,MARKDOC_PARTIALS_DEPS_KEY as O}from"./constants/common.js";import{isObject as k}from"../utils/guards/is-object.js";import{mapObject as L}from"../utils/object/map-object.js";import{getValueDeep as y}from"../utils/object/get-value-deep.js";import{removeTrailingSlash as D}from"../utils/url/remove-trailing-slash.js";import{normalizeRouteSlug as h}from"../utils/path/normalize-route-slug.js";import{isLocalLink as S}from"../utils/path/is-local-link.js";import{reporter as w}from"./tools/notifiers/reporter.js";import{logger as u}from"./tools/notifiers/logger.js";import{sha1 as H}from"./utils/crypto/sha1.js";import{envConfig as G,setEnv as _}from"./config/env-config.js";import{KvService as B}from"./persistence/kv/services/kv-service.js";import{SandboxContext as F}from"./utils/sandbox-context.js";import{writeSharedData as I}from"./utils/index.js";import{renderComponents as N}from"./ssr/render.js";import{readStaticData as V,writeStaticData as q}from"./utils/static-data.js";import{parseAndResolveMarkdoc as U}from"./plugins/markdown/compiler.js";import{getMarkdocOptions as j}from"./plugins/markdown/markdoc/markdoc-options.js";import{EntitlementsProvider as v}from"./entitlements/entitlements-provider.js";import{isL10nPath as x}from"./fs/utils/is-l10n-path.js";import{resolveGlobMapValue as K}from"./utils/globs.js";import{replaceEnvVariablesDeep as J}from"./utils/envs/replace-env-variables-deep.js";import{findRedirect as W}from"./utils/redirects/find-redirect.js";import{followRedirectChain as $}from"./utils/redirects/follow-redirect-chain.js";import{addWildcardRedirectToTree as z}from"./utils/redirects/add-wildcard-redirect-to-tree.js";import{telemetryTraceStep as Y}from"../cli/telemetry/helpers/trace-step.js";const E={routesBySlug:"map",apiRoutes:"object",middleware:"object",routesByFsPath:"map",routesSharedData:"map",globalData:"object",config:"object",ssr:"object",searchFacets:"map",routesPartials:"map",mcpToolHandlers:"map",skills:"map"},P="PLAN_GATES",Z=["OAUTH_CLIENT_ID","OAUTH_CLIENT_SECRET","ORGANIZATION_SLUG","ORGANIZATION_ID","ORG_ID"],Oe="userDefinedApiFunctions";class b{routesBySlug=new Map;replacedEnvVars={};unsetEnvVars=new Set;lifecycleContext;newRoutes=[];#t={};routesByFsPath=new Map;apiRoutes=[];middleware=[];routesSharedData=new Map;sharedDataDeps=new Map;sharedDataMarkdocComponents=new Map;routesDynamicComponents=new Map;routesPartials=new Map;ssr={preBodyTags:[],postBodyTags:[],headTags:[]};searchFacets=new Map;searchEngine;templates=new Map;browserPlugins=new Set;apiRoutesRequestHandlers=new Map;mcpToolHandlers=new Map;skills=new Map;serverPropsGetters=new Map;pagePropsGetters=new Map;listeners=new Map;globalData={};#o=void 0;config={configFilePath:"",redirects:{},wildcardRedirectsTree:{},access:{rbac:{},requiresLogin:!1},directoryPermissions:{},devLogin:!1,ssoDirect:{}};#i;serverMode;serverOutDir;outdir;buildRevision=0;hasSitemap=!1;compilationErrors=[];#n;userCodeReady;#s=Promise.resolve();#c;#l=Promise.resolve();#d;#u=Promise.resolve();#h;#e=!1;#r=0;#f=0;#a=new Map;constructor({outdir:e,contentDir:s,serverMode:t=!1,serverOutDir:r}){this.#i=s,this.outdir=e,this.serverMode=t,this.serverOutDir=r,F.register({serverOutDir:r,readRoots:[e,process.cwd()]}),this.userCodeReady=new Promise(a=>{this.#n=a})}on(e,s){const t=this.listeners.get(e);t?t.add(s):this.listeners.set(e,new Set([s]))}queueEvent=(e,s,...t)=>{this.#a.set(e+String(s),[e,s,...t])};runListeners=(e,s,...t)=>{for(const r of this.listeners.get(e)||new Set)s?r(s,...t):r(...t)};startPluginsRun(){this.clear(),this.#s=new Promise(e=>{this.#c=e})}waitForPluginsLifecycle(){return Promise.all([this.#s,this.#l,this.#u])}waitForPluginsRun(){return this.#s}finishPluginsRun(){this.#c?.();for(const e of this.#a.values())this.runListeners(...e);this.#a.clear()}startEsbuildRun(){this.#l=new Promise(e=>{this.#d=e})}finishEsbuildRun(){this.#d?.()}markRequestHandlersEntryOutdated(){this.#r++,!this.#e&&(this.#e=!0,this.#u=new Promise(e=>{this.#h=e}))}noteRequestHandlersEntryBuildStart(){this.#f=this.#r}markRequestHandlersEntryUpdated(){this.#e&&(this.#r>this.#f||(this.#e=!1,this.#h?.()))}get contentDir(){if(this.serverMode)throw new Error("contentDir should not be used in server mode");return this.#i}markUserCodeReady(){this.#n?.(!0)}async reloadMarkdocOptions(){await Y("com.redocly.build.reloadMarkdocOptions",async()=>{const e=v.instance(),s=await j(this.serverOutDir),t=Object.fromEntries(Object.entries(s.tags).filter(([r])=>R[r]!=null?e.canAccessFeature(R[r]):!0));this.#o={...s,tags:t}})}get markdocOptions(){return{...this.#o,partials:this.getGlobalConfig(m),themeConfig:this.config.markdown}}setGlobalData=e=>{const s=this.globalData,t={...this.globalData,...e};this.globalData=t,JSON.stringify(t)!==JSON.stringify(s)&&this.queueEvent("global-data-updated",void 0,t)};getGlobalData=()=>this.globalData;getKv=async()=>B.getInstance({baseDbDir:this.serverOutDir});parseMarkdoc=async({input:e,context:s,deps:t,resource:r})=>{const{data:{info:a,ast:i},compoundHash:l}=await U(e,this.markdocOptions,{actions:this,context:s},r);for(const o of a.sharedDataDeps||[]){for(const n of t?.routeSlugs||[])this.addRouteSharedData(n,o,o);for(const n of t?.sharedDataIds||[]){const c=this.sharedDataDeps.get(n)||new Set;c.add(o),this.sharedDataDeps.set(n,c)}}for(const o of a.dynamicMarkdocComponents||[]){for(const n of t?.routeSlugs||[]){const c=this.routesDynamicComponents.get(n)||new Set;c.add(o),this.routesDynamicComponents.set(n,c)}for(const n of t?.sharedDataIds||[]){const c=this.sharedDataMarkdocComponents.get(n)||new Set;c.add(o),this.sharedDataMarkdocComponents.set(n,c)}}if(t?.routeSlugs&&a.partials?.length)for(const o of t.routeSlugs){const n=this.routesPartials.get(o)||[];for(const c of a.partials)n.includes(c)||n.push(c);this.routesPartials.set(o,n)}return{info:a,ast:i,compoundHash:l}};async loadApiDocuments(e){return(await e.cache.load(".","api-docs")).data}setSearchEngine(e){this.searchEngine=e}setSearchFacets=e=>{this.searchFacets=e};setGlobalConfig=e=>{const s=Object.keys(e);for(const l of s)for(const o in this.replacedEnvVars)if(o===l||o.startsWith(`${l}:`)){const n=o.split(":"),{error:c,value:d}=y(e,n);(c||d!==this.replacedEnvVars[o].replaced)&&delete this.replacedEnvVars[o]}const{resolvedObj:t,unsetEnvVars:r,replacedValues:a}=J(e);for(const l of r)this.unsetEnvVars.add(l);Object.assign(this.replacedEnvVars,a);const i=t.seo?.siteUrl?.trim();i&&(t.seo={...t.seo,siteUrl:URL.canParse(i)?new URL(i).origin:D(i)}),Object.assign(this.config,t)};getConfig=()=>this.config;getGlobalConfig=e=>this.config[e];getSearchFacets=()=>this.searchFacets;addRedirect=(e,s,t={})=>{if(!v.instance().canAccessFeature("redirects")&&e!=="/")return;this.config.redirects||(this.config.redirects={});const i=h(e).toLowerCase();this.config.redirects[i]=s;const{trackOriginalSource:l=!0}=t,o=this.getGlobalConfig("originalRedirectSources");l&&Array.isArray(o)&&!o.includes(i)&&o.push(i),i.endsWith("*")&&z(this.config.wildcardRedirectsTree,i)};getRedirect=e=>{const s=h(e).toLowerCase(),t=W(s,this.config.redirects,this.config.wildcardRedirectsTree);if(!t)return null;if(S(t.to)){const r=h(t.to).toLowerCase();if(!r.endsWith("*")&&$(r,[s],this.config.redirects,this.config.wildcardRedirectsTree).type==="cycle")return null}return{to:t.to,type:t.type}};createSharedData=async(e,s,t)=>{if(t&&this.#t[e]===t)return e;const r=JSON.stringify(s),a=t??H(r);return this.#t[e]===a||(this.#t[e]=a,await I(e,r,this.outdir),this.queueEvent("shared-data-updated",e)),e};addRouteSharedData=(e,s,t)=>{const r=D(e),a=this.routesSharedData.get(r)||{};a[s]=t,this.routesSharedData.set(r,a),u.verbose(`Adding shared data to ${e}, ${s}, ${t}`)};getRouteSharedDataByFsPath=e=>{const s=this.routesByFsPath.get(e);return s?this.routesSharedData.get(s)||{}:{}};getPartialsForRoute=e=>{const s=this.getGlobalConfig(m)||{},t=this.routesPartials.get(e);if(!t||t.length===0)return{};const r=this.getGlobalConfig(O)||{},a=new Set(t),i=Array.from(t);for(let o=0;o<i.length;o++){const n=i[o],c=r[n]?.partials??[];for(const d of c)a.has(d)||(a.add(d),i.push(d))}const l={};for(const o of a)s[o]&&(l[o]=s[o]);return l};addRoute=e=>{const t={...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 r=[g,...this.lifecycleContext?.fs.localeFolders||[]].map(a=>({code:a,name:a}));for(const a of r){const i=T(e,g,a.code,r);this.addRouteSharedData(i,s,t)}};addApiRoute=e=>{this.apiRoutes.push(e),u.verbose("Created API route %s",e.slug)};addMcpTools=(e,s)=>{for(const t of s){const r=this.mcpToolHandlers.get(t.name);r&&r.importPath!==e&&u.warn('MCP tool "%s" from %s overwrites the tool registered from %s',t.name,e,r.importPath),this.mcpToolHandlers.set(t.name,{...t,importPath:e}),u.verbose("Created MCP tool %s",t.name)}};getMcpTools=()=>Array.from(this.mcpToolHandlers.values());markGatedMcpTools=e=>{for(const s of e){const t=this.mcpToolHandlers.get(s);t&&this.mcpToolHandlers.set(s,{...t,hasAvailabilityGate:!0})}};addSkills=e=>{for(const s of e)this.skills.set(s.slug,s),u.verbose("Discovered skill %s",s.slug)};getSkills=()=>Array.from(this.skills.values());removeMcpTools=e=>{for(const s of e)this.mcpToolHandlers.delete(s)};addMiddleware=e=>{this.middleware.push(e),u.verbose("Created middleware %s",e.id)};setResourceResponseHeaders=(e,s)=>{this.config.responseHeaders||(this.config.responseHeaders={});const t=new Set(s.map(i=>i.name.toLowerCase())),a=[...(this.config.responseHeaders[e]??[]).filter(i=>!t.has(i.name.toLowerCase())),...s];this.config.responseHeaders[e]=a};getRouteByFsPath=e=>{const s=this.routesByFsPath.get(e);return s?this.getRouteBySlug(s):void 0};getRouteBySlug=(e,s={})=>{const{followRedirect:t=!0}=s,r=this.getRedirect(e);return t&&r?this.routesBySlug.get(h(r.to)):this.routesBySlug.get(e)};hasRouteOrRedirectBySlug=e=>{if(this.routesBySlug.has(e))return!0;const s=this.getRedirect(e);if(!s)return!1;if(!S(s.to))return!0;const t=h(s.to);return this.routesBySlug.has(t)};getRoutesByTemplateId=e=>this.newRoutes.filter(s=>s.templateId===e);getAllRoutesForLocale=(e=g)=>{const s=Array.from(this.routesBySlug.values()),t=e.toLowerCase();return s.filter(r=>e===g?!x(r.fsPath):r.slug.startsWith(`/${t}`))};getAllRoutes=()=>Array.from(this.routesBySlug.values());getAllApiRoutes=()=>this.apiRoutes;getAllMiddleware=()=>this.middleware;getTemplate=e=>this.templates.get(e);getRequestHandler=e=>this.apiRoutesRequestHandlers.get(e);createTemplate=(e,s)=>(this.templates.set(e,s),e);addBrowserPlugin=e=>{this.browserPlugins.add(e)};createRequestHandler=(e,s)=>(this.apiRoutesRequestHandlers.set(e,s),e);clearRequestHandlersByPrefix=e=>{for(const s of this.apiRoutesRequestHandlers.keys())s.startsWith(e)&&this.apiRoutesRequestHandlers.delete(s)};registerServerPropsGetter=(e,s)=>(this.serverPropsGetters.set(e,s),e);registerPagePropsGetter=(e,s)=>{this.pagePropsGetters.set(e,s)};async writeRouteStaticData(e,s){const t=await this.resolveRouteStaticData(e,s,!1);t&&q(e.slug,t,this.outdir)}async resolveRouteStaticData(e,s,t){if(this.serverMode)return V(e.slug,this.outdir);const r={...this,contentDir:this.contentDir,parseMarkdoc:({input:c,context:d,resource:f})=>this.parseMarkdoc({input:c,context:d,deps:{routeSlugs:[e.slug]},resource:f})},a=await e.getStaticData?.(e,r)||{},i=new Set(this.routesDynamicComponents.get(e.slug)),l=this.routesSharedData.get(e.slug)||{};for(const c of Object.values(l)){const d=this.sharedDataMarkdocComponents.get(c);d&&d.forEach(p=>i.add(p));const f=this.sharedDataDeps.get(c);f&&f.forEach(p=>this.addRouteSharedData(e.slug,p,p))}const o=this.getGlobalConfig("seo"),n=a?.frontmatter||{};return{...a,frontmatter:{...n,seo:{...n?.seo,title:n?.seo?.title||await e.getNavText?.()}},props:{...a.props,dynamicMarkdocComponents:Array.from(i),metadata:{...a?.props?.metadata,...e.metadata},seo:{title:M,...o,...a.props?.seo,siteUrl:o?.siteUrl},compilationErrors:this.compilationErrors},lastModified:t||!e.fsPath?null:await this.lifecycleContext?.fs.getLastModified(e.fsPath)}}addSsrComponents(e,s){if(!e?.length)return;const t=typeof e[0]=="string"?e.join(""):N(e);t&&(s==="head"?this.ssr.headTags.push(t):s==="preBody"?this.ssr.preBodyTags.push(t):this.ssr.postBodyTags.push(t))}clear=()=>{this.routesByFsPath.clear(),this.templates.clear(),this.newRoutes=[],this.routesBySlug.clear(),this.apiRoutes=[],this.middleware=[],this.routesSharedData.clear(),this.sharedDataDeps.clear(),this.sharedDataMarkdocComponents.clear(),this.routesDynamicComponents.clear(),this.routesPartials.clear(),this.skills.clear(),this.config.redirects={},this.config.wildcardRedirectsTree={},this.config.directoryPermissions={},this.ssr={preBodyTags:[],postBodyTags:[],headTags:[]}};async toJson(){const e=[];for(const[t,r]of Object.entries(E))switch(r){case"map":const a=Array.from(this[t].entries());e.push([t,a]);break;case"object":if(t==="config"){e.push([t,await this.getConfigWithEnvPlaceholders()]);break}e.push([t,this[t]]);break;default:throw new Error("Invalid format")}const s=Object.fromEntries(e);return s[P]=G.PLAN_GATES,s}static fromJson(e,s){const t=new b(s);for(const[a,i]of Object.entries(E))switch(i){case"map":t[a]=new Map(e[a]);break;case"object":if(a==="config"){t.setGlobalConfig(e[a]);break}t[a]=e[a];break;default:throw new Error("Invalid format")}t.config[m]=Q(t.config[m]||{});const r=e[P];return r&&_("PLAN_GATES",r),t}async getConfigWithEnvPlaceholders(){const e=JSON.parse(JSON.stringify(this.config));for(const s in this.replacedEnvVars){const{original:t}=this.replacedEnvVars[s],r=s.split(":"),a=r.pop(),{error:i,value:l}=y(e,r);if(i||!k(l)&&!Array.isArray(l)){await w.panicOnBuild(`Failed to replace env var with env name for ${s}`);continue}l[a]=t}return e}async reportUnsetEnvVars(){if(this.unsetEnvVars.size===0)return;const e=Array.from(this.unsetEnvVars).filter(t=>!Z.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 Q(C){return L(C,e=>A.Ast.fromJSON(JSON.stringify(e)))}export{b as Store,Oe as USER_DEFINED_API_FUNCTIONS_COUNTER_KEY};
@@ -1 +1 @@
1
- import m from"path";import{REDOCLY_ROUTE_RBAC as v,REDOCLY_TEAMS_RBAC as B}from"@redocly/config";import{combineUrls as F,withoutPathPrefix as Q,withPathPrefix as ee}from"@redocly/theme/core/utils";import{CACHE_CONTROL_NO_STORE_HEADER_VALUE as z,CACHE_CONTROL_PUBLIC_HTML as te,DEFAULT_IMMUTABLE_CACHE_MAX_AGE as ne,X_REDOCLY_CACHE_CONTROL_HEADER as oe,X_REDOCLY_CACHE_CONTROL_PUBLIC_HTML as re}from"../../constants/common.js";import{removeTrailingSlash as ie}from"../../../utils/url/remove-trailing-slash.js";import{findInIterable as ae}from"../../../utils/collection/find-in-iterable.js";import{sanitizeRedirectPathname as se}from"../../../utils/url/sanitize-redirect-pathname.js";import{envConfig as ce}from"../../config/env-config.js";import{sanitizePath as le}from"../../../utils/path/sanitize-path.js";import{normalizeRouteSlug as me}from"../../../utils/path/normalize-route-slug.js";import{isPathInFolder as ue}from"../../../utils/path/is-path-in-folder.js";import{getLlmsTxtMdPathBySlug as de}from"../../utils/llmstxt/get-llms-txt-md-path-by-slug.js";import{resolveLlmsTxtMd as X}from"../../utils/llmstxt/resolve-llms-txt-md.js";import{removeLeadingSlash as fe}from"../../../utils/url/remove-leading-slash.js";import{processRedirects as ge}from"./helpers/process-redirects.js";import{renderPage as pe,getServerProps as he}from"../../ssr/index.js";import{canAccessAsset as Ce,canAccessResource as Y}from"../../utils/rbac.js";import{handleErrorPageRender as $,handleUnauthorized as k,handleUnauthorizedAsset as N}from"../utils.js";import{DEFAULT_MAX_AGE_FOR_MIME_TYPE as Re,MIME_TYPES as Ae}from"../mime-types.js";import{fileExistsAsync as Ee}from"../../utils/index.js";import{isAiAgentRequest as Le}from"../../utils/ai-agent-detection.js";import{getRedirectRoute as _e}from"../utils/legacy-openapi-redirects.js";import{getContentTypeHeaderValue as G}from"../utils/content-type.js";import{telemetry as we}from"../../../cli/telemetry/index.js";import{telemetry as Te}from"../../telemetry/index.js";function Ke(e,j,V,E){return async n=>{const L=n.get("logger"),r=n.req,a=new URL(r.url),i=Q(le(decodeURIComponent(a.pathname))),_=m.parse(i).ext===".md",w=Le({accept:r.header("accept"),signatureAgent:r.header("signature-agent"),signature:r.header("signature"),signatureInput:r.header("signature-input"),userAgent:r.header("user-agent")}),s=me(i),o=(r.method==="GET"||r.method==="HEAD")&&!_?e.getRouteBySlug(s,{followRedirect:!1})||ae(e.routesBySlug?.values(),t=>t.hasClientRoutes&&(i===t.slug||i.startsWith(t.slug+"/"))):void 0,T=e.getRedirect(s);if(T){const t=ge({redirect:T,reqUrlSearch:a.search});return Te.sendRedirectMessage([{id:s,object:"redirect",uri:`urn:redocly:realm:api:redirect:${s}`,from:s,templateId:t.type.toString()}]),n.newResponse(null,t.type,{Location:t.location})}const g=ce.isProductionEnv?301:302;if(o?.metadata?.type==="openapi"){const t=_e(a.pathname);if(t)return L.info("Legacy OpenAPI docs redirect from "+a.pathname),n.newResponse(null,g,{Location:encodeURI(t)});if(a.pathname.match(/[A-Z]/))return L.warn("Redirect to lowercase route to avoid 404 error"),n.newResponse(null,g,{Location:encodeURI(a.pathname.toLowerCase())})}if(i.endsWith("/")&&i!=="/"){const t=se(new URL(s||"/",n.req.url).pathname);return n.newResponse(null,g,{Location:encodeURI(ee((t==="/"?"/":ie(t))+a.search))})}const{isAuthenticated:u,teams:p,claims:{email:h}}=n.get("auth");if(o&&!Y(o,{isAuthenticated:u,email:h,teams:p},e.config.access?.rbac,e.config.access?.requiresLogin))return u?$(n,e,{slug:o.slug,[B]:o[B],[v]:o[v]},403):k(n,e,o.slug);const d=o&&w?de(o.slug):void 0,P=d?await X(d,e,E):void 0,U=P?.exists??!1;if(o&&(!w||!U)){const t=await j(o),Z=await he(o,n,t,e),{html:x,statusCode:S,error:J}=await pe(o,Z,n,e,we),D=e.config.access?.rbac,H=!e.config.access?.requiresLogin&&(!D||!Object.keys(D).length),q=S>=400||!!J||!!e.compilationErrors?.length,K=H&&!q;let f;return q?f=z:H?f=te:f="private",n.html(x,S,{"Cache-Control":f,...K&&{[oe]:re}})}const C=d&&U?d:i,W=fe(C),c=m.resolve(e.outdir,W);if(!ue(c,e.outdir))return N(n);let l,M;if(_){const t=await X(i,e,E);if(l=t.route,M=t.content,l&&!Y(l,{isAuthenticated:u,email:h,teams:p},e.config.access?.rbac,e.config.access?.requiresLogin))return k(n,e,i)}const b=e.getGlobalConfig("access");if(!Ce(C,b?.rbac||{},b?.requiresLogin||!1,e.getGlobalConfig("directoryPaths"),{isAuthenticated:u,email:h,teams:p}))return N(n);const R=Ae[m.extname(c)]||"text/plain",A=c.match(/assets\/.*\.[a-f0-9]{8,}\..+/)||c.match(/runtime\/chunks\/.*/)?ne:Re[R],y=A?{"Cache-Control":`public, max-age=${A}, immutable`,Expires:new Date(Date.now()+A*1e3).toUTCString()}:{"Cache-Control":z},O=r.query("download")!=null,I=P?.content??M;if(I!==void 0)return n.newResponse(I,200,{"Content-Type":G(R),"Access-Control-Allow-Origin":"*",...y,...l&&{"X-Robots-Tag":"noindex, follow",...e.config.seo?.siteUrl&&{Link:`<${F(e.config.seo.siteUrl,l.slug)}>; rel="canonical"`}},...O&&{"Content-Disposition":`attachment; filename="${m.basename(C)}"`}});if(await Ee(c)){const t=await V(c);return n.newResponse(t,200,{"Content-Type":G(R),"Access-Control-Allow-Origin":"*",...y,...l&&{"X-Robots-Tag":"noindex, follow",...e.config.seo?.siteUrl&&{Link:`<${F(e.config.seo.siteUrl,l.slug)}>; rel="canonical"`}},...O&&{"Content-Disposition":`attachment; filename="${m.basename(c)}"`}})}else return $(n,e,{slug:s},404)}}export{Ke as dynamicRouteHandler};
1
+ import m from"path";import{REDOCLY_ROUTE_RBAC as B,REDOCLY_TEAMS_RBAC as F}from"@redocly/config";import{combineUrls as z,withoutPathPrefix as ee,withPathPrefix as E}from"@redocly/theme/core/utils";import{CACHE_CONTROL_NO_STORE_HEADER_VALUE as X,CACHE_CONTROL_PUBLIC_HTML as te,DEFAULT_IMMUTABLE_CACHE_MAX_AGE as ne,X_REDOCLY_CACHE_CONTROL_HEADER as oe,X_REDOCLY_CACHE_CONTROL_PUBLIC_HTML as re}from"../../constants/common.js";import{removeTrailingSlash as ie}from"../../../utils/url/remove-trailing-slash.js";import{findInIterable as ae}from"../../../utils/collection/find-in-iterable.js";import{sanitizeRedirectPathname as se}from"../../../utils/url/sanitize-redirect-pathname.js";import{envConfig as ce}from"../../config/env-config.js";import{sanitizePath as le}from"../../../utils/path/sanitize-path.js";import{normalizeRouteSlug as me}from"../../../utils/path/normalize-route-slug.js";import{isPathInFolder as ue}from"../../../utils/path/is-path-in-folder.js";import{getLlmsTxtMdPathBySlug as de}from"../../utils/llmstxt/get-llms-txt-md-path-by-slug.js";import{resolveLlmsTxtMd as Y}from"../../utils/llmstxt/resolve-llms-txt-md.js";import{removeLeadingSlash as fe}from"../../../utils/url/remove-leading-slash.js";import{processRedirects as ge}from"./helpers/process-redirects.js";import{renderPage as pe,getServerProps as he}from"../../ssr/index.js";import{canAccessAsset as Ce,canAccessResource as $}from"../../utils/rbac.js";import{handleErrorPageRender as k,handleUnauthorized as N,handleUnauthorizedAsset as G}from"../utils.js";import{DEFAULT_MAX_AGE_FOR_MIME_TYPE as Re,MIME_TYPES as Ae}from"../mime-types.js";import{fileExistsAsync as Ee}from"../../utils/index.js";import{isAiAgentRequest as Le}from"../../utils/ai-agent-detection.js";import{getRedirectRoute as _e}from"../utils/legacy-openapi-redirects.js";import{getContentTypeHeaderValue as j}from"../utils/content-type.js";import{telemetry as we}from"../../../cli/telemetry/index.js";import{telemetry as Te}from"../../telemetry/index.js";function Ke(e,V,W,L){return async n=>{const _=n.get("logger"),r=n.req,a=new URL(r.url),i=ee(le(decodeURIComponent(a.pathname))),w=m.parse(i).ext===".md",T=Le({accept:r.header("accept"),signatureAgent:r.header("signature-agent"),signature:r.header("signature"),signatureInput:r.header("signature-input"),userAgent:r.header("user-agent")}),s=me(i),o=(r.method==="GET"||r.method==="HEAD")&&!w?e.getRouteBySlug(s,{followRedirect:!1})||ae(e.routesBySlug?.values(),t=>t.hasClientRoutes&&(i===t.slug||i.startsWith(t.slug+"/"))):void 0,P=e.getRedirect(s);if(P){const t=ge({redirect:P,reqUrlSearch:a.search});return Te.sendRedirectMessage([{id:s,object:"redirect",uri:`urn:redocly:realm:api:redirect:${s}`,from:s,templateId:t.type.toString()}]),n.newResponse(null,t.type,{Location:t.location})}const g=ce.isProductionEnv?301:302;if(o?.metadata?.type==="openapi"){const t=_e(a.pathname);if(t)return _.info("Legacy OpenAPI docs redirect from "+a.pathname),n.newResponse(null,g,{Location:encodeURI(t)});if(a.pathname.match(/[A-Z]/))return _.warn("Redirect to lowercase route to avoid 404 error"),n.newResponse(null,g,{Location:encodeURI(a.pathname.toLowerCase())})}if(i.endsWith("/")&&i!=="/"){const t=se(new URL(s||"/",n.req.url).pathname);return n.newResponse(null,g,{Location:encodeURI(E((t==="/"?"/":ie(t))+a.search))})}const{isAuthenticated:u,teams:p,claims:{email:h}}=n.get("auth");if(o&&!$(o,{isAuthenticated:u,email:h,teams:p},e.config.access?.rbac,e.config.access?.requiresLogin))return u?k(n,e,{slug:o.slug,[F]:o[F],[B]:o[B]},403):N(n,e,o.slug);const d=o&&T?de(o.slug):void 0,U=d?await Y(d,e,L):void 0,M=U?.exists??!1;if(o&&(!T||!M)){const t=await V(o),x=await he(o,n,t,e),{html:J,statusCode:D,error:K}=await pe(o,x,n,e,we),H=e.config.access?.rbac,q=!e.config.access?.requiresLogin&&(!H||!Object.keys(H).length),v=D>=400||!!K||!!e.compilationErrors?.length,Q=q&&!v;let f;return v?f=X:q?f=te:f="private",n.html(J,D,{"Cache-Control":f,...Q&&{[oe]:re}})}const C=d&&M?d:i,Z=fe(C),c=m.resolve(e.outdir,Z);if(!ue(c,e.outdir))return G(n);let l,b;if(w){const t=await Y(i,e,L);if(l=t.route,b=t.content,l&&!$(l,{isAuthenticated:u,email:h,teams:p},e.config.access?.rbac,e.config.access?.requiresLogin))return N(n,e,i)}const y=e.getGlobalConfig("access");if(!Ce(C,y?.rbac||{},y?.requiresLogin||!1,e.getGlobalConfig("directoryPaths"),{isAuthenticated:u,email:h,teams:p}))return G(n);const R=Ae[m.extname(c)]||"text/plain",A=c.match(/assets\/.*\.[a-f0-9]{8,}\..+/)||c.match(/runtime\/chunks\/.*/)?ne:Re[R],O=A?{"Cache-Control":`public, max-age=${A}, immutable`,Expires:new Date(Date.now()+A*1e3).toUTCString()}:{"Cache-Control":X},I=r.query("download")!=null,S=U?.content??b;if(S!==void 0)return n.newResponse(S,200,{"Content-Type":j(R),"Access-Control-Allow-Origin":"*",...O,...l&&{"X-Robots-Tag":"noindex, follow",...e.config.seo?.siteUrl&&{Link:`<${z(e.config.seo.siteUrl,E(l.slug))}>; rel="canonical"`}},...I&&{"Content-Disposition":`attachment; filename="${m.basename(C)}"`}});if(await Ee(c)){const t=await W(c);return n.newResponse(t,200,{"Content-Type":j(R),"Access-Control-Allow-Origin":"*",...O,...l&&{"X-Robots-Tag":"noindex, follow",...e.config.seo?.siteUrl&&{Link:`<${z(e.config.seo.siteUrl,E(l.slug))}>; rel="canonical"`}},...I&&{"Content-Disposition":`attachment; filename="${m.basename(c)}"`}})}else return k(n,e,{slug:s},404)}}export{Ke as dynamicRouteHandler};