@redocly/realm 0.136.0-next.5 → 0.136.0-next.7

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 (298) hide show
  1. package/CHANGELOG.md +60 -0
  2. package/dist/bin.js +1 -1
  3. package/dist/cli/build/analytics/collect-analytics.js +1 -1
  4. package/dist/cli/build/index.js +1 -1
  5. package/dist/cli/eject/resolveEjectParams.js +1 -1
  6. package/dist/cli/stats/collectors/openapi/index.js +1 -1
  7. package/dist/cli/stats/index.js +1 -1
  8. package/dist/client/App.js +1 -1
  9. package/dist/client/TestProvider.js +1 -1
  10. package/dist/client/api-docs-builder-entry.d.ts +3 -0
  11. package/dist/client/api-docs-builder-entry.js +1 -0
  12. package/dist/client/app/Feedback/useSubmitFeedback.js +1 -1
  13. package/dist/client/app/Sidebar/Sidebar.js +3 -3
  14. package/dist/client/app/Sidebar/helpers/hide-empty-separators.d.ts +13 -0
  15. package/dist/client/app/Sidebar/helpers/hide-empty-separators.js +1 -0
  16. package/dist/client/app/Sidebar/useActions.js +1 -1
  17. package/dist/client/app/Sidebar/utils.js +1 -1
  18. package/dist/client/app/hooks/codeHighlight/useCodeHighlight.js +1 -1
  19. package/dist/client/app/hooks/index.d.ts +1 -0
  20. package/dist/client/app/hooks/index.js +1 -1
  21. package/dist/client/app/hooks/useAutoScroll.js +1 -1
  22. package/dist/client/app/hooks/useUserClaims.js +1 -1
  23. package/dist/client/app/l10n/hooks/index.d.ts +1 -0
  24. package/dist/client/app/l10n/hooks/index.js +1 -1
  25. package/dist/client/app/l10n/hooks/useTranslationKeys.d.ts +2 -0
  26. package/dist/client/app/l10n/hooks/useTranslationKeys.js +1 -0
  27. package/dist/client/app/markdoc/custom-components/openapi/json-schema.d.ts +1 -1
  28. package/dist/client/app/markdoc/custom-components/openapi/json-schema.js +1 -1
  29. package/dist/client/app/markdoc/custom-components/openapi/openapi-code-sample.d.ts +1 -5
  30. package/dist/client/app/markdoc/custom-components/openapi/openapi-code-sample.js +1 -1
  31. package/dist/client/app/markdoc/custom-components/openapi/openapi-example.js +1 -1
  32. package/dist/client/app/markdoc/custom-components/openapi/openapi-response-sample.js +1 -1
  33. package/dist/client/app/markdoc/custom-components/openapi/replay-openapi.d.ts +8 -24
  34. package/dist/client/app/markdoc/custom-components/openapi/replay-openapi.js +1 -1
  35. package/dist/client/app/markdoc/hooks/use-store.d.ts +8 -6
  36. package/dist/client/app/markdoc/utils/build-replay-operation-source-map.d.ts +20 -0
  37. package/dist/client/app/markdoc/utils/build-replay-operation-source-map.js +1 -0
  38. package/dist/client/app/markdoc/utils/find-api-item.d.ts +15 -0
  39. package/dist/client/app/markdoc/utils/find-api-item.js +1 -0
  40. package/dist/client/app/markdoc/utils/find-code-sample-panel.d.ts +11 -0
  41. package/dist/client/app/markdoc/utils/find-code-sample-panel.js +1 -0
  42. package/dist/client/app/markdoc/utils/find-openapi-response-samples.d.ts +15 -0
  43. package/dist/client/app/markdoc/utils/find-openapi-response-samples.js +1 -0
  44. package/dist/client/app/markdoc/utils/openapi-panel-entry.d.ts +18 -0
  45. package/dist/client/app/markdoc/utils/openapi-panel-entry.js +1 -0
  46. package/dist/client/app/utils/resolveRouteBySlug.js +1 -1
  47. package/dist/client/app/utils/same-resolved-route.d.ts +5 -0
  48. package/dist/client/app/utils/same-resolved-route.js +1 -0
  49. package/dist/client/providers/post-message/PostMessageProvider.js +1 -1
  50. package/dist/client/providers/theme/ThemeDataProvider.js +1 -1
  51. package/dist/client/runtime/loader.js +1 -1
  52. package/dist/client/templates/api-docs/helpers.d.ts +10 -0
  53. package/dist/client/templates/api-docs/helpers.js +1 -0
  54. package/dist/client/templates/api-docs/template.d.ts +17 -0
  55. package/dist/client/templates/api-docs/template.js +14 -0
  56. package/dist/client/types/sidebar.d.ts +0 -1
  57. package/dist/client/utils/utils.d.ts +0 -2
  58. package/dist/client/utils/utils.js +1 -1
  59. package/dist/constants/common.d.ts +11 -1
  60. package/dist/constants/common.js +1 -1
  61. package/dist/constants/l10n/langs/ar.js +1 -1
  62. package/dist/constants/l10n/langs/de.js +1 -1
  63. package/dist/constants/l10n/langs/en.js +1 -1
  64. package/dist/constants/l10n/langs/es.js +1 -1
  65. package/dist/constants/l10n/langs/fr.js +1 -1
  66. package/dist/constants/l10n/langs/hi.js +1 -1
  67. package/dist/constants/l10n/langs/it.js +1 -1
  68. package/dist/constants/l10n/langs/ja.js +1 -1
  69. package/dist/constants/l10n/langs/ko.js +1 -1
  70. package/dist/constants/l10n/langs/pl.js +1 -1
  71. package/dist/constants/l10n/langs/pt-BR.js +1 -1
  72. package/dist/constants/l10n/langs/pt.js +1 -1
  73. package/dist/constants/l10n/langs/ru.js +1 -1
  74. package/dist/constants/l10n/langs/uk.js +1 -1
  75. package/dist/constants/l10n/langs/zh.js +1 -1
  76. package/dist/server/config/env-schemas/feature-flags.d.ts +1 -1
  77. package/dist/server/constants/entitlements.js +1 -1
  78. package/dist/server/constants/plugins/api-docs.d.ts +3 -0
  79. package/dist/server/constants/plugins/api-docs.js +1 -0
  80. package/dist/server/esbuild/esbuild-logger.js +3 -3
  81. package/dist/server/esbuild/esbuild.js +3 -3
  82. package/dist/server/esbuild/plugins/api-docs-module-replacer/empty-check.d.ts +9 -0
  83. package/dist/server/esbuild/plugins/api-docs-module-replacer/empty-check.js +1 -0
  84. package/dist/server/esbuild/plugins/api-docs-module-replacer/empty-overlay.d.ts +2 -0
  85. package/dist/server/esbuild/plugins/api-docs-module-replacer/empty-overlay.js +1 -0
  86. package/dist/server/esbuild/plugins/api-docs-module-replacer/index.d.ts +6 -0
  87. package/dist/server/esbuild/plugins/api-docs-module-replacer/index.js +1 -0
  88. package/dist/server/plugins/api-docs/get-server-props.d.ts +4 -0
  89. package/dist/server/plugins/api-docs/get-server-props.js +1 -0
  90. package/dist/server/plugins/api-docs/get-template-path.d.ts +2 -0
  91. package/dist/server/plugins/api-docs/get-template-path.js +1 -0
  92. package/dist/server/plugins/api-docs/import-api-docs-builder.d.ts +8 -0
  93. package/dist/server/plugins/api-docs/import-api-docs-builder.js +1 -0
  94. package/dist/server/plugins/api-docs/index.d.ts +19 -0
  95. package/dist/server/plugins/api-docs/index.js +1 -0
  96. package/dist/server/plugins/api-docs/loader.d.ts +35 -0
  97. package/dist/server/plugins/api-docs/loader.js +3 -0
  98. package/dist/server/plugins/api-docs/options.d.ts +14 -0
  99. package/dist/server/plugins/api-docs/options.js +1 -0
  100. package/dist/server/plugins/api-docs/search/get-ai-search-documents.d.ts +20 -0
  101. package/dist/server/plugins/api-docs/search/get-ai-search-documents.js +105 -0
  102. package/dist/server/plugins/api-docs/search/search-facets.d.ts +10 -0
  103. package/dist/server/plugins/api-docs/search/search-facets.js +1 -0
  104. package/dist/server/plugins/api-docs/search/search-indexer.d.ts +9 -0
  105. package/dist/server/plugins/api-docs/search/search-indexer.js +1 -0
  106. package/dist/server/plugins/api-docs/search/search-resolver.d.ts +5 -0
  107. package/dist/server/plugins/api-docs/search/search-resolver.js +1 -0
  108. package/dist/server/plugins/api-docs/spec-download.api.d.ts +4 -0
  109. package/dist/server/plugins/api-docs/spec-download.api.js +1 -0
  110. package/dist/server/plugins/api-docs/store-definition-bundles.d.ts +3 -0
  111. package/dist/server/plugins/api-docs/store-definition-bundles.js +1 -0
  112. package/dist/server/plugins/api-docs/utils/build-item-positions.d.ts +17 -0
  113. package/dist/server/plugins/api-docs/utils/build-item-positions.js +1 -0
  114. package/dist/server/plugins/api-docs/utils/build-routes-mapping.d.ts +3 -0
  115. package/dist/server/plugins/api-docs/utils/build-routes-mapping.js +1 -0
  116. package/dist/server/plugins/api-docs/utils/collect-item-routes.d.ts +12 -0
  117. package/dist/server/plugins/api-docs/utils/collect-item-routes.js +1 -0
  118. package/dist/server/plugins/api-docs/utils/decorators.d.ts +26 -0
  119. package/dist/server/plugins/api-docs/utils/decorators.js +1 -0
  120. package/dist/server/plugins/api-docs/utils/format-bundle-error.d.ts +6 -0
  121. package/dist/server/plugins/api-docs/utils/format-bundle-error.js +5 -0
  122. package/dist/server/plugins/api-docs/utils/normalize-api-version.d.ts +2 -0
  123. package/dist/server/plugins/api-docs/utils/normalize-api-version.js +1 -0
  124. package/dist/server/plugins/api-docs/utils/normalize-feedback-options.d.ts +2 -0
  125. package/dist/server/plugins/api-docs/utils/normalize-feedback-options.js +1 -0
  126. package/dist/server/plugins/api-docs/utils/relative-path-to-base-slug.d.ts +20 -0
  127. package/dist/server/plugins/api-docs/utils/relative-path-to-base-slug.js +1 -0
  128. package/dist/server/plugins/api-docs/utils/replace-file-extension.d.ts +2 -0
  129. package/dist/server/plugins/api-docs/utils/replace-file-extension.js +1 -0
  130. package/dist/server/plugins/api-docs/utils/resolve-api-doc-title.d.ts +3 -0
  131. package/dist/server/plugins/api-docs/utils/resolve-api-doc-title.js +1 -0
  132. package/dist/server/plugins/api-docs/utils/resolve-config-rbac.d.ts +10 -0
  133. package/dist/server/plugins/api-docs/utils/resolve-config-rbac.js +1 -0
  134. package/dist/server/plugins/api-docs/utils/to-relative-slug.d.ts +2 -0
  135. package/dist/server/plugins/api-docs/utils/to-relative-slug.js +1 -0
  136. package/dist/server/plugins/api-functions/index.js +1 -1
  137. package/dist/server/plugins/arazzo-docs/index.js +1 -1
  138. package/dist/server/plugins/asyncapi-docs/index.js +1 -1
  139. package/dist/server/plugins/catalog-classic/index.js +1 -1
  140. package/dist/server/plugins/catalog-entities/extensions/extractors/api-description/arazzo-entities-extractor.js +1 -1
  141. package/dist/server/plugins/catalog-entities/extensions/extractors/api-description/asyncapi-entities-extractor.d.ts +13 -5
  142. package/dist/server/plugins/catalog-entities/extensions/extractors/api-description/asyncapi-entities-extractor.js +1 -1
  143. package/dist/server/plugins/catalog-entities/extensions/extractors/api-description/base.js +1 -1
  144. package/dist/server/plugins/catalog-entities/extensions/extractors/api-description/graphql-entities-extractor.d.ts +6 -5
  145. package/dist/server/plugins/catalog-entities/extensions/extractors/api-description/graphql-entities-extractor.js +2 -2
  146. package/dist/server/plugins/catalog-entities/extensions/extractors/api-description/openapi-entities-extractor.d.ts +12 -5
  147. package/dist/server/plugins/catalog-entities/extensions/extractors/api-description/openapi-entities-extractor.js +1 -1
  148. package/dist/server/plugins/catalog-entities/plugin.js +1 -1
  149. package/dist/server/plugins/catalog-entities/template/index.js +1 -1
  150. package/dist/server/plugins/catalog-entities/types/openapi.d.ts +1 -1
  151. package/dist/server/plugins/catalog-entities/utils/openapi-component-content-extractor.d.ts +3 -3
  152. package/dist/server/plugins/catalog-entities/utils/openapi-component-content-extractor.js +1 -1
  153. package/dist/server/plugins/catalog-entities/utils/openapi-schema-resolver.d.ts +4 -3
  154. package/dist/server/plugins/catalog-entities/utils/openapi-schema-resolver.js +1 -1
  155. package/dist/server/plugins/config-parser/index.js +1 -1
  156. package/dist/server/plugins/create-slugify.d.ts +17 -0
  157. package/dist/server/plugins/create-slugify.js +1 -0
  158. package/dist/server/plugins/default-theme/index.js +1 -1
  159. package/dist/server/plugins/dev-onboarding/index.js +1 -1
  160. package/dist/server/plugins/entitlements/index.js +1 -1
  161. package/dist/server/plugins/graphql-docs/index.js +1 -1
  162. package/dist/server/plugins/helpers/parse-partials.d.ts +3 -0
  163. package/dist/server/plugins/helpers/parse-partials.js +1 -0
  164. package/dist/server/plugins/l10n/index.js +1 -1
  165. package/dist/server/plugins/lifecycle.js +2 -2
  166. package/dist/server/plugins/markdown/attribute-resolvers/helpers/load-openapi-bundle.d.ts +5 -3
  167. package/dist/server/plugins/markdown/attribute-resolvers/helpers/load-openapi-bundle.js +1 -1
  168. package/dist/server/plugins/markdown/attribute-resolvers/resolve-json-example-ref.js +1 -1
  169. package/dist/server/plugins/markdown/attribute-resolvers/resolve-open-api-ref.js +1 -1
  170. package/dist/server/plugins/markdown/attribute-resolvers/resolve-openapi-code-samples.js +1 -1
  171. package/dist/server/plugins/markdown/attribute-resolvers/resolve-openapi-response-samples.js +1 -1
  172. package/dist/server/plugins/markdown/index.js +1 -1
  173. package/dist/server/plugins/markdown/search/walk-sections.js +1 -1
  174. package/dist/server/plugins/mcp/auth/auth-handlers.d.ts +1 -0
  175. package/dist/server/plugins/mcp/auth/auth-handlers.js +1 -1
  176. package/dist/server/plugins/mcp/codemode/constants.js +1 -1
  177. package/dist/server/plugins/mcp/codemode/tools/execute-schema.js +1 -1
  178. package/dist/server/plugins/mcp/codemode/tools/execute.d.ts +1 -0
  179. package/dist/server/plugins/mcp/constants.d.ts +1 -0
  180. package/dist/server/plugins/mcp/constants.js +1 -1
  181. package/dist/server/plugins/mcp/docs-mcp/tool-schemas.d.ts +1 -0
  182. package/dist/server/plugins/mcp/docs-mcp/tool-schemas.js +1 -1
  183. package/dist/server/plugins/mcp/docs-mcp/tools/core/create-anonymous-session.d.ts +11 -0
  184. package/dist/server/plugins/mcp/docs-mcp/tools/core/create-anonymous-session.js +1 -0
  185. package/dist/server/plugins/mcp/docs-mcp/tools/graphql/constants.d.ts +4 -0
  186. package/dist/server/plugins/mcp/docs-mcp/tools/graphql/constants.js +1 -0
  187. package/dist/server/plugins/mcp/docs-mcp/tools/graphql/get-graphql-type-list.js +1 -1
  188. package/dist/server/plugins/mcp/docs-mcp/tools/graphql/get-graphql-type.js +7 -4
  189. package/dist/server/plugins/mcp/docs-mcp/tools/graphql/types.d.ts +7 -1
  190. package/dist/server/plugins/mcp/docs-mcp/tools/graphql/types.js +0 -1
  191. package/dist/server/plugins/mcp/docs-mcp/tools/graphql/utils.d.ts +5 -1
  192. package/dist/server/plugins/mcp/docs-mcp/tools/graphql/utils.js +4 -2
  193. package/dist/server/plugins/mcp/docs-mcp/tools/index.d.ts +4 -0
  194. package/dist/server/plugins/mcp/docs-mcp/tools/index.js +1 -1
  195. package/dist/server/plugins/mcp/docs-mcp/tools/openapi/load-api-description.d.ts +1 -1
  196. package/dist/server/plugins/mcp/docs-mcp/tools/openapi/utils.d.ts +1 -1
  197. package/dist/server/plugins/mcp/docs-mcp/utils.d.ts +1 -1
  198. package/dist/server/plugins/mcp/gateway-mcp/elicitation.d.ts +4 -2
  199. package/dist/server/plugins/mcp/gateway-mcp/elicitation.js +2 -2
  200. package/dist/server/plugins/mcp/gateway-mcp/eligibility.d.ts +1 -2
  201. package/dist/server/plugins/mcp/gateway-mcp/fetch/allowed-hosts.d.ts +1 -1
  202. package/dist/server/plugins/mcp/gateway-mcp/fetch/fetch-bridge.d.ts +4 -2
  203. package/dist/server/plugins/mcp/gateway-mcp/fetch/fetch-bridge.js +1 -1
  204. package/dist/server/plugins/mcp/gateway-mcp/fetch/fetch-errors.d.ts +11 -0
  205. package/dist/server/plugins/mcp/gateway-mcp/fetch/fetch-errors.js +1 -0
  206. package/dist/server/plugins/mcp/gateway-mcp/fetch/fetch-telemetry.d.ts +13 -0
  207. package/dist/server/plugins/mcp/gateway-mcp/fetch/fetch-telemetry.js +1 -0
  208. package/dist/server/plugins/mcp/gateway-mcp/fetch/redact.d.ts +4 -0
  209. package/dist/server/plugins/mcp/gateway-mcp/fetch/redact.js +1 -0
  210. package/dist/server/plugins/mcp/gateway-mcp/fetch/ssrf-blocklist.d.ts +12 -0
  211. package/dist/server/plugins/mcp/gateway-mcp/fetch/ssrf-blocklist.js +1 -1
  212. package/dist/server/plugins/mcp/gateway-mcp/fetch/ssrf-guard.js +1 -1
  213. package/dist/server/plugins/mcp/gateway-mcp/fetch/ssrf-safe-lookup.d.ts +3 -1
  214. package/dist/server/plugins/mcp/gateway-mcp/fetch/ssrf-safe-lookup.js +1 -1
  215. package/dist/server/plugins/mcp/gateway-mcp/fetch-capability.js +1 -1
  216. package/dist/server/plugins/mcp/gateway-mcp/rate-limit/apply-edge-rate-limit.d.ts +3 -0
  217. package/dist/server/plugins/mcp/gateway-mcp/rate-limit/apply-edge-rate-limit.js +1 -0
  218. package/dist/server/plugins/mcp/gateway-mcp/rate-limit/edge-limiter.d.ts +16 -0
  219. package/dist/server/plugins/mcp/gateway-mcp/rate-limit/edge-limiter.js +1 -0
  220. package/dist/server/plugins/mcp/gateway-mcp/rate-limit/ip-key.d.ts +2 -0
  221. package/dist/server/plugins/mcp/gateway-mcp/rate-limit/ip-key.js +1 -0
  222. package/dist/server/plugins/mcp/gateway-mcp/rate-limit/limits.d.ts +7 -0
  223. package/dist/server/plugins/mcp/gateway-mcp/rate-limit/limits.js +1 -0
  224. package/dist/server/plugins/mcp/gateway-mcp/rate-limit/window-counter.d.ts +15 -0
  225. package/dist/server/plugins/mcp/gateway-mcp/rate-limit/window-counter.js +1 -0
  226. package/dist/server/plugins/mcp/gateway-mcp/secret-store.d.ts +8 -8
  227. package/dist/server/plugins/mcp/gateway-mcp/secret-store.js +1 -1
  228. package/dist/server/plugins/mcp/gateway-mcp/subject.d.ts +20 -0
  229. package/dist/server/plugins/mcp/gateway-mcp/subject.js +1 -0
  230. package/dist/server/plugins/mcp/handlers/docs-mcp-handler.js +1 -1
  231. package/dist/server/plugins/mcp/handlers/errors.js +1 -1
  232. package/dist/server/plugins/mcp/handlers/handle-mcp-request.js +1 -1
  233. package/dist/server/plugins/mcp/handlers/mcp-credentials-handler.js +26 -26
  234. package/dist/server/plugins/mcp/index.js +1 -1
  235. package/dist/server/plugins/mcp/servers/docs-server.d.ts +3 -1
  236. package/dist/server/plugins/mcp/servers/docs-server.js +1 -1
  237. package/dist/server/plugins/mcp/servers/mcp-server.d.ts +2 -0
  238. package/dist/server/plugins/mcp/servers/mcp-server.js +1 -1
  239. package/dist/server/plugins/mcp/servers/session-manager.js +1 -1
  240. package/dist/server/plugins/mcp/types.d.ts +4 -2
  241. package/dist/server/plugins/mcp/utils/mode.js +1 -1
  242. package/dist/server/plugins/mcp/utils/telemetry-attributes.d.ts +8 -0
  243. package/dist/server/plugins/mcp/utils/telemetry-attributes.js +1 -0
  244. package/dist/server/plugins/mcp/utils/xmcp-utils.d.ts +1 -1
  245. package/dist/server/plugins/mcp/utils.d.ts +17 -5
  246. package/dist/server/plugins/mcp/utils.js +1 -1
  247. package/dist/server/plugins/mcp/workers/mcp-tool-telemetry.js +1 -1
  248. package/dist/server/plugins/openapi-docs/index.js +1 -1
  249. package/dist/server/plugins/openapi-docs/utils.js +1 -1
  250. package/dist/server/plugins/pages/index.js +1 -1
  251. package/dist/server/plugins/scorecard-classic/compute-scorecard.js +4 -4
  252. package/dist/server/plugins/scorecard-classic/index.js +1 -1
  253. package/dist/server/plugins/scorecards/plugin.js +1 -1
  254. package/dist/server/plugins/search/ai-indexer/prepare-semantic-documents.js +2 -2
  255. package/dist/server/plugins/search/documents/search-documents.js +1 -1
  256. package/dist/server/plugins/search/index.js +1 -1
  257. package/dist/server/plugins/search/llmstxt/index.js +4 -4
  258. package/dist/server/plugins/sidebars/index.js +1 -1
  259. package/dist/server/plugins/sitemap/index.js +1 -1
  260. package/dist/server/plugins/sso/index.js +1 -1
  261. package/dist/server/ssr/render.js +1 -1
  262. package/dist/server/ssr/utils.d.ts +1 -0
  263. package/dist/server/ssr/utils.js +5 -5
  264. package/dist/server/store.d.ts +2 -6
  265. package/dist/server/store.js +1 -1
  266. package/dist/server/types/plugins/common.d.ts +3 -5
  267. package/dist/server/types/plugins/markdown.d.ts +1 -3
  268. package/dist/server/types/plugins/search.d.ts +1 -0
  269. package/dist/server/utils/catalog-classic/get-route-slug-to-catalog-slug-map.test.js +1 -1
  270. package/dist/server/utils/rbac.d.ts +4 -0
  271. package/dist/server/utils/rbac.js +1 -1
  272. package/dist/server/utils/report-all-errors.js +1 -1
  273. package/dist/server/utils/shared-data.js +1 -1
  274. package/dist/server/web-server/routes/resolve-route.js +1 -1
  275. package/dist/server/workers/worker-pool.js +1 -1
  276. package/dist/types/entitlements.d.ts +3 -0
  277. package/dist/types/markdoc.d.ts +2 -1
  278. package/dist/utils/url/get-shared-data-fetch-url.d.ts +17 -0
  279. package/dist/utils/url/get-shared-data-fetch-url.js +1 -0
  280. package/package.json +9 -8
  281. package/dist/markdoc/helpers/get-operation/get-operation-info-by-id.d.ts +0 -4
  282. package/dist/markdoc/helpers/get-operation/get-operation-info-by-id.js +0 -1
  283. package/dist/markdoc/helpers/get-operation/get-operation-info-by-pointer.d.ts +0 -4
  284. package/dist/markdoc/helpers/get-operation/get-operation-info-by-pointer.js +0 -1
  285. package/dist/markdoc/helpers/get-operation/get-operation.d.ts +0 -14
  286. package/dist/markdoc/helpers/get-operation/get-operation.js +0 -1
  287. package/dist/markdoc/helpers/get-operation/index.d.ts +0 -4
  288. package/dist/markdoc/helpers/get-operation/index.js +0 -1
  289. package/dist/markdoc/helpers/get-operation/types/index.d.ts +0 -4
  290. package/dist/markdoc/helpers/get-operation/types/index.js +0 -0
  291. package/dist/markdoc/helpers/get-operation/types/operation-identifier.d.ts +0 -5
  292. package/dist/markdoc/helpers/get-operation/types/operation-identifier.js +0 -0
  293. package/dist/markdoc/helpers/get-operation/types/operation-info.d.ts +0 -6
  294. package/dist/markdoc/helpers/get-operation/types/operation-info.js +0 -0
  295. package/dist/markdoc/helpers/get-operation/types/operation-parameters.d.ts +0 -3
  296. package/dist/markdoc/helpers/get-operation/types/operation-parameters.js +0 -0
  297. package/dist/server/plugins/markdown/attribute-resolvers/helpers/get-media-content-samples.d.ts +0 -4
  298. package/dist/server/plugins/markdown/attribute-resolvers/helpers/get-media-content-samples.js +0 -1
@@ -1 +1 @@
1
- import{createCipheriv as f,createDecipheriv as u,createHash as d,hkdfSync as l,randomBytes as p,randomUUID as y}from"node:crypto";const A=14400*1e3,g=900*1e3,S=60*1e3,x="mcp-upstream-secrets";class m{#e=new Map;#t=new Map;#n=p(32);constructor(){setInterval(()=>this.#r(),S).unref?.()}setSecret(e,t,i){const s=this.#s(e),r=p(12),o=f("aes-256-gcm",s,r),c=Buffer.concat([o.update(JSON.stringify(i),"utf8"),o.final()]),n=this.#e.get(this.#i(e))??{byApi:new Map};n.byApi.set(t,{iv:r,tag:o.getAuthTag(),data:c,expiresAt:Date.now()+A}),this.#e.set(this.#i(e),n)}getSecretsForSession(e){const t=this.#i(e),i=this.#e.get(t);if(!i)return{};const s=Date.now(),r=this.#s(e),o={};for(const[c,n]of i.byApi){if(n.expiresAt<=s){i.byApi.delete(c);continue}try{const a=u("aes-256-gcm",r,n.iv);a.setAuthTag(n.tag);const h=Buffer.concat([a.update(n.data),a.final()]).toString("utf8");o[c]=JSON.parse(h)}catch{i.byApi.delete(c)}}return i.byApi.size===0&&this.#e.delete(t),o}deleteSession(e){this.#e.delete(this.#i(e))}createElicitation(e){const t=y();return this.#t.set(t,{...e,expiresAt:Date.now()+g}),t}peekElicitation(e){const t=this.#t.get(e);if(!t)return;if(t.expiresAt<=Date.now()){this.#t.delete(e);return}const{expiresAt:i,...s}=t;return s}consumeElicitation(e){const t=this.peekElicitation(e);return t&&this.#t.delete(e),t}#r(){const e=Date.now();for(const[t,i]of this.#e){for(const[s,r]of i.byApi)r.expiresAt<=e&&i.byApi.delete(s);i.byApi.size===0&&this.#e.delete(t)}for(const[t,i]of this.#t)i.expiresAt<=e&&this.#t.delete(t)}#i(e){return d("sha256").update(e).digest("hex")}#s(e){return Buffer.from(l("sha256",e,this.#n,x,32))}}const T=new m;export{g as ELICITATION_TTL_MS,m as SecretStore,T as secretStore};
1
+ import{createCipheriv as o,createDecipheriv as f,createHash as u,hkdfSync as a,randomBytes as h,randomUUID as m}from"node:crypto";import{JWT_SECRET_KEY as c}from"../../../constants/common.js";import{secretTtlSeconds as l}from"./subject.js";const p=900*1e3,d="mcp-upstream-secrets",y="mcp-elicitation",S="mcp-elicitation";class g{async setSecret(t,e,r,n){const i={api:r,...this.#c(this.#a(e),n,r)};await t.set(this.#n(e,r),i,{ttlInSeconds:l(e)})}async getSecretsForSubject(t,e){const r=this.#a(e),{items:n}=await t.list({prefix:this.#i(e)}),i={};for(const s of n)if(s.value)try{i[s.value.api]=this.#r(r,s.value,s.value.api)}catch{continue}return i}async deleteSubject(t,e){const{items:r}=await t.list({prefix:this.#i(e)}),n=r.flatMap(i=>i.value?[this.#n(e,i.value.api)]:[]);n.length!==0&&await t.transaction(async i=>{for(const s of n)await i.delete(s)})}async createElicitation(t,e){const r=m();return await t.set(this.#t(r),this.#c(this.#e(),e),{ttlInSeconds:p/1e3}),r}async peekElicitation(t,e){const r=await t.get(this.#t(e));if(r)try{return this.#r(this.#e(),r)}catch{return}}async consumeElicitation(t,e){const r=this.#t(e),n=await t.transaction(async i=>{const s=await i.get(r);return s&&await i.delete(r),s});if(n)try{return this.#r(this.#e(),n)}catch{return}}#i(t){return["mcp","secret",this.#s(t)]}#n(t,e){return["mcp","secret",this.#s(t),e]}#t(t){return["mcp","elicitation",t]}#s(t){return u("sha256").update(t).digest("hex")}#a(t){return Buffer.from(a("sha256",c,t,d,32))}#e(){return Buffer.from(a("sha256",c,S,y,32))}#c(t,e,r){const n=h(12),i=o("aes-256-gcm",t,n);r&&i.setAAD(Buffer.from(r,"utf8"));const s=Buffer.concat([i.update(JSON.stringify(e),"utf8"),i.final()]);return{iv:n.toString("base64"),tag:i.getAuthTag().toString("base64"),data:s.toString("base64")}}#r(t,e,r){const n=f("aes-256-gcm",t,Buffer.from(e.iv,"base64"));r&&n.setAAD(Buffer.from(r,"utf8")),n.setAuthTag(Buffer.from(e.tag,"base64"));const i=Buffer.concat([n.update(Buffer.from(e.data,"base64")),n.final()]).toString("utf8");return JSON.parse(i)}}const E=new g;export{p as ELICITATION_TTL_MS,g as SecretStore,E as secretStore};
@@ -0,0 +1,20 @@
1
+ import type { ApiFunctionsUser } from '@redocly/config';
2
+ export declare const ANONYMOUS_SUBJECT_PREFIX = "anon:";
3
+ export declare const USER_SUBJECT_PREFIX = "user:";
4
+ export declare const MISSING_SESSION_HANDLE_MESSAGE = "This API requires credentials and the caller is anonymous; call createAnonymousSession first, then retry with sessionHandle";
5
+ export declare const MALFORMED_SESSION_HANDLE_MESSAGE = "The sessionHandle is not a valid handle; call createAnonymousSession to obtain one";
6
+ export type SubjectResolution = {
7
+ kind: 'resolved';
8
+ subject: string;
9
+ } | {
10
+ kind: 'anonymous';
11
+ } | {
12
+ kind: 'invalid';
13
+ message: string;
14
+ };
15
+ export declare function createSessionHandle(): string;
16
+ export declare function isValidSessionHandle(value: string): boolean;
17
+ export declare function userSubject(user: ApiFunctionsUser | undefined): string | undefined;
18
+ export declare function resolveSecretSubject(user: ApiFunctionsUser | undefined, sessionHandle: string | undefined): SubjectResolution;
19
+ export declare function secretTtlSeconds(subject: string): number;
20
+ //# sourceMappingURL=subject.d.ts.map
@@ -0,0 +1 @@
1
+ import{randomBytes as r}from"node:crypto";const i=32,S=/^[A-Za-z0-9_-]{43}$/,c=1440*60,u=720*60*60,s="anon:",d="user:",f="This API requires credentials and the caller is anonymous; call createAnonymousSession first, then retry with sessionHandle",a="The sessionHandle is not a valid handle; call createAnonymousSession to obtain one";function N(){return r(i).toString("base64url")}function E(e){return S.test(e)}function l(e){if(!e?.isAuthenticated)return;const n=e.claims,o=(typeof n?.sub=="string"&&n.sub?n.sub:void 0)??(e.email||void 0);if(o)return`${d}${e.idpId??"local"}:${o}`}function A(e,n){const t=l(e);return t?{kind:"resolved",subject:t}:n===void 0?{kind:"anonymous"}:E(n)?{kind:"resolved",subject:`${s}${n}`}:{kind:"invalid",message:a}}function T(e){return e.startsWith(s)?c:u}export{s as ANONYMOUS_SUBJECT_PREFIX,a as MALFORMED_SESSION_HANDLE_MESSAGE,f as MISSING_SESSION_HANDLE_MESSAGE,d as USER_SUBJECT_PREFIX,N as createSessionHandle,E as isValidSessionHandle,A as resolveSecretSubject,T as secretTtlSeconds,l as userSubject};
@@ -1 +1 @@
1
- import{toFetchResponse as j,toReqRes as H}from"fetch-to-node";import{isInitializeRequest as L}from"@redocly/mcp-typescript-sdk/types.js";import{logger as S}from"../../../tools/notifiers/logger.js";import{isObject as B}from"../../../../utils/guards/is-object.js";import{getAccessibleSkills as J}from"../../../utils/skills/get-accessible-skills.js";import{getSkillUrl as P}from"../../../utils/skills/get-skill-url.js";import{createDocsMcpServer as A}from"../servers/docs-server.js";import{mcpSessionManager as g}from"../servers/session-manager.js";import{filterApiDescriptionsByRbac as _,filterGraphqlDescriptionsByRbac as z}from"../utils.js";import{createMethodNotAllowedError as V,withErrorHandling as F}from"./errors.js";import{attachSseKeepalive as G}from"./sse-keepalive.js";import{constructInvalidTokenResponse as $,constructUnauthorizedResponse as K,handleMcpAuth as X,shouldHandleMcpAuth as Q}from"../auth/auth-handlers.js";import{extractTokenFromAuthHeader as W}from"../utils/jwt.js";import{DEFAULT_DOCS_MCP_SERVER_NAME as Y}from"../constants.js";const h="X-Redocly-AI-Metadata";function Z(e){if(e)try{const o=JSON.parse(e);if(B(o))return o;S.warn(`Ignoring ${h} header: not a JSON object.`)}catch{S.warn(`Ignoring ${h} header: invalid JSON.`)}}const q=async(e,o,a)=>{const t=!!o?.config?.access?.requiresLogin,r=o?.config?.access?.rbac||{},l=a?.props?.config?.mcpMode??"tools";let c;const R=e.headers.get("Authorization");if(Q(t,r)){const{isAuthenticated:f,isTokenValid:p,currentUser:n,accessToken:u}=await X(e,o);if(!f)return K(new URL(e.url).origin);if(!p)return $();n&&(o.user=n),c=u}else R&&(c=W(R||"")??void 0);let i;return await F(async()=>{const f=e.headers.get("mcp-session-id")??void 0,p=a?.props?.config?.elicitationEnabled??!1;if(p&&f){const s=g.get(f);if(!s)return new Response(JSON.stringify({jsonrpc:"2.0",error:{code:-32001,message:"Session not found"},id:null}),{status:404,headers:{"Content-Type":"application/json"}});const d=e.method==="POST"?await e.json():void 0;return await w(e,s,d)}if(e.method==="GET")return new Response(JSON.stringify({error:"Method Not Allowed",message:`In order to use this MCP server, you need to register it in your MCP Client (VS Code, Cursor, Claude Code, etc.) using this URL: ${e.url}`}),{status:405,headers:{"Content-Type":"application/json"}});if(e.method!=="POST")return V();const n=a,u=n?.props?.config?.apiDescriptionsMap||{},y=n?.props?.config?.graphqlDescriptions||[],D=n?.props?.config?.mcpDocsServerName||Y,{config:{mcp:T={}}}=o,b=_(u,o.user,r,t),C=z(y,o.user,r,t),E=o.config.products?Object.values(o.config.products).map(s=>s?.name):[],v=T.docs?.name||D,U=Z(e.headers.get(h)),O=n?.props?.tools||[],k=n?.props?.skillsBaseUrl||new URL(e.url).origin,I=J(n?.props?.skills||[],o.user,r,t).map(s=>({slug:s.slug,name:s.name,description:s.description,content:s.content,uri:P(k,s.slug)})),m=await e.json(),N=p&&L(m),M={name:v,tools:O,skills:I,context:{...o,accessToken:c,outdir:o.outdir||"",baseUrl:o.baseUrl||new URL(e.url).origin,apiDescriptionsMap:b,graphqlDescriptions:C,products:E,metadata:U,mcpMode:l,elicitationEnabled:p}};if(N){const s=await A({...M,sessionHooks:{onInitialized:d=>{g.set(d,s),i=void 0},onClosed:d=>{g.close(d)}}});return i=s,await w(e,s,m)}return i=await A(M),await w(e,i,m)},async()=>{i&&(await i.cleanup(),i=void 0)},l)};async function w(e,o,a){const{req:t,res:r}=H(e),l=G(r);try{await o.transport.handleRequest(t,r,a)}catch(c){throw l.stop(),c}return j(r)}var me=q;export{me as default};
1
+ import{toFetchResponse as L,toReqRes as P}from"fetch-to-node";import{isInitializeRequest as j}from"@redocly/mcp-typescript-sdk/types.js";import{logger as S}from"../../../tools/notifiers/logger.js";import{getFeedbackClientIp as H}from"../../../web-server/utils/feedback-ip.js";import{GATEWAY_FETCH_LIMIT_DEFAULTS as B}from"../../../../constants/common.js";import{isObject as J}from"../../../../utils/guards/is-object.js";import{getAccessibleSkills as K}from"../../../utils/skills/get-accessible-skills.js";import{getSkillUrl as V}from"../../../utils/skills/get-skill-url.js";import{createDocsMcpServer as T}from"../servers/docs-server.js";import{mcpSessionManager as h}from"../servers/session-manager.js";import{filterApiDescriptionsByRbac as z,filterGraphqlDescriptionsByRbac as G}from"../utils.js";import{createMethodNotAllowedError as $,withErrorHandling as Y}from"./errors.js";import{attachSseKeepalive as W}from"./sse-keepalive.js";import{constructForbiddenResponse as X,constructInvalidTokenResponse as Q,constructUnauthorizedResponse as Z,handleMcpAuth as q,shouldHandleMcpAuth as x}from"../auth/auth-handlers.js";import{extractTokenFromAuthHeader as ee}from"../utils/jwt.js";import{DEFAULT_DOCS_MCP_SERVER_NAME as oe}from"../constants.js";import{canAccessFeature as se}from"../../../utils/rbac.js";import{DEFAULT_ANONYMOUS_VISITOR_TEAM as re,RbacFeatures as ne}from"../../../../constants/common.js";const A="X-Redocly-AI-Metadata";function ie(o){if(o)try{const e=JSON.parse(o);if(J(e))return e;S.warn(`Ignoring ${A} header: not a JSON object.`)}catch{S.warn(`Ignoring ${A} header: invalid JSON.`)}}const te=async(o,e,a)=>{const i=!!e?.config?.access?.requiresLogin,r=e?.config?.access?.rbac||{},d=a?.props?.config?.mcpMode??"tools",u=a?.props?.config?.gatewayFetchBudgetPerExec??B.budgetPerExec;let m;const w=o.headers.get("Authorization");if(x(i,r)){const{isAuthenticated:l,isTokenValid:c,currentUser:n,accessToken:f}=await q(o,e);if(!l)return Z(new URL(o.url).origin);if(!c)return Q();n&&(e.user=n),m=f}else w&&(m=ee(w||"")??void 0);const E={isAuthenticated:!!e.user?.isAuthenticated,teams:e.user?.teams||[re],claims:e.user?.claims??{}};if(!se(ne.MCP,E,r,i))return X();let t;return await Y(async()=>{const l=o.headers.get("mcp-session-id")??void 0,c=a?.props?.config?.elicitationEnabled??!1;if(c&&l){const s=h.get(l);if(!s)return new Response(JSON.stringify({jsonrpc:"2.0",error:{code:-32001,message:"Session not found"},id:null}),{status:404,headers:{"Content-Type":"application/json"}});const p=o.method==="POST"?await o.json():void 0;return await R(o,s,p)}if(o.method==="GET")return new Response(JSON.stringify({error:"Method Not Allowed",message:`In order to use this MCP server, you need to register it in your MCP Client (VS Code, Cursor, Claude Code, etc.) using this URL: ${o.url}`}),{status:405,headers:{"Content-Type":"application/json"}});if(o.method!=="POST")return $();const n=a,f=n?.props?.config?.apiDescriptionsMap||{},y=n?.props?.config?.graphqlDescriptions||[],b=n?.props?.config?.mcpDocsServerName||oe,{config:{mcp:C={}}}=e,D=z(f,e.user,r,i),v=G(y,e.user,r,i),I=e.config.products?Object.values(e.config.products).map(s=>s?.name):[],U=C.docs?.name||b,O=ie(o.headers.get(A)),F=n?.props?.tools||[],N=n?.props?.skillsBaseUrl||new URL(o.url).origin,k=K(n?.props?.skills||[],e.user,r,i).map(s=>({slug:s.slug,name:s.name,description:s.description,content:s.content,uri:V(N,s.slug)})),g=await o.json(),_=c&&j(g),M={name:U,tools:F,skills:k,context:{...e,accessToken:m,outdir:e.outdir||"",baseUrl:e.baseUrl||new URL(o.url).origin,apiDescriptionsMap:D,graphqlDescriptions:v,products:I,metadata:O,mcpMode:d,elicitationEnabled:c,gatewayFetchBudgetPerExec:u,clientIp:H(o)}};if(_){const s=await T({...M,getKv:e.getKv,sessionHooks:{onInitialized:p=>{h.set(p,s),t=void 0},onClosed:p=>{h.close(p)}}});return t=s,await R(o,s,g)}return t=await T({...M,getKv:e.getKv}),await R(o,t,g)},async()=>{t&&(await t.cleanup(),t=void 0)},d)};async function R(o,e,a){const{req:i,res:r}=P(o),d=W(r);try{await e.transport.handleRequest(i,r,a)}catch(u){throw d.stop(),u}return L(r)}var Ce=te;export{Ce as default};
@@ -1 +1 @@
1
- import{telemetry as d}from"../../../telemetry/index.js";import{McpErrorCodes as s,McpServerType as n}from"../constants.js";class a extends Error{code;data;requestId;constructor(e,t,o,c){super(t),this.name="McpError",this.code=e,this.data=o,this.requestId=c}createErrorResponse(){const e={jsonrpc:"2.0",error:{code:this.code,message:this.message,...this.data?{data:this.data}:{}},id:this.requestId??null},t=i(this.code);return new Response(JSON.stringify(e),{status:t,headers:{"Content-Type":"application/json"}})}}function i(r){switch(r){case s.InvalidRequest:case s.InvalidParams:return 400;case s.MethodNotFound:return 404;case s.ServerError:return 405;case s.InternalError:default:return 500}}function E(r){return new a(s.ServerError,"Method not allowed",void 0,r).createErrorResponse()}function u(r,e,t="tools"){const o=r instanceof Error?r.message:String(r),c=r instanceof Error?r.stack:void 0;return d.sendMcpErrorMessage([{id:n.Docs,object:"mcpServer",uri:`urn:redocly:realm:mcp:server:${n.Docs}`,server_type:n.Docs,message:o,stack:c||"",mode:t}]),new a(s.InternalError,"Internal server error mcp",o,e).createErrorResponse()}function v(r="Invalid request",e){return new a(s.InvalidRequest,r,void 0,e).createErrorResponse()}function f(r="Invalid parameters",e){return new a(s.InvalidParams,r,void 0,e).createErrorResponse()}async function h(r,e,t="tools"){try{return await r()}catch(o){return d.sendMcpErrorMessage([{id:n.Docs,object:"mcpServer",uri:`urn:redocly:realm:mcp:server:${n.Docs}`,server_type:n.Docs,message:o?.message||"",stack:o?.stack||"",mode:t}]),e&&e(),u(o,void 0,t)}}export{a as McpError,u as createInternalServerError,f as createInvalidParamsError,v as createInvalidRequestError,E as createMethodNotAllowedError,h as withErrorHandling};
1
+ import{telemetry as c}from"../../../telemetry/index.js";import{McpErrorCodes as s,McpServerType as d}from"../constants.js";import{serverAttributes as i}from"../utils/telemetry-attributes.js";class n extends Error{code;data;requestId;constructor(e,t,o,a){super(t),this.name="McpError",this.code=e,this.data=o,this.requestId=a}createErrorResponse(){const e={jsonrpc:"2.0",error:{code:this.code,message:this.message,...this.data?{data:this.data}:{}},id:this.requestId??null},t=u(this.code);return new Response(JSON.stringify(e),{status:t,headers:{"Content-Type":"application/json"}})}}function u(r){switch(r){case s.InvalidRequest:case s.InvalidParams:return 400;case s.MethodNotFound:return 404;case s.ServerError:return 405;case s.InternalError:default:return 500}}function h(r){return new n(s.ServerError,"Method not allowed",void 0,r).createErrorResponse()}function p(r,e,t="tools"){const o=r instanceof Error?r.message:String(r),a=r instanceof Error?r.stack:void 0;return c.sendMcpErrorMessage([{...i(d.Docs),message:o,stack:a||"",mode:t}]),new n(s.InternalError,"Internal server error mcp",o,e).createErrorResponse()}function I(r="Invalid request",e){return new n(s.InvalidRequest,r,void 0,e).createErrorResponse()}function v(r="Invalid parameters",e){return new n(s.InvalidParams,r,void 0,e).createErrorResponse()}async function g(r,e,t="tools"){try{return await r()}catch(o){return c.sendMcpErrorMessage([{...i(d.Docs),message:o?.message||"",stack:o?.stack||"",mode:t}]),e&&e(),p(o,void 0,t)}}export{n as McpError,p as createInternalServerError,v as createInvalidParamsError,I as createInvalidRequestError,h as createMethodNotAllowedError,g as withErrorHandling};
@@ -1 +1 @@
1
- import{withPathPrefix as f}from"@redocly/theme/core/utils";import{importApiRoutesHandler as D}from"../../../api-routes/import-api-routes-handlers.js";import{enhanceContext as g}from"../../../api-routes/helpers/enhance-context.js";import{telemetry as h}from"../../../telemetry/index.js";import{KvService as A}from"../../../persistence/kv/services/kv-service.js";import{envConfig as o}from"../../../config/env-config.js";import{acceptsHtml as R}from"../../../utils/ai-agent-detection.js";import{handleErrorPageRender as E}from"../../../web-server/utils.js";import{MCP_NOT_ALLOWED_TEMPLATE_ID as T}from"../constants.js";import{MCP_DOCS_SERVER_HANDLER_ID as _}from"../index.js";import{resolvePublicBaseUrl as w}from"../../../web-server/utils/resolve-public-base-url.js";async function P(a,t,e){const s=t.req.raw;if(a.requestHandlerId===_&&s.method==="GET"&&R(s.headers.get("accept"))&&e.globalData.mcpData?.docs?.enabled)return E(t,e,{slug:a.slug},405,T);const r=t.get("auth"),n=await e.resolveRouteStaticData(a)||{},l=f(a.slug),{requestHandlers:m}=await D(e.serverOutDir),c=m[a.requestHandlerId],p=(await c()).default,d=async()=>await A.getInstance({baseDbDir:e.serverOutDir,sqldRemoteDatabaseUrl:o.SQLD_REMOTE_DATABASE_URL,sqldRemoteDatabaseAuthToken:o.SQLD_REMOTE_DATABASE_AUTH_TOKEN}),u=g({honoCtx:t,ctx:{user:{teams:r.teams,email:r.claims.email,claims:r.claims,idpAccessToken:r.idpAccessToken,idpId:r.claims.idpId,isAuthenticated:r.isAuthenticated},config:e.config,outdir:e.outdir,baseUrl:new URL(t.req.url).origin},telemetry:h,getKv:d}),i=await p(t.req.raw,u,{...n,props:{...n.props,routeSlug:l,outdir:e.outdir,skills:e.config.skills?.hide===!0?[]:e.getSkills(),skillsBaseUrl:w(e,t)}});return i instanceof Response?i:typeof i=="string"?new Response(i,{headers:{"Content-Type":"text/plain"}}):new Response(JSON.stringify(i),{headers:{"Content-Type":"application/json"}})}export{P as handleMcpRequest};
1
+ import{withPathPrefix as g}from"@redocly/theme/core/utils";import{importApiRoutesHandler as D}from"../../../api-routes/import-api-routes-handlers.js";import{enhanceContext as h}from"../../../api-routes/helpers/enhance-context.js";import{telemetry as R}from"../../../telemetry/index.js";import{KvService as A}from"../../../persistence/kv/services/kv-service.js";import{envConfig as l}from"../../../config/env-config.js";import{acceptsHtml as E}from"../../../utils/ai-agent-detection.js";import{handleErrorPageRender as T}from"../../../web-server/utils.js";import{MCP_NOT_ALLOWED_TEMPLATE_ID as _}from"../constants.js";import{MCP_DOCS_SERVER_HANDLER_ID as w}from"../index.js";import{resolvePublicBaseUrl as S}from"../../../web-server/utils/resolve-public-base-url.js";import{applyEdgeRateLimit as q}from"../gateway-mcp/rate-limit/apply-edge-rate-limit.js";async function B(a,t,e){const n=t.req.raw;if(a.requestHandlerId===w&&n.method==="GET"&&E(n.headers.get("accept"))&&e.globalData.mcpData?.docs?.enabled)return T(t,e,{slug:a.slug},405,_);const r=t.get("auth"),s=await q(n,e);if(s)return s;const o=await e.resolveRouteStaticData(a)||{},m=g(a.slug),{requestHandlers:c}=await D(e.serverOutDir),p=c[a.requestHandlerId],d=(await p()).default,u=async()=>await A.getInstance({baseDbDir:e.serverOutDir,sqldRemoteDatabaseUrl:l.SQLD_REMOTE_DATABASE_URL,sqldRemoteDatabaseAuthToken:l.SQLD_REMOTE_DATABASE_AUTH_TOKEN}),f=h({honoCtx:t,ctx:{user:{teams:r.teams,email:r.claims.email,claims:r.claims,idpAccessToken:r.idpAccessToken,idpId:r.claims.idpId,isAuthenticated:r.isAuthenticated},config:e.config,outdir:e.outdir,baseUrl:new URL(t.req.url).origin},telemetry:R,getKv:u}),i=await d(t.req.raw,f,{...o,props:{...o.props,routeSlug:m,outdir:e.outdir,skills:e.config.skills?.hide===!0?[]:e.getSkills(),skillsBaseUrl:S(e,t)}});return i instanceof Response?i:typeof i=="string"?new Response(i,{headers:{"Content-Type":"text/plain"}}):new Response(JSON.stringify(i),{headers:{"Content-Type":"application/json"}})}export{B as handleMcpRequest};
@@ -1,4 +1,4 @@
1
- import{secretStore as d}from"../gateway-mcp/secret-store.js";import{buildAllowedHostMatchers as C}from"../gateway-mcp/fetch/allowed-hosts.js";import{assertUrlAllowed as P}from"../gateway-mcp/fetch/ssrf-guard.js";import{readCappedBody as $,ssrfSafeAgent as I}from"../gateway-mcp/fetch/fetch-bridge.js";const p={"Content-Type":"text/html; charset=utf-8","Cache-Control":"no-store","X-Frame-Options":"DENY","Referrer-Policy":"no-referrer","Content-Security-Policy":"default-src 'none'; style-src 'unsafe-inline'; form-action 'self'"},_=3e4,E=64*1024;let v=fetch;function j(e){v=e}const T=async e=>{if(e.method==="GET"){const t=new URL(e.url).searchParams.get("token")??"",n=d.peekElicitation(t);return n?new Response(B(n,t),{status:200,headers:p}):l()}if(e.method==="POST"){const t=await e.formData(),n=String(t.get("token")??"");return String(t.get("mode")??"token")==="client-credentials"?R(t,n):z(t,n)}return new Response("Method Not Allowed",{status:405,headers:{Allow:"GET, POST"}})};async function z(e,t){const n=String(e.get("secret")??"");if(!n)return l();const o=d.consumeElicitation(t);return o?(d.setSecret(o.sessionId,o.api,F(o.auth,n)),new Response(w(o.name),{status:200,headers:p})):l()}async function R(e,t){const n=String(e.get("client_id")??"").trim(),o=String(e.get("client_secret")??"").trim();if(!n||!o)return l();const y=d.peekElicitation(t);if(!y||y.auth.kind!=="oauth2ClientCredentials")return l();const r=d.consumeElicitation(t);if(!r||r.auth.kind!=="oauth2ClientCredentials")return l();const h=r.auth;try{const x=C([{url:h.tokenUrl}]),A=P(h.tokenUrl,x),g=new AbortController,S=setTimeout(()=>g.abort(),_);let f;try{f=await v(A,{method:"POST",headers:{"content-type":"application/x-www-form-urlencoded"},body:new URLSearchParams({grant_type:"client_credentials",client_id:n,client_secret:o,...h.scopes.length>0?{scope:h.scopes.join(" ")}:{}}),redirect:"manual",signal:g.signal,dispatcher:I})}finally{clearTimeout(S)}if(!f.ok)return m(r.name);let k;try{k=await $(f,E)}catch{return m(r.name)}let u;try{u=JSON.parse(k)}catch{return m(r.name)}const b=typeof u=="object"&&u!==null&&"access_token"in u?u.access_token:void 0;return typeof b!="string"||!b?m(r.name):(d.setSecret(r.sessionId,r.api,{header:"Authorization",value:`Bearer ${b}`}),new Response(w(r.name),{status:200,headers:p}))}catch{return m(r.name)}}function F(e,t){return e.kind==="apiKey"?{header:e.header,value:t}:e.kind==="bearer"||e.kind==="oauth2ClientCredentials"?{header:"Authorization",value:O(t)}:{header:"Authorization",value:t}}function O(e){const t=e.trim();return t.toLowerCase().startsWith("bearer")?t:`Bearer ${t}`}function a(e){return e.replaceAll("&","&amp;").replaceAll("<","&lt;").replaceAll(">","&gt;").replaceAll('"',"&quot;")}function i(e){return`<!doctype html>
1
+ import{secretStore as l}from"../gateway-mcp/secret-store.js";import{buildAllowedHostMatchers as C}from"../gateway-mcp/fetch/allowed-hosts.js";import{assertUrlAllowed as P}from"../gateway-mcp/fetch/ssrf-guard.js";import{readCappedBody as I,getDefaultAgent as _}from"../gateway-mcp/fetch/fetch-bridge.js";const m={"Content-Type":"text/html; charset=utf-8","Cache-Control":"no-store","X-Frame-Options":"DENY","Referrer-Policy":"no-referrer","Content-Security-Policy":"default-src 'none'; style-src 'unsafe-inline'; form-action 'self'"},E=3e4,T=64*1024;let v=fetch;function L(e){v=e}const z=async(e,t)=>{const o=await t.getKv();if(e.method==="GET"){const n=new URL(e.url).searchParams.get("token")??"",r=await l.peekElicitation(o,n);return r?new Response(q(r,n),{status:200,headers:m}):u()}if(e.method==="POST"){const n=await e.formData(),r=String(n.get("token")??"");return String(n.get("mode")??"token")==="client-credentials"?F(o,n,r):R(o,n,r)}return new Response("Method Not Allowed",{status:405,headers:{Allow:"GET, POST"}})};async function R(e,t,o){const n=String(t.get("secret")??"");if(!n)return u();const r=await l.consumeElicitation(e,o);return r?(await l.setSecret(e,r.subject,r.api,O(r.auth,n)),new Response(x(r.name),{status:200,headers:m})):u()}async function F(e,t,o){const n=String(t.get("client_id")??"").trim(),r=String(t.get("client_secret")??"").trim();if(!n||!r)return u();const b=await l.peekElicitation(e,o);if(!b||b.auth.kind!=="oauth2ClientCredentials")return u();const a=await l.consumeElicitation(e,o);if(!a||a.auth.kind!=="oauth2ClientCredentials")return u();const f=a.auth;try{const A=C([{url:f.tokenUrl}]),S=P(f.tokenUrl,A),w=new AbortController,$=setTimeout(()=>w.abort(),E);let y;try{y=await v(S,{method:"POST",headers:{"content-type":"application/x-www-form-urlencoded"},body:new URLSearchParams({grant_type:"client_credentials",client_id:n,client_secret:r,...f.scopes.length>0?{scope:f.scopes.join(" ")}:{}}),redirect:"manual",signal:w.signal,dispatcher:_()})}finally{clearTimeout($)}if(!y.ok)return h(a.name);let k;try{k=await I(y,T)}catch{return h(a.name)}let p;try{p=JSON.parse(k)}catch{return h(a.name)}const g=typeof p=="object"&&p!==null&&"access_token"in p?p.access_token:void 0;return typeof g!="string"||!g?h(a.name):(await l.setSecret(e,a.subject,a.api,{header:"Authorization",value:`Bearer ${g}`}),new Response(x(a.name),{status:200,headers:m}))}catch{return h(a.name)}}function O(e,t){return e.kind==="apiKey"?{header:e.header,value:t}:e.kind==="bearer"||e.kind==="oauth2ClientCredentials"?{header:"Authorization",value:B(t)}:{header:"Authorization",value:t}}function B(e){const t=e.trim();return t.toLowerCase().startsWith("bearer")?t:`Bearer ${t}`}function i(e){return e.replaceAll("&","&amp;").replaceAll("<","&lt;").replaceAll(">","&gt;").replaceAll('"',"&quot;")}function s(e){return`<!doctype html>
2
2
  <html lang="en">
3
3
  <head>
4
4
  <meta charset="utf-8">
@@ -34,34 +34,34 @@ footer{border-top-color:#1f2937;color:#6b7280}
34
34
  </style>
35
35
  </head>
36
36
  <body><div class="card">${e}</div></body>
37
- </html>`}function s(e){return`<h1>\u{1F512} ${a(e)}</h1>`}function c(){return"<footer>Secured by Redocly &middot; credentials never enter the AI conversation</footer>"}function B(e,t){switch(e.auth.kind){case"bearer":return M(e.name,t);case"apiKey":return q(e.name,t,e.auth.header);case"oauth2ClientCredentials":return H(e.name,t,e.auth.scopes);default:return N(e.name,t)}}function M(e,t){return i(`
38
- ${s(`Credentials for ${e}`)}
39
- <p class="hint">Stored encrypted for this MCP session only (up to 4 hours) and sent to the API as the <code>Authorization</code> header. It never passes through the AI conversation.</p>
37
+ </html>`}function c(e){return`<h1>\u{1F512} ${i(e)}</h1>`}function d(){return"<footer>Secured by Redocly &middot; credentials never enter the AI conversation</footer>"}function q(e,t){switch(e.auth.kind){case"bearer":return H(e.name,t);case"apiKey":return N(e.name,t,e.auth.header);case"oauth2ClientCredentials":return U(e.name,t,e.auth.scopes);default:return j(e.name,t)}}function H(e,t){return s(`
38
+ ${c(`Credentials for ${e}`)}
39
+ <p class="hint">Stored encrypted for you only (24 hours for anonymous callers, 30 days when signed in) and sent to the API as the <code>Authorization</code> header. It never passes through the AI conversation.</p>
40
40
  <form method="post" action="/mcp/credentials" autocomplete="off">
41
- <input type="hidden" name="token" value="${a(t)}">
41
+ <input type="hidden" name="token" value="${i(t)}">
42
42
  <input type="hidden" name="mode" value="token">
43
43
  <label for="secret">API token</label>
44
44
  <input type="password" id="secret" name="secret" placeholder="your API token" required autofocus>
45
45
  <p class="hint">Paste the raw token or one already prefixed with <code>Bearer</code> &mdash; we add the prefix automatically if it is missing.</p>
46
46
  <button type="submit">Save credentials</button>
47
47
  </form>
48
- ${c()}`)}function q(e,t,n){return i(`
49
- ${s(`Credentials for ${e}`)}
50
- <p class="hint">Stored encrypted for this MCP session only (up to 4 hours) and sent to the API as the <code>${a(n)}</code> header. It never passes through the AI conversation.</p>
48
+ ${d()}`)}function N(e,t,o){return s(`
49
+ ${c(`Credentials for ${e}`)}
50
+ <p class="hint">Stored encrypted for you only (24 hours for anonymous callers, 30 days when signed in) and sent to the API as the <code>${i(o)}</code> header. It never passes through the AI conversation.</p>
51
51
  <form method="post" action="/mcp/credentials" autocomplete="off">
52
- <input type="hidden" name="token" value="${a(t)}">
52
+ <input type="hidden" name="token" value="${i(t)}">
53
53
  <input type="hidden" name="mode" value="token">
54
- <label for="secret">${a(n)} value</label>
54
+ <label for="secret">${i(o)} value</label>
55
55
  <input type="password" id="secret" name="secret" placeholder="value" required autofocus>
56
56
  <button type="submit">Save credentials</button>
57
57
  </form>
58
- ${c()}`)}function H(e,t,n){const o=n.length>0?n.map(a).join(", "):"default scopes";return i(`
59
- ${s(`Credentials for ${e}`)}
58
+ ${d()}`)}function U(e,t,o){const n=o.length>0?o.map(i).join(", "):"default scopes";return s(`
59
+ ${c(`Credentials for ${e}`)}
60
60
  <p class="hint">Paste a token you already have, or let us exchange client credentials for one via OAuth2 client_credentials.</p>
61
61
  <div class="section">
62
62
  <h2>I have a token</h2>
63
63
  <form method="post" action="/mcp/credentials" autocomplete="off">
64
- <input type="hidden" name="token" value="${a(t)}">
64
+ <input type="hidden" name="token" value="${i(t)}">
65
65
  <input type="hidden" name="mode" value="token">
66
66
  <label for="secret">API token</label>
67
67
  <input type="password" id="secret" name="secret" placeholder="your API token" required autofocus>
@@ -71,9 +71,9 @@ ${s(`Credentials for ${e}`)}
71
71
  </div>
72
72
  <div class="section">
73
73
  <h2>Exchange client credentials</h2>
74
- <p class="hint">We request a token from the API on your behalf. Scopes: ${o}.</p>
74
+ <p class="hint">We request a token from the API on your behalf. Scopes: ${n}.</p>
75
75
  <form method="post" action="/mcp/credentials" autocomplete="off">
76
- <input type="hidden" name="token" value="${a(t)}">
76
+ <input type="hidden" name="token" value="${i(t)}">
77
77
  <input type="hidden" name="mode" value="client-credentials">
78
78
  <label for="client_id">Client ID</label>
79
79
  <input type="text" id="client_id" name="client_id" required>
@@ -82,20 +82,20 @@ ${s(`Credentials for ${e}`)}
82
82
  <button type="submit">Exchange &amp; save</button>
83
83
  </form>
84
84
  </div>
85
- ${c()}`)}function N(e,t){return i(`
86
- ${s(`Credentials for ${e}`)}
87
- <p class="hint">The value is stored encrypted for this MCP session only (up to 4 hours) and is sent to the API as the <code>Authorization</code> header. It never passes through the AI conversation.</p>
85
+ ${d()}`)}function j(e,t){return s(`
86
+ ${c(`Credentials for ${e}`)}
87
+ <p class="hint">The value is stored encrypted for you only (24 hours for anonymous callers, 30 days when signed in) and is sent to the API as the <code>Authorization</code> header. It never passes through the AI conversation.</p>
88
88
  <form method="post" action="/mcp/credentials" autocomplete="off">
89
- <input type="hidden" name="token" value="${a(t)}">
89
+ <input type="hidden" name="token" value="${i(t)}">
90
90
  <input type="hidden" name="mode" value="token">
91
91
  <label for="secret">Authorization header value</label>
92
92
  <input type="password" id="secret" name="secret" placeholder="Bearer &lt;your token&gt;" required autofocus>
93
93
  <button type="submit">Save credentials</button>
94
94
  </form>
95
- ${c()}`)}function w(e){return i(`
96
- ${s("Credentials saved")}
97
- <p>Credentials for ${a(e)} are set for this session. Return to your AI client and continue - confirm the elicitation prompt if it is still open.</p>
98
- ${c()}`)}function m(e){return new Response(i(`
99
- ${s("Exchange failed")}
100
- <p>We could not exchange your client credentials for a token for ${a(e)}. This link has been used up - go back to your AI client and request a new link, then try again.</p>
101
- ${c()}`),{status:502,headers:p})}function l(){return new Response(i(`${s("Link expired")}<p>This credentials link is invalid or has expired. Retry the request in your AI client to get a fresh link.</p>${c()}`),{status:404,headers:p})}var D=T;export{D as default,j as setCredentialsFetchImpl};
95
+ ${d()}`)}function x(e){return s(`
96
+ ${c("Credentials saved")}
97
+ <p>Credentials for ${i(e)} are set for this session. Return to your AI client and continue - confirm the elicitation prompt if it is still open.</p>
98
+ ${d()}`)}function h(e){return new Response(s(`
99
+ ${c("Exchange failed")}
100
+ <p>We could not exchange your client credentials for a token for ${i(e)}. This link has been used up - go back to your AI client and request a new link, then try again.</p>
101
+ ${d()}`),{status:502,headers:m})}function u(){return new Response(s(`${c("Link expired")}<p>This credentials link is invalid or has expired. Retry the request in your AI client to get a fresh link.</p>${d()}`),{status:404,headers:m})}var W=z;export{W as default,L as setCredentialsFetchImpl};
@@ -1 +1 @@
1
- import{fileURLToPath as L}from"node:url";import{dirname as q,join as c}from"node:path";import{logger as m}from"../../tools/notifiers/logger.js";import{reporter as w}from"../../tools/notifiers/reporter.js";import{isDefined as N}from"../../../utils/guards/is-defined.js";import{buildGraphqlDescriptions as G,filterIgnoredApiDescriptions as D,getCleanedUpApiDescriptions as H,isMcpInRedirects as I}from"./utils.js";import{getMcpMode as U,isMcpElicitationEnabled as j}from"./utils/mode.js";import{getDefaultToolSchemas as x}from"./docs-mcp/tool-schemas.js";import{EXECUTE_TOOL_SCHEMA as F}from"./codemode/tools/execute-schema.js";import{isGatewayCapabilityEnabled as V,isGatewayEligible as B}from"./gateway-mcp/eligibility.js";import{telemetryTraceStep as J}from"../../../cli/telemetry/helpers/trace-step.js";import{DEFAULT_DOCS_MCP_SERVER_NAME as E,MCP_NOT_ALLOWED_TEMPLATE_ID as W}from"./constants.js";const M="mcp-docs-server-handler",X="/mcp",C="mcp-credentials-handler",k="/mcp/credentials",p=q(L(import.meta.url));async function z(){let o=!1;return{id:"mcp",async processContent(i,r){o||await J("build.plugin.mcp",async a=>{const s=await i.loadOpenApiDefinitions(r),d=await i.loadGraphqlDefinitions(r),n=await r.getConfig(),{mcp:t,redirects:l}=n;if(a?.setAttribute("config",JSON.stringify(t||{})),!(t?.hide||t?.docs?.hide)&&(I(l)&&await w.panicOnBuildContentError('The reserved route "/mcp" cannot be used in redirect configuration. Please remove any redirects involving "/mcp" from your redocly.yaml config.'),i.createTemplate(W,"@redocly/theme/layouts/McpNotAllowed"),!t?.docs?.hide)){m.info("Configuring MCP servers...");const _=c(p,"./handlers/docs-mcp-handler.js"),P=H(D(s,t?.docs?.ignore||[])),v=!!n?.access?.requiresLogin,f=n?.access?.rbac||{},R=V(t),g=new Map;for(const e of P){const b=e.definition.info?.title||"",O=e.definition.info?.version||"";g.set(e.relativePath,{name:b,description:e.definition.info?.description||"",version:O,servers:e.definition.servers||[],relativePath:e.relativePath,...R&&B(e.definition.info,e.relativePath,f)?{fetchEligible:!0}:{}})}const u=G(D(d,t?.docs?.ignore||[])),S=Object.values(n.products||{}).map(e=>e?.name).filter(N),y=n.l10n?.locales?.map(e=>e.code)??r.fs.localeFolders,A=x({products:S,locales:y,requiresLogin:v,rbac:f,hasGraphqlApis:u.length>0});i.addMcpTools(c(p,"./docs-mcp/tools/index.js"),A);const h=U(),T=j();h==="code"&&i.addMcpTools(c(p,"./codemode/tools/execute.js"),[F]),await K({actions:i,handlerPath:_,apiDescriptionsMap:Object.fromEntries(g),graphqlDescriptions:u,mcpConfig:t,mcpMode:h,elicitationEnabled:T}),o=!0}})},async afterRoutesCreated(i,r){const a=await r.getConfig(),{mcp:s}=a;i.setGlobalData({mcpData:{docs:{enabled:!s?.hide&&!s?.docs?.hide,name:s?.docs?.name||E}}})}}}var ce=z;async function K({actions:o,handlerPath:i,apiDescriptionsMap:r,graphqlDescriptions:a,mcpConfig:s,mcpMode:d,elicitationEnabled:n}){if(o.createRequestHandler(M,i),o.addApiRoute({slug:X,requestHandlerId:M,httpMethod:"all",getStaticData:async()=>({props:{config:{apiDescriptionsMap:r,graphqlDescriptions:a,mcpDocsServerName:s?.docs?.name||E,mcpMode:d,elicitationEnabled:n},serverOutDir:o.serverOutDir,tools:o.getMcpTools().map(({importPath:t,...l})=>l)}})}),m.info("Registered Docs MCP Server endpoint at /mcp"),n){const t=c(p,"./handlers/mcp-credentials-handler.js");o.createRequestHandler(C,t),o.addApiRoute({slug:k,requestHandlerId:C,httpMethod:"all",getStaticData:async()=>({props:{}})}),m.info("Registered MCP credentials endpoint at /mcp/credentials")}}export{C as MCP_CREDENTIALS_HANDLER_ID,M as MCP_DOCS_SERVER_HANDLER_ID,ce as default,z as mcpServerPlugin};
1
+ import{fileURLToPath as w}from"node:url";import{dirname as q,join as p}from"node:path";import{logger as f}from"../../tools/notifiers/logger.js";import{reporter as G}from"../../tools/notifiers/reporter.js";import{isDefined as N}from"../../../utils/guards/is-defined.js";import{bundledOpenApiDocumentsToMcpOpenApi as H,bundledGraphqlDocumentsToMcpOpenApi as I,buildGraphqlDescriptions as U,filterIgnoredApiDescriptions as M,getCleanedUpApiDescriptions as j,isMcpInRedirects as x}from"./utils.js";import{getMcpMode as F,isMcpElicitationEnabled as B}from"./utils/mode.js";import{getDefaultToolSchemas as V}from"./docs-mcp/tool-schemas.js";import{EXECUTE_TOOL_SCHEMA as J}from"./codemode/tools/execute-schema.js";import{isGatewayCapabilityEnabled as W,isGatewayEligible as X}from"./gateway-mcp/eligibility.js";import{resolveGatewayFetchLimits as k}from"./gateway-mcp/rate-limit/limits.js";import{telemetryTraceStep as z}from"../../../cli/telemetry/helpers/trace-step.js";import{DEFAULT_DOCS_MCP_SERVER_NAME as C,MCP_NOT_ALLOWED_TEMPLATE_ID as K}from"./constants.js";const P="mcp-docs-server-handler",Q="/mcp",_="mcp-credentials-handler",Y="/mcp/credentials",d=q(w(import.meta.url));async function Z(){let i=!1;return{id:"mcp",async processContent(t,r){i||await z("com.redocly.build.plugin.mcp",async c=>{const s=H(await t.loadApiDocuments(r)),l=I(await t.loadApiDocuments(r)),n=await r.getConfig(),{mcp:o,redirects:a}=n;if(c?.setAttribute("config",JSON.stringify(o||{})),!(o?.hide||o?.docs?.hide)&&(x(a)&&await G.panicOnBuildContentError('The reserved route "/mcp" cannot be used in redirect configuration. Please remove any redirects involving "/mcp" from your redocly.yaml config.'),t.createTemplate(K,"@redocly/theme/layouts/McpNotAllowed"),!o?.docs?.hide)){f.info("Configuring MCP servers...");const m=p(d,"./handlers/docs-mcp-handler.js"),y=j(M(s,o?.docs?.ignore||[])),v=!!n?.access?.requiresLogin,u=n?.access?.rbac||{},A=W(o),g=new Map;for(const e of y){const O=e.definition.info?.title||"",L=e.definition.info?.version||"";g.set(e.relativePath,{name:O,description:typeof e.definition.info?.description=="string"?e.definition.info.description:"",version:L,servers:e.definition.servers||[],relativePath:e.relativePath,...A&&X(e.definition.info,e.relativePath,u)?{fetchEligible:!0}:{}})}const h=U(M(l,o?.docs?.ignore||[])),b=Object.values(n.products||{}).map(e=>e?.name).filter(N),R=n.l10n?.locales?.map(e=>e.code)??r.fs.localeFolders,D=F(),E=B(),{budgetPerExec:S}=k(),T=V({products:b,locales:R,requiresLogin:v,rbac:u,hasGraphqlApis:h.length>0,elicitationEnabled:E});t.addMcpTools(p(d,"./docs-mcp/tools/index.js"),T),D==="code"&&t.addMcpTools(p(d,"./codemode/tools/execute.js"),[J]),await $({actions:t,handlerPath:m,apiDescriptionsMap:Object.fromEntries(g),graphqlDescriptions:h,mcpConfig:o,mcpMode:D,elicitationEnabled:E,gatewayFetchBudgetPerExec:S}),i=!0}})},async afterRoutesCreated(t,r){const c=await r.getConfig(),{mcp:s}=c;t.setGlobalData({mcpData:{docs:{enabled:!s?.hide&&!s?.docs?.hide,name:s?.docs?.name||C}}})}}}var fe=Z;async function $({actions:i,handlerPath:t,apiDescriptionsMap:r,graphqlDescriptions:c,mcpConfig:s,mcpMode:l,elicitationEnabled:n,gatewayFetchBudgetPerExec:o}){if(i.createRequestHandler(P,t),i.addApiRoute({slug:Q,requestHandlerId:P,httpMethod:"all",getStaticData:async()=>({props:{config:{apiDescriptionsMap:r,graphqlDescriptions:c,mcpDocsServerName:s?.docs?.name||C,mcpMode:l,elicitationEnabled:n,gatewayFetchBudgetPerExec:o},serverOutDir:i.serverOutDir,tools:i.getMcpTools().map(({importPath:a,...m})=>m)}})}),f.info("Registered Docs MCP Server endpoint at /mcp"),n){const a=p(d,"./handlers/mcp-credentials-handler.js");i.createRequestHandler(_,a),i.addApiRoute({slug:Y,requestHandlerId:_,httpMethod:"all",getStaticData:async()=>({props:{}})}),f.info("Registered MCP credentials endpoint at /mcp/credentials")}}export{_ as MCP_CREDENTIALS_HANDLER_ID,P as MCP_DOCS_SERVER_HANDLER_ID,fe as default,Z as mcpServerPlugin};
@@ -1,11 +1,13 @@
1
1
  import type { McpToolSchema } from '../../../types';
2
2
  import type { McpToolContext, SkillMcpResource } from '../types.js';
3
+ import type { KvService } from '@redocly/config';
3
4
  import { type McpServerInstance, type McpSessionHooks } from './mcp-server.js';
4
- export declare function createDocsMcpServer({ name, tools, context, sessionHooks, skills, }: {
5
+ export declare function createDocsMcpServer({ name, tools, context, sessionHooks, skills, getKv, }: {
5
6
  name: string;
6
7
  tools: McpToolSchema[];
7
8
  context: McpToolContext;
8
9
  sessionHooks?: McpSessionHooks;
9
10
  skills?: SkillMcpResource[];
11
+ getKv: () => Promise<KvService>;
10
12
  }): Promise<McpServerInstance>;
11
13
  //# sourceMappingURL=docs-server.d.ts.map
@@ -1 +1 @@
1
- import{logger as O}from"../../../tools/notifiers/logger.js";import{mcpToolWorkers as _,MCP_TOOL_IS_AVAILABLE_KEY as u}from"../../../workers/mcp-tool-worker-pool.js";import{EXECUTE_TOOL_SCHEMA as b}from"../codemode/tools/execute-schema.js";import{EXECUTE_TOOL_NAME as p,DESCRIBE_TOOLS_TOOL_NAME as M,CODE_MODE_TOOL_NAMES as S,FETCH_TOOL_NAME as A}from"../codemode/constants.js";import{buildCodeModeInstructions as h,buildExecuteDescription as L,DESCRIBE_TOOLS_DESCRIPTION as g}from"../codemode/prompts.js";import{composeExecuteAnnotations as v,getActiveCapabilities as x}from"../codemode/capabilities/index.js";import{describeToolsSchema as D,describeTools as y}from"../codemode/tools/describe-tools.js";import{connectMcpServer as I,createMcpServer as k,createToolDispatch as w,extractSerializableContext as N}from"./mcp-server.js";async function $({name:E,tools:n,context:o,sessionHooks:d,skills:T=[]}){const a=o.mcpMode==="code",r=a?x(o):[],s=r.some(e=>e.id===A),{server:i,transport:f}=k(E,a?h(s):void 0,d),c=N(o),m=w(c,{getClientCapabilities:()=>i.server.getClientCapabilities()}),l=async e=>{try{return await _.exec(u,[{toolName:e,context:c}],{timeout:1e4})}catch(t){return O.error(`Failed to check MCP tool availability for "${e}": ${t instanceof Error?t.message:String(t)}`),!1}};if(a){const e=n.filter(t=>!S.has(t.name));i.tool(p,L(s),b.schema,v(r),m(p)),i.tool(M,g,D(e,r),y(e,l,r,o))}else await Promise.all(n.map(async e=>{const t=e.annotations||{title:e.name},C=i.tool(e.name,e.description,e.schema,t,m(e.name));await l(e.name)||C.disable()}));for(const e of T)i.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 I(i,f)}export{$ as createDocsMcpServer};
1
+ import{logger as C}from"../../../tools/notifiers/logger.js";import{mcpToolWorkers as S,MCP_TOOL_IS_AVAILABLE_KEY as b}from"../../../workers/mcp-tool-worker-pool.js";import{CREATE_ANONYMOUS_SESSION_TOOL_NAME as A}from"../constants.js";import{isAnonymousSessionToolAvailable as f}from"../docs-mcp/tools/core/create-anonymous-session.js";import{EXECUTE_TOOL_SCHEMA as M}from"../codemode/tools/execute-schema.js";import{EXECUTE_TOOL_NAME as O,DESCRIBE_TOOLS_TOOL_NAME as h,CODE_MODE_TOOL_NAMES as L,FETCH_TOOL_NAME as v}from"../codemode/constants.js";import{buildCodeModeInstructions as g,buildExecuteDescription as y,DESCRIBE_TOOLS_DESCRIPTION as D}from"../codemode/prompts.js";import{composeExecuteAnnotations as x,getActiveCapabilities as I}from"../codemode/capabilities/index.js";import{describeToolsSchema as N,describeTools as k}from"../codemode/tools/describe-tools.js";import{connectMcpServer as w,createMcpServer as R,createToolDispatch as F,extractSerializableContext as H}from"./mcp-server.js";function P(a){const t=M.schema;if(f(a))return t;const{sessionHandle:i,...c}=t.properties;return{...t,properties:c}}async function q({name:a,tools:t,context:i,sessionHooks:c,skills:T=[],getKv:_}){const m=i.mcpMode==="code",s=m?I(i):[],p=s.some(e=>e.id===v),{server:r,transport:u}=R(a,m?g(p):void 0,c),E=H(i),l=F(E,{getClientCapabilities:()=>r.server.getClientCapabilities(),getKv:_}),d=async e=>{try{return await S.exec(b,[{toolName:e,context:E}],{timeout:1e4})}catch(o){return C.error(`Failed to check MCP tool availability for "${e}": ${o instanceof Error?o.message:String(o)}`),!1}};if(m){const e=t.filter(n=>!L.has(n.name));r.tool(O,y(p),P(i),x(s),l(O)),r.tool(h,D,N(e,s),k(e,d,s,i));const o=t.find(n=>n.name===A);o&&f(i)&&r.tool(o.name,o.description,o.schema,o.annotations??{title:o.name},l(o.name))}else await Promise.all(t.map(async e=>{const o=e.annotations||{title:e.name},n=r.tool(e.name,e.description,e.schema,o,l(e.name));await d(e.name)||n.disable()}));for(const e of T)r.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 w(r,u)}export{q as createDocsMcpServer};
@@ -2,6 +2,7 @@ import { McpServer } from '@redocly/mcp-typescript-sdk/server/mcp.js';
2
2
  import { StreamableHTTPServerTransport } from '@redocly/mcp-typescript-sdk/server/streamableHttp.js';
3
3
  import type { ToolCallback } from '@redocly/mcp-typescript-sdk/server/mcp.js';
4
4
  import type { McpToolContext } from '../types.js';
5
+ import type { KvService } from '@redocly/config';
5
6
  export type McpServerInstance = {
6
7
  server: McpServer;
7
8
  transport: StreamableHTTPServerTransport;
@@ -20,6 +21,7 @@ export type ToolDispatchDeps = {
20
21
  getClientCapabilities: () => {
21
22
  elicitation?: unknown;
22
23
  } | undefined;
24
+ getKv: () => Promise<KvService>;
23
25
  };
24
26
  /** Build the tool callback that ships a tool call to the worker pool. */
25
27
  export declare function createToolDispatch(serializableContext: McpToolContext, deps?: ToolDispatchDeps): (toolName: string) => ToolCallback<Record<string, unknown>>;
@@ -1 +1 @@
1
- import{randomUUID as I}from"node:crypto";import{McpServer as S}from"@redocly/mcp-typescript-sdk/server/mcp.js";import{StreamableHTTPServerTransport as g}from"@redocly/mcp-typescript-sdk/server/streamableHttp.js";import{logger as M}from"../../../tools/notifiers/logger.js";import{mcpToolWorkers as h,MCP_TOOL_WORKER_KEY as q}from"../../../workers/mcp-tool-worker-pool.js";import{secretStore as E}from"../gateway-mcp/secret-store.js";import{readAuthRequiredMeta as T,stripAuthRequiredMeta as b}from"../gateway-mcp/upstream-auth.js";import{runUpstreamCredentialElicitation as w}from"../gateway-mcp/elicitation.js";import{resolveUpstreamAuthScheme as U}from"../gateway-mcp/upstream-auth-scheme.js";const v=6e4,p=new Map;function D(e,t){const i=p.get(e);if(i)return i;const r=t().finally(()=>{p.delete(e)});return p.set(e,r),r}function G(e,t,i){const r=new S({name:e,version:new Date().toISOString().slice(0,10)},{capabilities:{logging:{}},...t?{instructions:t}:{}}),s=new g(i?{sessionIdGenerator:()=>I(),onsessioninitialized:i.onInitialized,onsessionclosed:i.onClosed}:{sessionIdGenerator:void 0});return{server:r,transport:s}}async function K(e,t){return await e.connect(t),{server:e,transport:t,cleanup:async()=>{t.close()}}}function L(e,t){return i=>async(r,s)=>{M.info(`MCP tool called: ${i}`);const l=async()=>{const a=e.elicitationEnabled&&s.sessionId?E.getSecretsForSession(s.sessionId):void 0,c={toolName:i,args:r,context:{...e,upstreamSecrets:a},extra:O(s)};return await h.exec(q,[c],{timeout:v})};let n=await l();const o=T(n);if(o.length>0&&e.elicitationEnabled&&s.sessionId){const a=s.sessionId,c=await U(e,o[0].api),u=await D(`${a}:${o[0].api}`,()=>w({sendRequest:(d,m,f)=>s.sendRequest(d,m,f),clientSupportsElicitation:!!t?.getClientCapabilities()?.elicitation,sessionId:a,baseUrl:e.baseUrl??"",events:o,auth:c}));u.status==="accepted"?n=await l():u.status==="fallback"&&(n={...n,content:[...n.content,{type:"text",text:u.text}]})}return b(n)}}function O(e){return{sessionId:e.sessionId,authInfo:e.authInfo,requestId:e.requestId,requestInfo:e.requestInfo,_meta:e._meta}}function W(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,upstreamSecrets:e.upstreamSecrets}}export{K as connectMcpServer,G as createMcpServer,L as createToolDispatch,W as extractSerializableContext};
1
+ import{randomUUID as w}from"node:crypto";import{McpServer as v}from"@redocly/mcp-typescript-sdk/server/mcp.js";import{StreamableHTTPServerTransport as M}from"@redocly/mcp-typescript-sdk/server/streamableHttp.js";import{logger as f}from"../../../tools/notifiers/logger.js";import{mcpToolWorkers as y,MCP_TOOL_WORKER_KEY as b}from"../../../workers/mcp-tool-worker-pool.js";import{secretStore as q}from"../gateway-mcp/secret-store.js";import{readAuthRequiredMeta as T,stripAuthRequiredMeta as S}from"../gateway-mcp/upstream-auth.js";import{runUpstreamCredentialElicitation as U}from"../gateway-mcp/elicitation.js";import{resolveUpstreamAuthScheme as _}from"../gateway-mcp/upstream-auth-scheme.js";import{MISSING_SESSION_HANDLE_MESSAGE as D,resolveSecretSubject as O}from"../gateway-mcp/subject.js";const k=6e4,d=new Map;function A(e,t){const r=d.get(e);if(r)return r;const i=t().finally(()=>{d.delete(e)});return d.set(e,i),i}function H(e,t,r){const i=new v({name:e,version:new Date().toISOString().slice(0,10)},{capabilities:{logging:{}},...t?{instructions:t}:{}}),c=new M(r?{sessionIdGenerator:()=>w(),onsessioninitialized:r.onInitialized,onsessionclosed:r.onClosed}:{sessionIdGenerator:void 0});return{server:i,transport:c}}async function Y(e,t){return await e.connect(t),{server:e,transport:t,cleanup:async()=>{t.close()}}}function C(e,t){return r=>async(i,c)=>{f.info(`MCP tool called: ${r}`);const u=e.elicitationEnabled?O(e.user,i.sessionHandle):{kind:"anonymous"},o=u.kind==="resolved"?u.subject:void 0;if(u.kind==="invalid")return{content:[{type:"text",text:u.message}],isError:!0};const g=async()=>{if(!(!e.elicitationEnabled||!o||!t?.getKv))try{const a=await t.getKv();return await q.getSecretsForSubject(a,o)}catch(a){f.warn(`gateway mcp secret store error, continuing unauthenticated: ${String(a)}`);return}},m=async()=>{const a=await g(),p={toolName:r,args:i,context:{...e,upstreamSecrets:a},extra:K(c)};return await y.exec(b,[p],{timeout:k})};let n=await m();const s=T(n);if(s.length>0&&e.elicitationEnabled&&!o)return S({...n,content:[{type:"text",text:D}],isError:!0});if(s.length>0&&e.elicitationEnabled&&o&&t?.getKv){const a=await t.getKv(),p=await _(e,s[0].api),l=await A(`${o}:${s[0].api}`,()=>U({sendRequest:(E,I,h)=>c.sendRequest(E,I,h),clientSupportsElicitation:!!t?.getClientCapabilities()?.elicitation,subject:o,baseUrl:e.baseUrl??"",events:s,auth:p,kv:a}));l.status==="accepted"?n=await m():l.status==="fallback"&&(n={...n,content:[...n.content,{type:"text",text:l.text}]})}return S(n)}}function K(e){return{sessionId:e.sessionId,authInfo:e.authInfo,requestId:e.requestId,requestInfo:e.requestInfo,_meta:e._meta}}function J(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,upstreamSecrets:e.upstreamSecrets}}export{Y as connectMcpServer,H as createMcpServer,C as createToolDispatch,J as extractSerializableContext};
@@ -1 +1 @@
1
- import{logger as i}from"../../../tools/notifiers/logger.js";import{secretStore as a}from"../gateway-mcp/secret-store.js";const c=1800*1e3,o=60*1e3,r=500;class h{#t=new Map;#e;#s;constructor(t={}){this.#e=t.maxSessions??r,this.#s=t.onEvict??(s=>a.deleteSession(s)),setInterval(()=>{this.#i()},o).unref?.()}get(t){const e=this.#t.get(t);if(e)return e.lastAccess=Date.now(),this.#t.delete(t),this.#t.set(t,e),e.instance}set(t,e){const s=this.#t.get(t);if(this.#t.delete(t),this.#t.set(t,{instance:e,lastAccess:Date.now()}),s&&s.instance!==e&&this.#n(t,s.instance),this.#t.size>this.#e){const n=this.#t.keys().next().value;n!==void 0&&this.close(n)}}async close(t){const e=this.#t.get(t);e&&(this.#t.delete(t),this.#s(t),await this.#n(t,e.instance))}async#n(t,e){try{await e.cleanup()}catch(s){i.warn(`Failed to clean up MCP session ${t.slice(0,8)}\u2026: ${s instanceof Error?s.message:String(s)}`)}}async#i(){const t=Date.now()-c;for(const[e,s]of this.#t)s.lastAccess<=t&&await this.close(e)}}const g=new h;export{h as McpSessionManager,g as mcpSessionManager};
1
+ import{logger as i}from"../../../tools/notifiers/logger.js";const a=1800*1e3,c=60*1e3,o=500;class r{#t=new Map;#e;#s;constructor(t={}){this.#e=t.maxSessions??o,this.#s=t.onEvict??(()=>{}),setInterval(()=>{this.#i()},c).unref?.()}get(t){const e=this.#t.get(t);if(e)return e.lastAccess=Date.now(),this.#t.delete(t),this.#t.set(t,e),e.instance}set(t,e){const s=this.#t.get(t);if(this.#t.delete(t),this.#t.set(t,{instance:e,lastAccess:Date.now()}),s&&s.instance!==e&&this.#n(t,s.instance),this.#t.size>this.#e){const n=this.#t.keys().next().value;n!==void 0&&this.close(n)}}async close(t){const e=this.#t.get(t);e&&(this.#t.delete(t),this.#s(t),await this.#n(t,e.instance))}async#n(t,e){try{await e.cleanup()}catch(s){i.warn(`Failed to clean up MCP session ${t.slice(0,8)}\u2026: ${s instanceof Error?s.message:String(s)}`)}}async#i(){const t=Date.now()-a;for(const[e,s]of this.#t)s.lastAccess<=t&&await this.close(e)}}const f=new r;export{r as McpSessionManager,f as mcpSessionManager};
@@ -1,8 +1,7 @@
1
- import type { OpenAPIOperation, OpenAPIPath } from '@redocly/openapi-docs/src/types';
2
1
  import type { ApiFunctionsContext, ApiFunctionsContextMethods, PageStaticData } from '@redocly/config';
3
2
  import type { CallToolResult, RequestId, RequestInfo, RequestMeta } from '@redocly/mcp-typescript-sdk/types.js';
4
3
  import type { AuthInfo } from '@redocly/mcp-typescript-sdk/server/types.js';
5
- import type { OpenAPIServer } from '@redocly/openapi-docs/lib/types/open-api.js';
4
+ import type { OpenAPIPath, OpenAPIServer, OpenAPIOperation } from '@redocly/api-docs';
6
5
  import type { McpErrorCodes, McpServerType } from './constants';
7
6
  import type { McpToolSchema } from '../../types';
8
7
  import type { Skill } from '../../types/plugins/skills.js';
@@ -29,6 +28,7 @@ export type McpDocsStaticDataPropsConfig = {
29
28
  graphqlDescriptions: GraphqlDescriptionInfo[];
30
29
  mcpMode: McpMode;
31
30
  elicitationEnabled: boolean;
31
+ gatewayFetchBudgetPerExec: number;
32
32
  };
33
33
  export type McpDocsStaticData = PageStaticData & {
34
34
  props: {
@@ -95,6 +95,8 @@ export type McpToolContext = Omit<ApiFunctionsContext, 'telemetry' | 'getKv' | k
95
95
  upstreamAuthorization?: string;
96
96
  mcpMode?: McpMode;
97
97
  elicitationEnabled?: boolean;
98
+ gatewayFetchBudgetPerExec?: number;
99
+ clientIp?: string;
98
100
  upstreamSecrets?: Record<string, StoredSecret>;
99
101
  };
100
102
  export type McpToolHandler<TArgs extends Record<string, unknown> = Record<string, unknown>> = (args: TArgs, context: McpToolContext, extra: McpToolExtra) => Promise<McpToolWorkerResponse>;
@@ -1 +1 @@
1
- import{EntitlementsProvider as e}from"../../../entitlements/entitlements-provider.js";import{envConfig as n}from"../../../config/env-config.js";function t(){return e.instance().entitlements?.mcpMode==="code"}function o(){return!!e.instance().canAccessFeature("mcpGateway")&&t()}function i(){return(n.REDOCLY_EXP_MCP_ELICITATION_ENABLED??!1)&&o()}function a(){return t()?"code":"tools"}export{a as getMcpMode,t as isMcpCodeModeEnabled,i as isMcpElicitationEnabled,o as isMcpGatewayEnabled};
1
+ import{EntitlementsProvider as e}from"../../../entitlements/entitlements-provider.js";import{envConfig as n}from"../../../config/env-config.js";function t(){return e.instance().entitlements?.mcpMode==="code"}function o(){return!!e.instance().canAccessFeature("mcpGateway")&&t()}function i(){return(n.REDOCLY_EXP_MCP_ELICITATION_ENABLED??!0)&&o()}function a(){return t()?"code":"tools"}export{a as getMcpMode,t as isMcpCodeModeEnabled,i as isMcpElicitationEnabled,o as isMcpGatewayEnabled};
@@ -0,0 +1,8 @@
1
+ import type { McpServerType } from '../types.js';
2
+ /** CloudEvent resource attributes shared by every `mcpServer` telemetry event. */
3
+ export declare function serverAttributes(serverType: McpServerType): {
4
+ id: "docs";
5
+ object: 'mcpServer';
6
+ uri: string;
7
+ };
8
+ //# sourceMappingURL=telemetry-attributes.d.ts.map
@@ -0,0 +1 @@
1
+ function e(r){return{id:r,object:"mcpServer",uri:`urn:redocly:realm:mcp:server:${r}`}}export{e as serverAttributes};
@@ -1,4 +1,4 @@
1
- import type { OpenAPIDefinition } from '@redocly/openapi-docs';
1
+ import type { OpenAPIDefinition } from '@redocly/api-docs';
2
2
  import type { XMcpConfig, XMcpSection } from '../types.js';
3
3
  /**
4
4
  * Returns false when the endpoint is hidden for `section`; otherwise strips x-mcp from the
@@ -1,8 +1,20 @@
1
+ import type { DocumentNode } from 'graphql';
1
2
  import type { ApiFunctionsUser, RbacConfig, RedirectConfig } from '@redocly/config';
2
- import type { ProcessContentActions } from '../../types';
3
- import type { BundledDefinition as GraphqlBundledDefinition } from '../../plugins/graphql-docs/graphql-doc-loader';
4
3
  import type { ApiDescriptionInfo, GraphqlDescriptionInfo } from './types.js';
5
- export type ApiDescriptions = Awaited<ReturnType<ProcessContentActions['loadOpenApiDefinitions']>>;
4
+ import type { OpenAPIDefinition } from '@redocly/api-docs';
5
+ import type { BundledApiDefinition } from '../api-docs/loader.js';
6
+ /** OpenAPI specs only; MCP lists paths/servers from OpenAPI documents. */
7
+ export type McpOpenApiSpec = {
8
+ relativePath: string;
9
+ definition: OpenAPIDefinition;
10
+ };
11
+ export type McpGraphqlSpec = {
12
+ relativePath: string;
13
+ definition: DocumentNode;
14
+ options: BundledApiDefinition['options'];
15
+ };
16
+ export declare function bundledOpenApiDocumentsToMcpOpenApi(bundled: BundledApiDefinition[]): McpOpenApiSpec[];
17
+ export declare function bundledGraphqlDocumentsToMcpOpenApi(bundled: BundledApiDefinition[]): McpGraphqlSpec[];
6
18
  /**
7
19
  * Filters out localizations and definitions with no public paths.
8
20
  *
@@ -19,7 +31,7 @@ export type ApiDescriptions = Awaited<ReturnType<ProcessContentActions['loadOpen
19
31
  * { relativePath: 'api.yaml', definition: { paths: { '/users': {} } } }
20
32
  * ]); // Returns only the api.yaml definition
21
33
  */
22
- export declare function getCleanedUpApiDescriptions(apiDescriptions: ApiDescriptions): ApiDescriptions;
34
+ export declare function getCleanedUpApiDescriptions(apiDescriptions: McpOpenApiSpec[]): McpOpenApiSpec[];
23
35
  /**
24
36
  * Filters OpenAPI definitions based on user RBAC permissions.
25
37
  *
@@ -39,7 +51,7 @@ export declare function getCleanedUpApiDescriptions(apiDescriptions: ApiDescript
39
51
  */
40
52
  export declare function filterApiDescriptionsByRbac(apiDescriptions: Record<string, ApiDescriptionInfo>, user: ApiFunctionsUser, rbac: RbacConfig, requiresLogin: boolean): Record<string, ApiDescriptionInfo>;
41
53
  export declare function filterGraphqlDescriptionsByRbac(graphqlDescriptions: GraphqlDescriptionInfo[], user: ApiFunctionsUser, rbac: RbacConfig, requiresLogin: boolean): GraphqlDescriptionInfo[];
42
- export declare function buildGraphqlDescriptions(definitions: GraphqlBundledDefinition[]): GraphqlDescriptionInfo[];
54
+ export declare function buildGraphqlDescriptions(definitions: McpGraphqlSpec[]): GraphqlDescriptionInfo[];
43
55
  export declare function filterIgnoredApiDescriptions<T extends {
44
56
  relativePath: string;
45
57
  }>(apiDescriptions: T[], ignoredPaths: string[]): T[];
@@ -1 +1 @@
1
- import f,{join as a}from"node:path";import u from"picomatch";import{PUBLIC_API_DEFINITIONS_FOLDER as h,L10N_DIR_NAME as o,I18N_DIR_NAME as s}from"../../constants/common.js";import{RESERVED_ROUTES as l}from"../../plugins/get-reserved-routes.js";import{canDownloadApiDefinition as m}from"../../utils/rbac.js";function p(r){if(typeof r!="object"||r===null)return r;if(Array.isArray(r))return r.map(p);const i={};for(const t in r)if(Object.hasOwn(r,t)){if(t.toString().startsWith("x-parsed-"))continue;i[t]=p(r[t])}return i}function x(r){return r.reduce((i,t)=>(t.relativePath.startsWith(o)||t.relativePath.startsWith(s)||t.definition?.paths&&Object.keys(t.definition.paths).length>0&&i.push({...t,definition:p(t.definition)}),i),[])}function R(r,i,t,e){const n={};for(const[D,c]of Object.entries(r))m(a(h,c.relativePath),t,e,i)&&(n[D]=c);return n}function g(r,i,t,e){return r.filter(n=>m(a(h,n.relativePath),t,e,i))}function E(r){return r.filter(({relativePath:i})=>!i.startsWith(o)&&!i.startsWith(s)).map(({relativePath:i,settings:t})=>({name:t.info?.title||f.basename(i,f.extname(i)),description:t.info?.description,relativePath:i}))}function _(r,i){return r.filter(({relativePath:t})=>!u(i||[])(t))}function W(r={}){for(const[i,t]of Object.entries(r))if(i===l.mcp||(typeof t=="string"?t:t.to)===l.mcp)return!0;return!1}function b(r,i,t){return r.startsWith(o)||r.startsWith(s)||!i?.paths||Object.keys(i.paths).length===0?!1:!u(t?.docs?.ignore||[])(r)}export{E as buildGraphqlDescriptions,R as filterApiDescriptionsByRbac,g as filterGraphqlDescriptionsByRbac,_ as filterIgnoredApiDescriptions,x as getCleanedUpApiDescriptions,b as isApiIncludedInDocsMcp,W as isMcpInRedirects};
1
+ import a,{join as f}from"node:path";import u from"picomatch";import{PUBLIC_API_DEFINITIONS_FOLDER as l,L10N_DIR_NAME as o,I18N_DIR_NAME as p}from"../../constants/common.js";import{RESERVED_ROUTES as h}from"../../plugins/get-reserved-routes.js";import{canDownloadApiDefinition as m}from"../../utils/rbac.js";function x(e){return e.filter(t=>t.type==="openapi").map(t=>({relativePath:t.relativePath,definition:t.document}))}function g(e){return e.filter(t=>t.type==="graphql").map(t=>({relativePath:t.relativePath,definition:t.document,options:t.options}))}function s(e){if(typeof e!="object"||e===null)return e;if(Array.isArray(e))return e.map(s);const t={};for(const i in e)if(Object.hasOwn(e,i)){if(i.toString().startsWith("x-parsed-"))continue;t[i]=s(e[i])}return t}function P(e){return e.reduce((t,i)=>(i.relativePath.startsWith(o)||i.relativePath.startsWith(p)||!i.definition||typeof i.definition!="object"||!("paths"in i.definition)||i.definition?.paths&&Object.keys(i.definition.paths).length>0&&t.push({...i,definition:s(i.definition)}),t),[])}function R(e,t,i,r){const n={};for(const[d,c]of Object.entries(e))m(f(l,c.relativePath),i,r,t)&&(n[d]=c);return n}function E(e,t,i,r){return e.filter(n=>m(f(l,n.relativePath),i,r,t))}function _(e){return e.filter(({relativePath:t})=>!t.startsWith(o)&&!t.startsWith(p)).map(({relativePath:t,options:i})=>({name:i.info?.title||a.basename(t,a.extname(t)),description:i.info?.description,relativePath:t}))}function W(e,t){return e.filter(({relativePath:i})=>!u(t||[])(i))}function b(e={}){for(const[t,i]of Object.entries(e))if(t===h.mcp||(typeof i=="string"?i:i.to)===h.mcp)return!0;return!1}function M(e,t,i){return e.startsWith(o)||e.startsWith(p)||!t?.paths||Object.keys(t.paths).length===0?!1:!u(i?.docs?.ignore||[])(e)}export{_ as buildGraphqlDescriptions,g as bundledGraphqlDocumentsToMcpOpenApi,x as bundledOpenApiDocumentsToMcpOpenApi,R as filterApiDescriptionsByRbac,E as filterGraphqlDescriptionsByRbac,W as filterIgnoredApiDescriptions,P as getCleanedUpApiDescriptions,M as isApiIncludedInDocsMcp,b as isMcpInRedirects};
@@ -1 +1 @@
1
- import{telemetry as c}from"../../../telemetry/index.js";function l(r){return{id:r,object:"mcpServer",uri:`urn:redocly:realm:mcp:server:${r}`,server_type:r}}function s({tool:r,mode:e,serverType:o,durationMs:t,outputLength:n}){c.sendMcpToolCalledMessage([{...l(o),tool:r,mode:e,output_length:n,duration_ms:t}])}function i({tool:r,mode:e,serverType:o,durationMs:t,message:n,stack:p=""}){c.sendMcpErrorMessage([{...l(o),tool:r,message:n,stack:p,mode:e,duration_ms:t}])}export{s as reportMcpToolCalled,i as reportMcpToolError};
1
+ import{telemetry as s}from"../../../telemetry/index.js";import{serverAttributes as l}from"../utils/telemetry-attributes.js";function u({tool:r,mode:o,serverType:e,durationMs:t,outputLength:p}){s.sendMcpToolCalledMessage([{...l(e),tool:r,mode:o,output_length:p,duration_ms:t}])}function a({tool:r,mode:o,serverType:e,durationMs:t,message:p,stack:n=""}){s.sendMcpErrorMessage([{...l(e),tool:r,message:p,stack:n,mode:o,duration_ms:t}])}export{u as reportMcpToolCalled,a as reportMcpToolError};
@@ -1 +1 @@
1
- import{simplifyAstStructure as Z}from"@redocly/openapi-docs";import{REDOCLY_ROUTE_RBAC as y,REDOCLY_TEAMS_RBAC as D}from"@redocly/config";import{OPENAPI_DOCS_TEMPLATE_ID as j,PUBLIC_RBAC_SCOPE_ITEM as U}from"../../../constants/common.js";import{DEPRECATED_PUBLIC_API_DEFINITIONS_FOLDER as ee,PUBLIC_API_DEFINITIONS_FOLDER as te}from"../../constants/common.js";import{OPENAPI_SHARED_DATA_PREFIX as L}from"../../constants/plugins/openapi-docs.js";import{envConfig as V}from"../../config/env-config.js";import{isRbacScopeItems as oe}from"../../utils/rbac/is-rbac-scope-items.js";import{getRouteSlugsForPath as ae}from"../utils.js";import{searchResolver as re}from"./search/search-resolver.js";import{convertOpenAPIDocs2Sidebar as ie,shouldAddRoute as se}from"./utils.js";import{getTemplatePath as q}from"./get-template-path.js";import{storeDefinitionBundles as ne}from"./store-definition-bundles.js";import{definitionLoader as pe,definitionsLoader as ce}from"./load-definition.js";import{getAiDocumentsStore as de}from"./search/get-ai-search-documents.js";import{fromCurrentDir as le}from"../../utils/paths.js";import{telemetryTraceStep as fe}from"../../../cli/telemetry/helpers/trace-step.js";import{getApiConfigByPath as ue}from"../get-api-config.js";import{shouldAdvertiseGatewayXMcp as me,buildGatewayXMcp as ge}from"../mcp/gateway-mcp/eligibility.js";const x="openapi-spec-download";async function Be(){let k=[],C={},N=new Set,d={};return{id:"openapi",requiredEntitlements:["openapi"],loaders:{"load-oas-docs":ce,"load-oas":pe},processContent:async(e,n)=>{await fe("build.plugin.openapi_docs",async l=>{e.createRequestHandler(x,le(import.meta.url,"./spec-download.api.js")),e.addApiRoute({slug:te+"/*",requestHandlerId:x,httpMethod:"all",[D]:U,getStaticData:async()=>({props:{}})}),e.addApiRoute({slug:ee+"/*",requestHandlerId:x,httpMethod:"all",[D]:U,getStaticData:async()=>({props:{}})});const E=e.createTemplate(j,q("../../../client/templates/openapi-docs/template.js")),f=e.registerServerPropsGetter(j,q("./get-server-props.js")),u=await n.getConfig();l?.setAttribute("config",JSON.stringify(u.openapi||{})),C={},d={};const p=await e.loadOpenApiDefinitions(n);k=p.map(({markdocChunks:a,relativePath:o,customOutputRelativeFile:r,isVirtual:i,realRelativePath:m})=>({chunks:a,relativePath:o,realRelativePath:m,isVirtual:r!=null||i})),ne(p,e.outdir);for(const a of p||[]){const{definition:o,config:r,relativePath:i,customOutputRelativeFile:m,contentItems:_,flatItems:g,parser:h,options:I,rawOptions:v,hash:R}=a,S=m||i,s=[],G={},{definition:X}=h||{},{info:c}=X||{},O=c?.["x-metadata"],w=!!r.openapi?.excludeFromSearch||!!r.theme?.openapi?.excludeFromSearch||!!u.openapi?.excludeFromSearch||!!u.theme?.openapi?.excludeFromSearch,H={title:c?.title,description:c?.description,summary:c?.summary,...r.metadata,...O},P={untagged:[],tagged:new Map};for(const t of g){const{id:F,href:A,operationDefinition:T}=t;if(T){const{tags:b}=T;if(b)for(const B of b)P.tagged.has(B)||P.tagged.set(B,[]),P.tagged.get(B)?.push(t);else P.untagged.push(t);V.isDevelopMode&&(G[`#${T.pointer}`]=t.href)}if(!se({item:t}))continue;const M=t,Q=M.type==="section"&&!!M.infoDefinition,W=A.split("#")[0]+"/",z=t?.operationDefinition?.[D],K=oe(r.access?.rbac)?r.access.rbac:void 0;s.push({excludeFromSearch:w,slugSuffix:W,fsPath:S,metadata:{subType:"openapi-operation"},httpVerb:t?.httpVerb||"",path:i,templateId:E,[D]:z||K,getAiDocumentsStore:de({parser:h,options:I,info:c,tagOperations:P,openapiContentItem:M,metadata:H,relativePath:i,getSearchFacets:e.getSearchFacets,includeInLLMsTxt:Q,excludeFromSearch:w}),getStaticData:async b=>({props:{dynamicMarkdocComponents:["openapi"],baseSlug:b.baseSlug,seo:t["x-metadata"]?.seo||{title:t.name,description:t.description},itemId:F,disableAutoScroll:!0}})})}if(s[0]={...s[0],metadata:{type:"openapi",...H},hasClientRoutes:!0,getSidebar:(t,F)=>{const A=[];return ie({contentItems:_,sidebarItems:A,routeSlug:t.slug,navItem:F}),A},getNavText:()=>c?.title,getSearchDocuments:re(h,I,g,e.getSearchFacets,e.setSearchFacets,w)},O?.apiId&&!a.isVirtual){const t=ue(a.config.apis,a.realRelativePath);d[O.apiId]={[D]:t.rbac,[y]:{fsPath:S}}}const Y=s[0];s[0]=s[s.length-1],s[s.length-1]=Y;for(const t of s)e.addRoute({...t,serverPropsGetterIds:[f]});const J=V.isDevelopMode?i:void 0,$=`${L}${i}`;C[$]={fsPath:S,definition:o,options:v,sourcePath:J,routesMapping:G,hash:R};for(const t of s)e.addRoute({...t,sharedData:[{id:$,key:"openAPIDocsStore"}],serverPropsGetterIds:[f]})}})},afterRoutesCreated:async(e,n)=>{const l=new Set;for(const{chunks:a,relativePath:o,isVirtual:r,realRelativePath:i}of k){const m=ae(e.getAllRoutes(),o),_=(await n.cache.load(i,"load-oas")).compoundHash;await n.cache.load(o,{loader:async function(){for(const{node:h,markdown:I,key:v,relativePath:R}of a){const{ast:S}=await e.parseMarkdoc({input:{content:I,relativePath:R,isVirtual:r},context:n,deps:{sharedDataIds:[`${L}${R}`],routeSlugs:m}});h[`x-parsed-md-${v}`]={result:Z(S)}}},name:"openapi-markdoc-inline-parser"},[_]);for(const{pointer:g}of a)l.add(g)}const E=N.difference(l);for(const a of E)n.cache.delete(a);N=l;const f=e.getConfig(),u=f.access?.rbac??{},p=n.withPathPrefix("/mcp");for(const[a,o]of Object.entries(C)){const r=e.getRouteByFsPath(o.fsPath)?.baseSlug,i=r&&me(o.definition,a.slice(L.length),u,f.mcp)?{...o.definition,"x-mcp":{...ge(p),...o.definition["x-mcp"],servers:[{url:p}]}}:o.definition;await e.createSharedData(a,{...o,definition:i,baseSlug:r},o.hash)}Object.entries(d).forEach(([a,o])=>{const r=o[y]?.fsPath;if(!r)return;const i=e.getRouteByFsPath(r)?.baseSlug;d[a]={...o,[y]:{...o[y],slug:i},slug:i}}),e.setGlobalData({apiProducts:d})}}}export{Be as openAPIDocsPlugin};
1
+ import{simplifyAstStructure as Z}from"@redocly/openapi-docs";import{REDOCLY_ROUTE_RBAC as y,REDOCLY_TEAMS_RBAC as D}from"@redocly/config";import{OPENAPI_DOCS_TEMPLATE_ID as j,PUBLIC_RBAC_SCOPE_ITEM as U}from"../../../constants/common.js";import{DEPRECATED_PUBLIC_API_DEFINITIONS_FOLDER as ee,PUBLIC_API_DEFINITIONS_FOLDER as te}from"../../constants/common.js";import{OPENAPI_SHARED_DATA_PREFIX as L}from"../../constants/plugins/openapi-docs.js";import{envConfig as V}from"../../config/env-config.js";import{isRbacScopeItems as oe}from"../../utils/rbac/is-rbac-scope-items.js";import{getRouteSlugsForPath as ae}from"../utils.js";import{searchResolver as re}from"./search/search-resolver.js";import{convertOpenAPIDocs2Sidebar as se,shouldAddRoute as ie}from"./utils.js";import{getTemplatePath as q}from"./get-template-path.js";import{storeDefinitionBundles as ne}from"./store-definition-bundles.js";import{definitionLoader as ce,definitionsLoader as pe}from"./load-definition.js";import{getAiDocumentsStore as de}from"./search/get-ai-search-documents.js";import{fromCurrentDir as le}from"../../utils/paths.js";import{telemetryTraceStep as fe}from"../../../cli/telemetry/helpers/trace-step.js";import{getApiConfigByPath as ue}from"../get-api-config.js";import{shouldAdvertiseGatewayXMcp as me,buildGatewayXMcp as ge}from"../mcp/gateway-mcp/eligibility.js";const x="openapi-spec-download";async function Be(){let k=[],C={},N=new Set,d={};return{id:"openapi",requiredEntitlements:["openapi"],loaders:{"load-oas-docs":pe,"load-oas":ce},processContent:async(e,n)=>{await fe("com.redocly.build.plugin.openapiDocs",async l=>{e.createRequestHandler(x,le(import.meta.url,"./spec-download.api.js")),e.addApiRoute({slug:te+"/*",requestHandlerId:x,httpMethod:"all",[D]:U,getStaticData:async()=>({props:{}})}),e.addApiRoute({slug:ee+"/*",requestHandlerId:x,httpMethod:"all",[D]:U,getStaticData:async()=>({props:{}})});const E=e.createTemplate(j,q("../../../client/templates/openapi-docs/template.js")),f=e.registerServerPropsGetter(j,q("./get-server-props.js")),u=await n.getConfig();l?.setAttribute("config",JSON.stringify(u.openapi||{})),C={},d={};const c=(await n.cache.load(".","load-oas-docs")).data;k=c.map(({markdocChunks:a,relativePath:o,customOutputRelativeFile:r,isVirtual:s,realRelativePath:m})=>({chunks:a,relativePath:o,realRelativePath:m,isVirtual:r!=null||s})),ne(c,e.outdir);for(const a of c||[]){const{definition:o,config:r,relativePath:s,customOutputRelativeFile:m,contentItems:_,flatItems:g,parser:h,options:I,rawOptions:v,hash:R}=a,S=m||s,i=[],G={},{definition:X}=h||{},{info:p}=X||{},O=p?.["x-metadata"],w=!!r.openapi?.excludeFromSearch||!!r.theme?.openapi?.excludeFromSearch||!!u.openapi?.excludeFromSearch||!!u.theme?.openapi?.excludeFromSearch,H={title:p?.title,description:p?.description,summary:p?.summary,...r.metadata,...O},P={untagged:[],tagged:new Map};for(const t of g){const{id:F,href:A,operationDefinition:T}=t;if(T){const{tags:b}=T;if(b)for(const B of b)P.tagged.has(B)||P.tagged.set(B,[]),P.tagged.get(B)?.push(t);else P.untagged.push(t);V.isDevelopMode&&(G[`#${T.pointer}`]=t.href)}if(!ie({item:t}))continue;const M=t,Q=M.type==="section"&&!!M.infoDefinition,W=A.split("#")[0]+"/",z=t?.operationDefinition?.[D],K=oe(r.access?.rbac)?r.access.rbac:void 0;i.push({excludeFromSearch:w,slugSuffix:W,fsPath:S,metadata:{subType:"openapi-operation"},httpVerb:t?.httpVerb||"",path:s,templateId:E,[D]:z||K,getAiDocumentsStore:de({parser:h,options:I,info:p,tagOperations:P,openapiContentItem:M,metadata:H,relativePath:s,getSearchFacets:e.getSearchFacets,includeInLLMsTxt:Q,excludeFromSearch:w}),getStaticData:async b=>({props:{dynamicMarkdocComponents:["openapi"],baseSlug:b.baseSlug,seo:t["x-metadata"]?.seo||{title:t.name,description:t.description},itemId:F,disableAutoScroll:!0}})})}if(i[0]={...i[0],metadata:{type:"openapi",...H},hasClientRoutes:!0,getSidebar:(t,F)=>{const A=[];return se({contentItems:_,sidebarItems:A,routeSlug:t.slug,navItem:F}),A},getNavText:()=>p?.title,getSearchDocuments:re(h,I,g,e.getSearchFacets,e.setSearchFacets,w)},O?.apiId&&!a.isVirtual){const t=ue(a.config.apis,a.realRelativePath);d[O.apiId]={[D]:t.rbac,[y]:{fsPath:S}}}const Y=i[0];i[0]=i[i.length-1],i[i.length-1]=Y;for(const t of i)e.addRoute({...t,serverPropsGetterIds:[f]});const J=V.isDevelopMode?s:void 0,$=`${L}${s}`;C[$]={fsPath:S,definition:o,options:v,sourcePath:J,routesMapping:G,hash:R};for(const t of i)e.addRoute({...t,sharedData:[{id:$,key:"openAPIDocsStore"}],serverPropsGetterIds:[f]})}})},afterRoutesCreated:async(e,n)=>{const l=new Set;for(const{chunks:a,relativePath:o,isVirtual:r,realRelativePath:s}of k){const m=ae(e.getAllRoutes(),o),_=(await n.cache.load(s,"load-oas")).compoundHash;await n.cache.load(o,{loader:async function(){for(const{node:h,markdown:I,key:v,relativePath:R}of a){const{ast:S}=await e.parseMarkdoc({input:{content:I,relativePath:R,isVirtual:r},context:n,deps:{sharedDataIds:[`${L}${R}`],routeSlugs:m}});h[`x-parsed-md-${v}`]={result:Z(S)}}},name:"openapi-markdoc-inline-parser"},[_]);for(const{pointer:g}of a)l.add(g)}const E=N.difference(l);for(const a of E)n.cache.delete(a);N=l;const f=e.getConfig(),u=f.access?.rbac??{},c=n.withPathPrefix("/mcp");for(const[a,o]of Object.entries(C)){const r=e.getRouteByFsPath(o.fsPath)?.baseSlug,s=r&&me(o.definition,a.slice(L.length),u,f.mcp)?{...o.definition,"x-mcp":{...ge(c),...o.definition["x-mcp"],servers:[{url:c}]}}:o.definition;await e.createSharedData(a,{...o,definition:s,baseSlug:r},o.hash)}Object.entries(d).forEach(([a,o])=>{const r=o[y]?.fsPath;if(!r)return;const s=e.getRouteByFsPath(r)?.baseSlug;d[a]={...o,[y]:{...o[y],slug:s},slug:s}}),e.setGlobalData({apiProducts:d})}}}export{Be as openAPIDocsPlugin};
@@ -1 +1 @@
1
- import{REDOCLY_TEAMS_RBAC as i}from"@redocly/config";import{combineUrls as p}from"@redocly/theme/core/utils";import{FEEDBACK_TYPES as c}from"../../../constants/common.js";import{normalizeRouteSlug as g}from"../../../utils/path/normalize-route-slug.js";function u(t){const{contentItems:r,sidebarItems:a,routeSlug:o,navItem:s}=t;let b=!0;for(const e of r){let n;switch(e.type){case"group":a.push({type:"separator",label:e.name,[i]:e[i]}),u({...t,contentItems:e.items,sidebarItems:a});break;case"tag":n=p(o,e.href);const m={type:"group",label:e.name,items:[],link:n,routeSlug:n,[i]:e[i]};a.push(m),u({routeSlug:o,contentItems:e.items,sidebarItems:m.items||[],navItem:s});break;case"operation":case"schema":case"rsrc":case"prompt":case"tool":e.isWebhook&&b&&(a.push({type:"separator",label:"Webhooks",variant:"secondary"}),b=!1),n=p(o,e.href),a.push({type:"link",label:e.name,httpVerb:e.type==="operation"?e.httpVerb:e.type,routeSlug:g(n),badges:e.badges,link:n,deprecated:e.deprecated,isAdditionalOperation:e.isAdditionalOperation,[i]:e[i]});break;case"section":if(e.depth===-1)continue;n=p(o,e.href);const l=e.href==="/",f={type:e.items.length?"group":"link",label:l&&s?.label?s.label:e.name,labelTranslationKey:s?.labelTranslationKey,routeSlug:n.split("#")[0]===o?o:g(n),link:n,items:[],...l&&s?.icon&&{icon:typeof s.icon=="object"?s.icon.srcSet:s.icon},...l&&s?.badges&&{badges:s.badges}};a.push(f),e.items.length&&u({routeSlug:o,contentItems:e.items,sidebarItems:f.items});break}}}function S({item:t}){return t.id===""?!0:t.type!=="group"||t.description!==""}const I=t=>(typeof t=="string"?t:t?.raw)?.replace(/\[(.*?)\][\[\(].*?[\]\)]/g,"$1")||"";function O(t){if(!t)return;let r="";const{type:a,settings:o}=t;switch(a){case c.RATING:r="Rate this section";break;case c.SENTIMENT:r="Was this section helpful?";break;case c.MOOD:r="Was this section helpful?";break;case c.COMMENT:r="Share your feedback about this section";break;case c.SCALE:r="How would you rate this section?";break}return{...t,settings:{...o,label:o?.label||r}}}function A(t){return(typeof t=="string"?t:t?.raw||"").replace(/<[^>]*>/g,"").replace(/```([\s\S]*?)```/g,"$1").replace(/`([^`]+)`/g,"$1").replace(/\*\*(.*?)\*\*/g,"$1").replace(/\*(.*?)\*/g,"$1").trim()}function E(t){if(t?.oneOf)return t;if(t?.items?.oneOf)return t.items}export{u as convertOpenAPIDocs2Sidebar,E as getOneOfSchema,O as normalizeFeedbackOptions,I as removeMarkdownLinks,S as shouldAddRoute,A as stripFormatting};
1
+ import{REDOCLY_TEAMS_RBAC as i}from"@redocly/config";import{combineUrls as l}from"@redocly/theme/core/utils";import{FEEDBACK_TYPES as c}from"../../../constants/common.js";import{normalizeRouteSlug as f}from"../../../utils/path/normalize-route-slug.js";function u(t){const{contentItems:r,sidebarItems:a,routeSlug:o,navItem:s}=t;let m=!0;for(const e of r){let n;switch(e.type){case"group":a.push({type:"separator",label:e.name,hideWhenEmpty:!0,[i]:e[i]}),u({...t,contentItems:e.items,sidebarItems:a});break;case"tag":n=l(o,e.href);const b={type:"group",label:e.name,items:[],link:n,routeSlug:n,[i]:e[i]};a.push(b),u({routeSlug:o,contentItems:e.items,sidebarItems:b.items||[],navItem:s});break;case"operation":case"schema":case"rsrc":case"prompt":case"tool":e.isWebhook&&m&&(a.push({type:"separator",label:"Webhooks",variant:"secondary",hideWhenEmpty:!0}),m=!1),n=l(o,e.href),a.push({type:"link",label:e.name,httpVerb:e.type==="operation"?e.httpVerb:e.type,routeSlug:f(n),badges:e.badges,link:n,deprecated:e.deprecated,isAdditionalOperation:e.isAdditionalOperation,[i]:e[i]});break;case"section":if(e.depth===-1)continue;n=l(o,e.href);const p=e.href==="/",d={type:e.items.length?"group":"link",label:p&&s?.label?s.label:e.name,labelTranslationKey:s?.labelTranslationKey,routeSlug:n.split("#")[0]===o?o:f(n),link:n,items:[],...p&&s?.icon&&{icon:typeof s.icon=="object"?s.icon.srcSet:s.icon},...p&&s?.badges&&{badges:s.badges}};a.push(d),e.items.length&&u({routeSlug:o,contentItems:e.items,sidebarItems:d.items});break}}}function S({item:t}){return t.id===""?!0:t.type!=="group"||t.description!==""}const I=t=>(typeof t=="string"?t:t?.raw)?.replace(/\[(.*?)\][\[\(].*?[\]\)]/g,"$1")||"";function E(t){if(!t)return;let r="";const{type:a,settings:o}=t;switch(a){case c.RATING:r="Rate this section";break;case c.SENTIMENT:r="Was this section helpful?";break;case c.MOOD:r="Was this section helpful?";break;case c.COMMENT:r="Share your feedback about this section";break;case c.SCALE:r="How would you rate this section?";break}return{...t,settings:{...o,label:o?.label||r}}}function O(t){return(typeof t=="string"?t:t?.raw||"").replace(/<[^>]*>/g,"").replace(/```([\s\S]*?)```/g,"$1").replace(/`([^`]+)`/g,"$1").replace(/\*\*(.*?)\*\*/g,"$1").replace(/\*(.*?)\*/g,"$1").trim()}function A(t){if(t?.oneOf)return t;if(t?.items?.oneOf)return t.items}export{u as convertOpenAPIDocs2Sidebar,A as getOneOfSchema,E as normalizeFeedbackOptions,I as removeMarkdownLinks,S as shouldAddRoute,O as stripFormatting};
@@ -1 +1 @@
1
- import g from"node:path";import{REDOCLY_TEAMS_RBAC as h}from"@redocly/config";import{slash as S}from"../../../utils/path/slash.js";import{canAccessFeature as b}from"../../utils/entitlements/can-access-feature.js";import{staticDataLoader as y}from"./loaders/static-data-loader.js";import{findFrontmatterSlugs as F,getSidebarSharedDataId as P,resolveFrontmatterSlugs as w}from"../utils.js";import{reactFrontmatterLoader as v}from"./loaders/react-frontmatter-loader.js";import{registerPageProps as D}from"../register-page-props.js";import{telemetryTraceStep as R}from"../../../cli/telemetry/helpers/trace-step.js";import{searchResolver as E}from"./search/search-resolver.js";async function x(){return{loaders:{"react-frontmatter":v},id:"react-pages",requiredEntitlements:["reactPages"],processContent:async(r,a)=>{await R("build.plugin.pages",async()=>{const{fs:o,cache:f}=a;for(const d of o.scan(/\.page\.tsx?$/)){const{relativePath:e,realRelativePath:l}=d;if(await a.isPathIgnored(e))continue;const p=r.createTemplate(S(e),g.resolve(o.cwd,l));await D(d,o,r);const{data:t}=await f.load(e,"react-frontmatter"),u=await F(e,"react-frontmatter",t,a),s=w(u,e);let c=null;t?.sidebar&&(c=await P(t.sidebar,e,a.fs)),(s.length?s.reverse():[void 0]).forEach(i=>{r.addRoute({excludeFromSearch:t?.excludeFromSearch||!1,slug:i,templateId:p,fsPath:e,sharedData:c?[{id:c,key:"sidebar"}]:void 0,[h]:b("rbac")?t?.rbac:void 0,getNavText:async()=>t?.seo?.title,getStaticData:async(m,n)=>({props:await y({frontmatter:t,relativePath:e},a,n)}),getSearchDocuments:E(t,e,r.getSearchFacets,r.setSearchFacets)})});for(const[i,{to:m,type:n}]of Object.entries(t?.redirects||{}))r.addRedirect(i,{to:m||s[0],type:n||301})}})}}}export{x as customPagesPlugin};
1
+ import g from"node:path";import{REDOCLY_TEAMS_RBAC as h}from"@redocly/config";import{slash as S}from"../../../utils/path/slash.js";import{canAccessFeature as y}from"../../utils/entitlements/can-access-feature.js";import{staticDataLoader as b}from"./loaders/static-data-loader.js";import{findFrontmatterSlugs as F,getSidebarSharedDataId as P,resolveFrontmatterSlugs as w}from"../utils.js";import{reactFrontmatterLoader as v}from"./loaders/react-frontmatter-loader.js";import{registerPageProps as D}from"../register-page-props.js";import{telemetryTraceStep as R}from"../../../cli/telemetry/helpers/trace-step.js";import{searchResolver as E}from"./search/search-resolver.js";async function x(){return{loaders:{"react-frontmatter":v},id:"react-pages",requiredEntitlements:["reactPages"],processContent:async(r,a)=>{await R("com.redocly.build.plugin.pages",async()=>{const{fs:o,cache:f}=a;for(const n of o.scan(/\.page\.tsx?$/)){const{relativePath:e,realRelativePath:l}=n;if(await a.isPathIgnored(e))continue;const p=r.createTemplate(S(e),g.resolve(o.cwd,l));await D(n,o,r);const{data:t}=await f.load(e,"react-frontmatter"),u=await F(e,"react-frontmatter",t,a),s=w(u,e);let c=null;t?.sidebar&&(c=await P(t.sidebar,e,a.fs)),(s.length?s.reverse():[void 0]).forEach(i=>{r.addRoute({excludeFromSearch:t?.excludeFromSearch||!1,slug:i,templateId:p,fsPath:e,sharedData:c?[{id:c,key:"sidebar"}]:void 0,[h]:y("rbac")?t?.rbac:void 0,getNavText:async()=>t?.seo?.title,getStaticData:async(m,d)=>({props:await b({frontmatter:t,relativePath:e},a,d)}),getSearchDocuments:E(t,e,r.getSearchFacets,r.setSearchFacets)})});for(const[i,{to:m,type:d}]of Object.entries(t?.redirects||{}))r.addRedirect(i,{to:m||s[0],type:d||301})}})}}}export{x as customPagesPlugin};
@@ -1,4 +1,4 @@
1
- import w from"node:path";import R from"picomatch";import{removeLeadingSlash as S}from"@redocly/theme/core/utils";import{parsePathVersions as O}from"../../../utils/path/parse-path-versions.js";import{logger as l}from"../../tools/notifiers/logger.js";import{ScorecardStatus as d}from"./types.js";import{getTarget as M}from"./loaders/scorecard.js";const P=15;async function y({actions:t,context:i,scorecardConfig:e,reuniteConfig:o}){l.info("Computing scorecard...");const a=e.levels||[],n=a[0],u=await t.loadOpenApiDefinitions(i),s=e.ignore||[],h=R(s),f=new Set,g=l.startTiming(),c={},p={};for(const r of u){if(!D(r,h,f))continue;const v=r.customOutputRelativeFile||r.realRelativePath;f.add(v);const m=await N(r,i,e,a,n);c[r.realRelativePath]=m,p[m.relativePath]=m}return l.infoTime(g,"Scorecard processed"),T(c,o,e),p}function D(t,i,e){if(t.isVirtual||!t.definition)return!1;const o=t.customOutputRelativeFile||t.realRelativePath,a=S(t.realRelativePath);return i(a)?(l.info(`Skipping scorecard calculation for ignored file: ${t.realRelativePath}`),!1):!e.has(o)}function L(t,i,e){return t-1<i?d.BelowMinimum:i<e-1?d.Minimum:d.Highest}async function N(t,i,e,o,a){let n=a.name;if(e.targets?.length){const r=await i.getConfig(w.posix.dirname(t.realRelativePath)),v=t.definition.info?.["x-metadata"]||{},m={title:t.definition.info?.title,version:t.definition.info?.version,...v,...r.metadata};n=(await M(e.targets,m))?.minimumLevel||a.name}const{data:{levels:u,scorecardLevelIdx:s,scorecardLevel:h}}=await i.cache.load(t.realRelativePath,"scorecard"),f=o.findIndex(r=>r.name===n),g=L(s,f,o.length),c=t.customOutputRelativeFile||t.realRelativePath,p=O(c)?.versionName;return{levels:u,status:g,targetLevel:n,scorecardLevel:h,scorecardLevelIdx:s,relativePath:c,title:t.definition.info?.title,version:p}}function T(t,i,e){const o=Object.values(t).filter(s=>s.status===d.BelowMinimum);if(o.length===0)return;const a=o.map(s=>s.relativePath);let n=`Detected OpenAPI definitions with score below minimum level:
2
- - ${a.slice(0,P).map(()=>"%rp").join(`
3
- - `)}`;a.length>P&&(n+=`
4
- ... and ${a.length-P} more`),i?.ignoreLint??e.ignoreNonCompliant?l.warn(n,...a):l.error(n,...a)}export{y as computeScorecard};
1
+ import w from"node:path";import S from"picomatch";import{removeLeadingSlash as O}from"@redocly/theme/core/utils";import{parsePathVersions as D}from"../../../utils/path/parse-path-versions.js";import{logger as c}from"../../tools/notifiers/logger.js";import{ScorecardStatus as d}from"./types.js";import{getTarget as M}from"./loaders/scorecard.js";const R=15;async function $({actions:t,context:i,scorecardConfig:e,reuniteConfig:o}){c.info("Computing scorecard...");const a=e.levels||[],n=a[0],u=await t.loadApiDocuments(i),r=B(u),h=e.ignore||[],v=S(h),m=new Set,f=c.startTiming(),p={},l={};for(const s of r){if(!L(s,v,m))continue;const g=s.customOutputRelativeFile||s.realRelativePath;m.add(g);const P=await N(s,i,e,a,n);p[s.realRelativePath]=P,l[P.relativePath]=P}return c.infoTime(f,"Scorecard processed"),T(p,o,e),l}function L(t,i,e){if(t.isVirtual||!t.definition)return!1;const o=t.customOutputRelativeFile||t.realRelativePath,a=O(t.realRelativePath);return i(a)?(c.info(`Skipping scorecard calculation for ignored file: ${t.realRelativePath}`),!1):!e.has(o)}function F(t,i,e){return t-1<i?d.BelowMinimum:i<e-1?d.Minimum:d.Highest}async function N(t,i,e,o,a){let n=a.name;if(e.targets?.length){const l=await i.getConfig(w.posix.dirname(t.realRelativePath)),s=t.definition.info?.["x-metadata"]||{},g={title:t.definition.info?.title,version:t.definition.info?.version,...s,...l.metadata};n=(await M(e.targets,g))?.minimumLevel||a.name}const{data:{levels:u,scorecardLevelIdx:r,scorecardLevel:h}}=await i.cache.load(t.realRelativePath,"scorecard"),v=o.findIndex(l=>l.name===n),m=F(r,v,o.length),f=t.customOutputRelativeFile||t.realRelativePath,p=D(f)?.versionName;return{levels:u,status:m,targetLevel:n,scorecardLevel:h,scorecardLevelIdx:r,relativePath:f,title:t.definition.info?.title,version:p}}function T(t,i,e){const o=Object.values(t).filter(r=>r.status===d.BelowMinimum);if(o.length===0)return;const a=o.map(r=>r.relativePath);let n=`Detected OpenAPI definitions with score below minimum level:
2
+ - ${a.slice(0,R).map(()=>"%rp").join(`
3
+ - `)}`;a.length>R&&(n+=`
4
+ ... and ${a.length-R} more`),i?.ignoreLint??e.ignoreNonCompliant?c.warn(n,...a):c.error(n,...a)}function B(t){const i=[];for(const e of t){if(e.type!=="openapi")continue;const o=e.document;i.push({realRelativePath:e.realRelativePath,customOutputRelativeFile:e.customOutputRelativeFile,isVirtual:e.isVirtual,definition:{info:o.info}})}return i}export{$ as computeScorecard};
@@ -1 +1 @@
1
- import{writeFileSync as D}from"node:fs";import L from"path";import{SCORECARD_OUTPUT_FILE_NAME as w}from"../../constants/common.js";import{mapObject as E}from"../../../utils/object/map-object.js";import{envConfig as A}from"../../config/env-config.js";import{removeLeadingSlash as j}from"../../../utils/url/remove-leading-slash.js";import{combineUrls as O}from"@redocly/theme/core/utils";import{logger as _}from"../../tools/notifiers/logger.js";import{getRouteSlugToCatalogSlugMap as F}from"../../utils/catalog-classic/get-route-slug-to-catalog-slug-map.js";import{deepEqual as I}from"../../../utils/object/deep-equal.js";import{ensureDir as N}from"../../utils/index.js";import{getTemplatePath as q}from"./get-template-path.js";import{getAllRuleNames as U}from"./lint.js";import{getScorecardConfig as T}from"./get-scorecard-config.js";import{getScorecardSlug as k}from"./shared-utils.js";import{scorecardConfigLoader as M}from"./loaders/scorecard-config.js";import{scorecardLoader as W}from"./loaders/scorecard.js";import{computeScorecard as B}from"./compute-scorecard.js";import{telemetryTraceStep as J}from"../../../cli/telemetry/helpers/trace-step.js";const $="scorecardClassic";let u={},R={};async function ne({id:b,requiredEntitlements:P,loadersPrefix:v=""}){let p=null,y=null,h=!1;return{id:b??"scorecardClassic",requiredEntitlements:P??["scorecard"],loaders:{[`${v}scorecard-config`]:M,[`${v}scorecard`]:W},async processContent(r,l){await J("build.plugin.scorecard_classic",async S=>{const a=r.createTemplate($,q("./template/index.js")),g=await l.getConfig(),m=T(g),f=g?.reunite??{},i=[()=>p===null,()=>!I(u,m),()=>!I(R,f)].some(e=>e());u=m,S?.setAttribute("config",JSON.stringify(u||{})),R=f;const n=g.catalogClassic??{},c=u.levels||[];if(c.length<1)throw Error("Invalid configuration of levels config");i&&(p=await B({actions:r,context:l,scorecardConfig:u,reuniteConfig:R}));const{data:{configs:t}}=await l.cache.load("",`${v}scorecard-config`),{perLevel:d,all:s}=U(t);y={levelNames:c.map(e=>e.name),rules:s,rulesPerLevel:d};for(const[e,o]of Object.entries(n)){const C=O(o.slug,"scorecard/");r.addRoute({duplicateInAllLocales:!0,slug:C,fsPath:O(o.slug,"scorecard/"),templateId:a,hasClientRoutes:!0,excludeFromSidebar:!0,serverPropsGetterIds:[],sharedData:[{id:"scorecard",key:"scorecard"},{key:"catalog",id:"catalog-"+e}],getNavText:()=>Promise.resolve(o.title||"API design scorecard"),getStaticData:async()=>({props:{catalogId:e,catalogConfig:{...o,items:void 0},scorecardConfig:u,scorecardInfo:y}})})}})},afterRoutesCreated:async(r,l)=>{const S=await l.getConfig(),a=S.catalogClassic??{},g=T(S);if(Object.keys(a).length){const i=Object.keys(a).length>1?await F(r,l,a):null,n={};for(const[c,t]of Object.entries(p||{})){const d=r.getRouteByFsPath(c),s=d?.slug;if(s){if(d&&!g.ignoreMetadata){const e=i?i.get(s)??Object.values(a)[0].slug:Object.values(a)[0].slug,o=O(e,"scorecard/");d.metadata={...d.metadata,scorecardStatus:t.status,scorecardLevel:t.scorecardLevel,scorecardLevelIdx:t.scorecardLevelIdx,scorecardLevels:E(t.levels,C=>({uniqueErrors:C.uniqueErrors,uniqueWarnings:C.uniqueWarnings})),scoreCardSlug:o+"apis/"+encodeURIComponent(j(s))}}if(n[s]={...t,levels:E(t.levels,e=>({...e,problems:e.problems.map(o=>({ruleId:o.ruleId,severity:o.severity}))}))},!h){const e=L.resolve(r.outdir,"_scorecard",k(s));D(N(e),JSON.stringify(t))}}}await r.createSharedData("scorecard",n)}const m={};for(const[i,n]of Object.entries(p||{})){const c=r.getRouteByFsPath(i)?.slug;c&&(m[c]=n)}const f=A.REDOCLY_METADATA_OUTPUT_FOLDER;!h&&f&&(_.info("Writing scorecard data..."),D(L.join(f,w),JSON.stringify({scorecardData:m,...y}))),h=!0}}}export{ne as scorecardClassicPlugin};
1
+ import{writeFileSync as D}from"node:fs";import L from"path";import{SCORECARD_OUTPUT_FILE_NAME as w}from"../../constants/common.js";import{mapObject as E}from"../../../utils/object/map-object.js";import{envConfig as A}from"../../config/env-config.js";import{removeLeadingSlash as j}from"../../../utils/url/remove-leading-slash.js";import{combineUrls as O}from"@redocly/theme/core/utils";import{logger as _}from"../../tools/notifiers/logger.js";import{getRouteSlugToCatalogSlugMap as F}from"../../utils/catalog-classic/get-route-slug-to-catalog-slug-map.js";import{deepEqual as I}from"../../../utils/object/deep-equal.js";import{ensureDir as N}from"../../utils/index.js";import{getTemplatePath as q}from"./get-template-path.js";import{getAllRuleNames as U}from"./lint.js";import{getScorecardConfig as T}from"./get-scorecard-config.js";import{getScorecardSlug as k}from"./shared-utils.js";import{scorecardConfigLoader as M}from"./loaders/scorecard-config.js";import{scorecardLoader as W}from"./loaders/scorecard.js";import{computeScorecard as B}from"./compute-scorecard.js";import{telemetryTraceStep as J}from"../../../cli/telemetry/helpers/trace-step.js";const $="scorecardClassic";let u={},R={};async function ne({id:b,requiredEntitlements:P,loadersPrefix:v=""}){let p=null,y=null,h=!1;return{id:b??"scorecardClassic",requiredEntitlements:P??["scorecard"],loaders:{[`${v}scorecard-config`]:M,[`${v}scorecard`]:W},async processContent(r,l){await J("com.redocly.build.plugin.scorecardClassic",async S=>{const a=r.createTemplate($,q("./template/index.js")),g=await l.getConfig(),m=T(g),f=g?.reunite??{},i=[()=>p===null,()=>!I(u,m),()=>!I(R,f)].some(e=>e());u=m,S?.setAttribute("config",JSON.stringify(u||{})),R=f;const n=g.catalogClassic??{},c=u.levels||[];if(c.length<1)throw Error("Invalid configuration of levels config");i&&(p=await B({actions:r,context:l,scorecardConfig:u,reuniteConfig:R}));const{data:{configs:o}}=await l.cache.load("",`${v}scorecard-config`),{perLevel:d,all:s}=U(o);y={levelNames:c.map(e=>e.name),rules:s,rulesPerLevel:d};for(const[e,t]of Object.entries(n)){const C=O(t.slug,"scorecard/");r.addRoute({duplicateInAllLocales:!0,slug:C,fsPath:O(t.slug,"scorecard/"),templateId:a,hasClientRoutes:!0,excludeFromSidebar:!0,serverPropsGetterIds:[],sharedData:[{id:"scorecard",key:"scorecard"},{key:"catalog",id:"catalog-"+e}],getNavText:()=>Promise.resolve(t.title||"API design scorecard"),getStaticData:async()=>({props:{catalogId:e,catalogConfig:{...t,items:void 0},scorecardConfig:u,scorecardInfo:y}})})}})},afterRoutesCreated:async(r,l)=>{const S=await l.getConfig(),a=S.catalogClassic??{},g=T(S);if(Object.keys(a).length){const i=Object.keys(a).length>1?await F(r,l,a):null,n={};for(const[c,o]of Object.entries(p||{})){const d=r.getRouteByFsPath(c),s=d?.slug;if(s){if(d&&!g.ignoreMetadata){const e=i?i.get(s)??Object.values(a)[0].slug:Object.values(a)[0].slug,t=O(e,"scorecard/");d.metadata={...d.metadata,scorecardStatus:o.status,scorecardLevel:o.scorecardLevel,scorecardLevelIdx:o.scorecardLevelIdx,scorecardLevels:E(o.levels,C=>({uniqueErrors:C.uniqueErrors,uniqueWarnings:C.uniqueWarnings})),scoreCardSlug:t+"apis/"+encodeURIComponent(j(s))}}if(n[s]={...o,levels:E(o.levels,e=>({...e,problems:e.problems.map(t=>({ruleId:t.ruleId,severity:t.severity}))}))},!h){const e=L.resolve(r.outdir,"_scorecard",k(s));D(N(e),JSON.stringify(o))}}}await r.createSharedData("scorecard",n)}const m={};for(const[i,n]of Object.entries(p||{})){const c=r.getRouteByFsPath(i)?.slug;c&&(m[c]=n)}const f=A.REDOCLY_METADATA_OUTPUT_FOLDER;!h&&f&&(_.info("Writing scorecard data..."),D(L.join(f,w),JSON.stringify({scorecardData:m,...y}))),h=!0}}}export{ne as scorecardClassicPlugin};