@redocly/realm 0.136.0-next.0 → 0.136.0-next.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (535) hide show
  1. package/CHANGELOG.md +202 -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/ejectComponent.d.ts +1 -1
  6. package/dist/cli/eject/ejectTheme.d.ts +1 -1
  7. package/dist/cli/eject/resolveEjectParams.js +1 -1
  8. package/dist/cli/eject/themeOperations.d.ts +2 -2
  9. package/dist/cli/stats/collectors/openapi/index.js +1 -1
  10. package/dist/cli/stats/index.js +1 -1
  11. package/dist/client/App.js +1 -1
  12. package/dist/client/ErrorBoundary.js +1 -1
  13. package/dist/client/TestProvider.d.ts +1 -1
  14. package/dist/client/TestProvider.js +1 -1
  15. package/dist/client/api-docs-builder-entry.d.ts +3 -0
  16. package/dist/client/api-docs-builder-entry.js +1 -0
  17. package/dist/client/app/ConditionalLink.d.ts +1 -1
  18. package/dist/client/app/Feedback/useSubmitFeedback.js +1 -1
  19. package/dist/client/app/Sidebar/Sidebar.js +3 -3
  20. package/dist/client/app/Sidebar/helpers/hide-empty-separators.d.ts +13 -0
  21. package/dist/client/app/Sidebar/helpers/hide-empty-separators.js +1 -0
  22. package/dist/client/app/Sidebar/useActions.js +1 -1
  23. package/dist/client/app/Sidebar/utils.js +1 -1
  24. package/dist/client/app/hooks/catalog/useCatalogFilter.d.ts +1 -1
  25. package/dist/client/app/hooks/catalog/useCatalogViewMode.js +1 -1
  26. package/dist/client/app/hooks/catalog/useFetchCatalogEntities.d.ts +1 -1
  27. package/dist/client/app/hooks/catalog/useFetchCatalogEntities.js +1 -1
  28. package/dist/client/app/hooks/catalog/useFetchCatalogEntitiesRelations.d.ts +2 -2
  29. package/dist/client/app/hooks/catalog/useFetchCatalogEntitiesRelations.js +1 -1
  30. package/dist/client/app/hooks/catalog/useFetchCatalogEntityRevisions.d.ts +1 -1
  31. package/dist/client/app/hooks/catalog/useSearchTracker.d.ts +2 -5
  32. package/dist/client/app/hooks/catalog/useSearchTracker.js +1 -1
  33. package/dist/client/app/hooks/codeHighlight/useCodeHighlight.d.ts +1 -6
  34. package/dist/client/app/hooks/codeHighlight/useCodeHighlight.js +1 -1
  35. package/dist/client/app/hooks/index.d.ts +1 -0
  36. package/dist/client/app/hooks/index.js +1 -1
  37. package/dist/client/app/hooks/useAutoScroll.js +1 -1
  38. package/dist/client/app/hooks/useUserClaims.js +1 -1
  39. package/dist/client/app/l10n/hooks/index.d.ts +1 -0
  40. package/dist/client/app/l10n/hooks/index.js +1 -1
  41. package/dist/client/app/l10n/hooks/useTranslate.js +1 -1
  42. package/dist/client/app/l10n/hooks/useTranslationKeys.d.ts +2 -0
  43. package/dist/client/app/l10n/hooks/useTranslationKeys.js +1 -0
  44. package/dist/client/app/l10n/initL10n.js +1 -1
  45. package/dist/client/app/markdoc/custom-components/openapi/json-schema.d.ts +1 -1
  46. package/dist/client/app/markdoc/custom-components/openapi/json-schema.js +1 -1
  47. package/dist/client/app/markdoc/custom-components/openapi/openapi-code-sample.d.ts +1 -5
  48. package/dist/client/app/markdoc/custom-components/openapi/openapi-code-sample.js +1 -1
  49. package/dist/client/app/markdoc/custom-components/openapi/openapi-example.js +1 -1
  50. package/dist/client/app/markdoc/custom-components/openapi/openapi-response-sample.js +1 -1
  51. package/dist/client/app/markdoc/custom-components/openapi/replay-openapi.d.ts +8 -24
  52. package/dist/client/app/markdoc/custom-components/openapi/replay-openapi.js +1 -1
  53. package/dist/client/app/markdoc/hooks/use-store.d.ts +8 -6
  54. package/dist/client/app/markdoc/utils/build-replay-operation-source-map.d.ts +20 -0
  55. package/dist/client/app/markdoc/utils/build-replay-operation-source-map.js +1 -0
  56. package/dist/client/app/markdoc/utils/find-api-item.d.ts +15 -0
  57. package/dist/client/app/markdoc/utils/find-api-item.js +1 -0
  58. package/dist/client/app/markdoc/utils/find-code-sample-panel.d.ts +11 -0
  59. package/dist/client/app/markdoc/utils/find-code-sample-panel.js +1 -0
  60. package/dist/client/app/markdoc/utils/find-openapi-response-samples.d.ts +15 -0
  61. package/dist/client/app/markdoc/utils/find-openapi-response-samples.js +1 -0
  62. package/dist/client/app/markdoc/utils/openapi-panel-entry.d.ts +18 -0
  63. package/dist/client/app/markdoc/utils/openapi-panel-entry.js +1 -0
  64. package/dist/client/app/pages/DevLogin/DevLoginForm.d.ts +1 -1
  65. package/dist/client/app/useGlobalData.d.ts +1 -1
  66. package/dist/client/app/usePreloadHistory.d.ts +2 -2
  67. package/dist/client/app/usePreloadHistory.js +1 -1
  68. package/dist/client/app/utils/loadAndNavigate.d.ts +1 -1
  69. package/dist/client/app/utils/loadAndNavigate.js +1 -1
  70. package/dist/client/app/utils/resolveRouteBySlug.js +1 -1
  71. package/dist/client/app/utils/same-resolved-route.d.ts +5 -0
  72. package/dist/client/app/utils/same-resolved-route.js +1 -0
  73. package/dist/client/browser-entry.js +2 -2
  74. package/dist/client/providers/page-data/hooks.d.ts +2 -2
  75. package/dist/client/providers/post-message/PostMessageProvider.js +1 -1
  76. package/dist/client/providers/post-message/use-post-message.d.ts +1 -1
  77. package/dist/client/providers/theme/ThemeDataProvider.js +1 -1
  78. package/dist/client/runtime/loader.js +1 -1
  79. package/dist/client/templates/api-docs/helpers.d.ts +10 -0
  80. package/dist/client/templates/api-docs/helpers.js +1 -0
  81. package/dist/client/templates/api-docs/template.d.ts +17 -0
  82. package/dist/client/templates/api-docs/template.js +14 -0
  83. package/dist/client/templates/openapi-docs/helpers.d.ts +1 -1
  84. package/dist/client/templates/openapi-docs/helpers.js +2 -2
  85. package/dist/client/types/sidebar.d.ts +0 -1
  86. package/dist/client/utils/utils.d.ts +0 -2
  87. package/dist/client/utils/utils.js +1 -1
  88. package/dist/constants/common.d.ts +14 -1
  89. package/dist/constants/common.js +1 -1
  90. package/dist/constants/l10n/langs/ar.js +1 -1
  91. package/dist/constants/l10n/langs/de.js +1 -1
  92. package/dist/constants/l10n/langs/en.js +1 -1
  93. package/dist/constants/l10n/langs/es.js +1 -1
  94. package/dist/constants/l10n/langs/fr.js +1 -1
  95. package/dist/constants/l10n/langs/hi.js +1 -1
  96. package/dist/constants/l10n/langs/it.js +1 -1
  97. package/dist/constants/l10n/langs/ja.js +1 -1
  98. package/dist/constants/l10n/langs/ko.js +1 -1
  99. package/dist/constants/l10n/langs/pl.js +1 -1
  100. package/dist/constants/l10n/langs/pt-BR.js +1 -1
  101. package/dist/constants/l10n/langs/pt.js +1 -1
  102. package/dist/constants/l10n/langs/ru.js +1 -1
  103. package/dist/constants/l10n/langs/uk.js +1 -1
  104. package/dist/constants/l10n/langs/zh.js +1 -1
  105. package/dist/markdoc/tags/index.d.ts +48 -2
  106. package/dist/server/api-routes/execute-api-route.js +1 -1
  107. package/dist/server/api-routes/helpers/enhance-context.d.ts +3 -1
  108. package/dist/server/api-routes/helpers/enhance-context.js +1 -1
  109. package/dist/server/api-routes/helpers/is-mock-server.d.ts +2 -0
  110. package/dist/server/api-routes/helpers/is-mock-server.js +1 -0
  111. package/dist/server/api-routes/helpers/read-stream-with-size-limit.d.ts +1 -1
  112. package/dist/server/api-routes/mock-server/kv-state-store.d.ts +3 -0
  113. package/dist/server/api-routes/mock-server/kv-state-store.js +1 -0
  114. package/dist/server/api-routes/mock-server/mock-js-executor.d.ts +3 -0
  115. package/dist/server/api-routes/mock-server/mock-js-executor.js +13 -0
  116. package/dist/server/api-routes/run-api-routes-worker.d.ts +1 -1
  117. package/dist/server/api-routes/run-api-routes-worker.js +1 -1
  118. package/dist/server/config/env-config.d.ts +4 -4
  119. package/dist/server/config/env-schema.d.ts +10 -10
  120. package/dist/server/config/env-schemas/catalog.d.ts +3 -0
  121. package/dist/server/config/env-schemas/catalog.js +1 -1
  122. package/dist/server/config/env-schemas/feature-flags.d.ts +4 -8
  123. package/dist/server/config/env-schemas/feature-flags.js +1 -1
  124. package/dist/server/constants/common.d.ts +2 -0
  125. package/dist/server/constants/common.js +1 -1
  126. package/dist/server/constants/entitlements.js +1 -1
  127. package/dist/server/constants/plugins/api-docs.d.ts +3 -0
  128. package/dist/server/constants/plugins/api-docs.js +1 -0
  129. package/dist/server/esbuild/esbuild-logger.js +3 -3
  130. package/dist/server/esbuild/esbuild.js +3 -3
  131. package/dist/server/esbuild/plugins/api-docs-module-replacer/empty-check.d.ts +9 -0
  132. package/dist/server/esbuild/plugins/api-docs-module-replacer/empty-check.js +1 -0
  133. package/dist/server/esbuild/plugins/api-docs-module-replacer/empty-overlay.d.ts +2 -0
  134. package/dist/server/esbuild/plugins/api-docs-module-replacer/empty-overlay.js +1 -0
  135. package/dist/server/esbuild/plugins/api-docs-module-replacer/index.d.ts +6 -0
  136. package/dist/server/esbuild/plugins/api-docs-module-replacer/index.js +1 -0
  137. package/dist/server/persistence/cache/mappers/create-cache-db-record.d.ts +1 -1
  138. package/dist/server/persistence/file-hashes/mappers/create-file-hash-db-record.d.ts +1 -1
  139. package/dist/server/persistence/kv/mappers/create-kv-db-record.d.ts +1 -1
  140. package/dist/server/plugins/api-docs/get-server-props.d.ts +4 -0
  141. package/dist/server/plugins/api-docs/get-server-props.js +1 -0
  142. package/dist/server/plugins/api-docs/get-template-path.d.ts +2 -0
  143. package/dist/server/plugins/api-docs/get-template-path.js +1 -0
  144. package/dist/server/plugins/api-docs/import-api-docs-builder.d.ts +8 -0
  145. package/dist/server/plugins/api-docs/import-api-docs-builder.js +1 -0
  146. package/dist/server/plugins/api-docs/index.d.ts +19 -0
  147. package/dist/server/plugins/api-docs/index.js +1 -0
  148. package/dist/server/plugins/api-docs/loader.d.ts +35 -0
  149. package/dist/server/plugins/api-docs/loader.js +3 -0
  150. package/dist/server/plugins/api-docs/options.d.ts +14 -0
  151. package/dist/server/plugins/api-docs/options.js +1 -0
  152. package/dist/server/plugins/api-docs/search/get-ai-search-documents.d.ts +20 -0
  153. package/dist/server/plugins/api-docs/search/get-ai-search-documents.js +105 -0
  154. package/dist/server/plugins/api-docs/search/search-facets.d.ts +10 -0
  155. package/dist/server/plugins/api-docs/search/search-facets.js +1 -0
  156. package/dist/server/plugins/api-docs/search/search-indexer.d.ts +9 -0
  157. package/dist/server/plugins/api-docs/search/search-indexer.js +1 -0
  158. package/dist/server/plugins/api-docs/search/search-resolver.d.ts +5 -0
  159. package/dist/server/plugins/api-docs/search/search-resolver.js +1 -0
  160. package/dist/server/plugins/api-docs/spec-download.api.d.ts +4 -0
  161. package/dist/server/plugins/api-docs/spec-download.api.js +1 -0
  162. package/dist/server/plugins/api-docs/store-definition-bundles.d.ts +3 -0
  163. package/dist/server/plugins/api-docs/store-definition-bundles.js +1 -0
  164. package/dist/server/plugins/api-docs/utils/build-item-positions.d.ts +17 -0
  165. package/dist/server/plugins/api-docs/utils/build-item-positions.js +1 -0
  166. package/dist/server/plugins/api-docs/utils/build-routes-mapping.d.ts +3 -0
  167. package/dist/server/plugins/api-docs/utils/build-routes-mapping.js +1 -0
  168. package/dist/server/plugins/api-docs/utils/collect-item-routes.d.ts +12 -0
  169. package/dist/server/plugins/api-docs/utils/collect-item-routes.js +1 -0
  170. package/dist/server/plugins/api-docs/utils/decorators.d.ts +26 -0
  171. package/dist/server/plugins/api-docs/utils/decorators.js +1 -0
  172. package/dist/server/plugins/api-docs/utils/format-bundle-error.d.ts +6 -0
  173. package/dist/server/plugins/api-docs/utils/format-bundle-error.js +5 -0
  174. package/dist/server/plugins/api-docs/utils/normalize-api-version.d.ts +2 -0
  175. package/dist/server/plugins/api-docs/utils/normalize-api-version.js +1 -0
  176. package/dist/server/plugins/api-docs/utils/normalize-feedback-options.d.ts +2 -0
  177. package/dist/server/plugins/api-docs/utils/normalize-feedback-options.js +1 -0
  178. package/dist/server/plugins/api-docs/utils/relative-path-to-base-slug.d.ts +20 -0
  179. package/dist/server/plugins/api-docs/utils/relative-path-to-base-slug.js +1 -0
  180. package/dist/server/plugins/api-docs/utils/replace-file-extension.d.ts +2 -0
  181. package/dist/server/plugins/api-docs/utils/replace-file-extension.js +1 -0
  182. package/dist/server/plugins/api-docs/utils/resolve-api-doc-title.d.ts +3 -0
  183. package/dist/server/plugins/api-docs/utils/resolve-api-doc-title.js +1 -0
  184. package/dist/server/plugins/api-docs/utils/resolve-config-rbac.d.ts +10 -0
  185. package/dist/server/plugins/api-docs/utils/resolve-config-rbac.js +1 -0
  186. package/dist/server/plugins/api-docs/utils/to-relative-slug.d.ts +2 -0
  187. package/dist/server/plugins/api-docs/utils/to-relative-slug.js +1 -0
  188. package/dist/server/plugins/api-functions/index.js +1 -1
  189. package/dist/server/plugins/arazzo-docs/index.js +1 -1
  190. package/dist/server/plugins/asyncapi-docs/index.js +1 -1
  191. package/dist/server/plugins/catalog-classic/index.js +1 -1
  192. package/dist/server/plugins/catalog-entities/database/catalog-entities-diff-publisher.d.ts +27 -0
  193. package/dist/server/plugins/catalog-entities/database/catalog-entities-diff-publisher.js +12 -0
  194. package/dist/server/plugins/catalog-entities/database/catalog-entities-publisher.js +1 -12
  195. package/dist/server/plugins/catalog-entities/database/catalog-entities-revisions-pruner.d.ts +22 -0
  196. package/dist/server/plugins/catalog-entities/database/catalog-entities-revisions-pruner.js +62 -0
  197. package/dist/server/plugins/catalog-entities/database/catalog-entities-service.d.ts +5 -5
  198. package/dist/server/plugins/catalog-entities/database/consts.d.ts +5 -0
  199. package/dist/server/plugins/catalog-entities/database/consts.js +1 -1
  200. package/dist/server/plugins/catalog-entities/database/mappers/create-entity-attributes-db-record.d.ts +1 -1
  201. package/dist/server/plugins/catalog-entities/database/mappers/create-entity-db-record.d.ts +1 -1
  202. package/dist/server/plugins/catalog-entities/database/mappers/create-entity-relation-db-record-from-file-schema.d.ts +1 -1
  203. package/dist/server/plugins/catalog-entities/database/remote-publish-lock-service.d.ts +3 -3
  204. package/dist/server/plugins/catalog-entities/database/repositories/bffEntities/bff-entities-read-repository.d.ts +2 -2
  205. package/dist/server/plugins/catalog-entities/database/repositories/catalog-entities-repository.js +1 -1
  206. package/dist/server/plugins/catalog-entities/database/repositories/common/filters-repository.d.ts +1 -1
  207. package/dist/server/plugins/catalog-entities/database/repositories/common/revision-repository.d.ts +1 -1
  208. package/dist/server/plugins/catalog-entities/database/repositories/entities/entities-read-repository.d.ts +1 -1
  209. package/dist/server/plugins/catalog-entities/database/repositories/entities/entities-write-repository.d.ts +2 -2
  210. package/dist/server/plugins/catalog-entities/database/repositories/entities/entities-write-repository.js +1 -1
  211. package/dist/server/plugins/catalog-entities/database/repositories/entityAttributes/entity-attributes-write-repository.d.ts +1 -1
  212. package/dist/server/plugins/catalog-entities/database/repositories/relations/relations-read-repository.d.ts +1 -1
  213. package/dist/server/plugins/catalog-entities/extensions/extractors/api-description/arazzo-entities-extractor.js +1 -1
  214. package/dist/server/plugins/catalog-entities/extensions/extractors/api-description/asyncapi-entities-extractor.d.ts +13 -5
  215. package/dist/server/plugins/catalog-entities/extensions/extractors/api-description/asyncapi-entities-extractor.js +1 -1
  216. package/dist/server/plugins/catalog-entities/extensions/extractors/api-description/base.d.ts +5 -2
  217. package/dist/server/plugins/catalog-entities/extensions/extractors/api-description/base.js +1 -1
  218. package/dist/server/plugins/catalog-entities/extensions/extractors/api-description/graphql-entities-extractor.d.ts +6 -5
  219. package/dist/server/plugins/catalog-entities/extensions/extractors/api-description/graphql-entities-extractor.js +2 -2
  220. package/dist/server/plugins/catalog-entities/extensions/extractors/api-description/openapi-entities-extractor.d.ts +12 -5
  221. package/dist/server/plugins/catalog-entities/extensions/extractors/api-description/openapi-entities-extractor.js +1 -1
  222. package/dist/server/plugins/catalog-entities/extensions/extractors/fs-entities-extractor.d.ts +1 -1
  223. package/dist/server/plugins/catalog-entities/plugin.js +1 -1
  224. package/dist/server/plugins/catalog-entities/template/index.js +1 -1
  225. package/dist/server/plugins/catalog-entities/types/openapi.d.ts +1 -1
  226. package/dist/server/plugins/catalog-entities/utils/get-not-accessible-catalog-resources.d.ts +1 -1
  227. package/dist/server/plugins/catalog-entities/utils/openapi-component-content-extractor.d.ts +4 -4
  228. package/dist/server/plugins/catalog-entities/utils/openapi-component-content-extractor.js +1 -1
  229. package/dist/server/plugins/catalog-entities/utils/openapi-schema-resolver.d.ts +4 -3
  230. package/dist/server/plugins/catalog-entities/utils/openapi-schema-resolver.js +1 -1
  231. package/dist/server/plugins/config-parser/index.js +1 -1
  232. package/dist/server/plugins/config-parser/loaders/utils/read-and-validate-config.js +1 -1
  233. package/dist/server/plugins/create-slugify.d.ts +17 -0
  234. package/dist/server/plugins/create-slugify.js +1 -0
  235. package/dist/server/plugins/default-theme/index.js +1 -1
  236. package/dist/server/plugins/dev-onboarding/index.d.ts +1 -1
  237. package/dist/server/plugins/dev-onboarding/index.js +1 -1
  238. package/dist/server/plugins/dev-onboarding/template/components/RevokeAPIKey.d.ts +1 -1
  239. package/dist/server/plugins/dev-onboarding/template/components/RollAPIKey.d.ts +1 -1
  240. package/dist/server/plugins/entitlements/index.js +1 -1
  241. package/dist/server/plugins/graphql-docs/index.js +1 -1
  242. package/dist/server/plugins/graphql-docs/search/ai/utils.d.ts +1 -1
  243. package/dist/server/plugins/helpers/parse-partials.d.ts +3 -0
  244. package/dist/server/plugins/helpers/parse-partials.js +1 -0
  245. package/dist/server/plugins/l10n/index.js +1 -1
  246. package/dist/server/plugins/lifecycle.js +2 -2
  247. package/dist/server/plugins/markdown/attribute-resolvers/helpers/load-openapi-bundle.d.ts +5 -3
  248. package/dist/server/plugins/markdown/attribute-resolvers/helpers/load-openapi-bundle.js +1 -1
  249. package/dist/server/plugins/markdown/attribute-resolvers/resolve-json-example-ref.js +1 -1
  250. package/dist/server/plugins/markdown/attribute-resolvers/resolve-open-api-ref.js +1 -1
  251. package/dist/server/plugins/markdown/attribute-resolvers/resolve-openapi-code-samples.js +1 -1
  252. package/dist/server/plugins/markdown/attribute-resolvers/resolve-openapi-response-samples.js +1 -1
  253. package/dist/server/plugins/markdown/index.js +1 -1
  254. package/dist/server/plugins/markdown/markdoc/markdoc-options.d.ts +9 -9
  255. package/dist/server/plugins/markdown/markdoc/plugins/utils.d.ts +5 -0
  256. package/dist/server/plugins/markdown/markdoc/plugins/utils.js +1 -1
  257. package/dist/server/plugins/markdown/runtime-transform.js +1 -1
  258. package/dist/server/plugins/markdown/search/create-render-tag-fn.d.ts +2 -1
  259. package/dist/server/plugins/markdown/search/create-render-tag-fn.js +1 -1
  260. package/dist/server/plugins/markdown/search/get-ai-search-documents.js +9 -9
  261. package/dist/server/plugins/markdown/search/walk-sections.js +1 -1
  262. package/dist/server/plugins/markdown/utils/resolve-markdown-template.d.ts +1 -1
  263. package/dist/server/plugins/mcp/auth/auth-handlers.d.ts +3 -0
  264. package/dist/server/plugins/mcp/auth/auth-handlers.js +1 -1
  265. package/dist/server/plugins/mcp/codemode/capabilities/types.d.ts +1 -1
  266. package/dist/server/plugins/mcp/codemode/capabilities/utils.d.ts +1 -1
  267. package/dist/server/plugins/mcp/codemode/code-audit.d.ts +12 -0
  268. package/dist/server/plugins/mcp/codemode/code-audit.js +1 -0
  269. package/dist/server/plugins/mcp/codemode/code-execution-telemetry.d.ts +11 -0
  270. package/dist/server/plugins/mcp/codemode/code-execution-telemetry.js +1 -0
  271. package/dist/server/plugins/mcp/codemode/constants.d.ts +3 -0
  272. package/dist/server/plugins/mcp/codemode/constants.js +1 -1
  273. package/dist/server/plugins/mcp/codemode/prompts.js +1 -1
  274. package/dist/server/plugins/mcp/codemode/sandbox/create-sandbox-setup.d.ts +10 -0
  275. package/dist/server/plugins/mcp/codemode/sandbox/create-sandbox-setup.js +11 -0
  276. package/dist/server/plugins/mcp/codemode/sandbox/polyfills.d.ts +2 -0
  277. package/dist/server/plugins/mcp/codemode/sandbox/{sandbox-polyfills.js → polyfills.js} +7 -8
  278. package/dist/server/plugins/mcp/codemode/tools/describe-tools.d.ts +2 -3
  279. package/dist/server/plugins/mcp/codemode/tools/execute-schema.d.ts +1 -1
  280. package/dist/server/plugins/mcp/codemode/tools/execute-schema.js +1 -1
  281. package/dist/server/plugins/mcp/codemode/tools/execute.d.ts +1 -0
  282. package/dist/server/plugins/mcp/codemode/tools/execute.js +1 -1
  283. package/dist/server/plugins/mcp/codemode/types.d.ts +0 -8
  284. package/dist/server/plugins/mcp/constants.d.ts +2 -1
  285. package/dist/server/plugins/mcp/constants.js +1 -1
  286. package/dist/server/plugins/mcp/docs-mcp/tool-schemas.d.ts +1 -0
  287. package/dist/server/plugins/mcp/docs-mcp/tool-schemas.js +1 -1
  288. package/dist/server/plugins/mcp/docs-mcp/tools/core/create-anonymous-session.d.ts +11 -0
  289. package/dist/server/plugins/mcp/docs-mcp/tools/core/create-anonymous-session.js +1 -0
  290. package/dist/server/plugins/mcp/docs-mcp/tools/graphql/constants.d.ts +4 -0
  291. package/dist/server/plugins/mcp/docs-mcp/tools/graphql/constants.js +1 -0
  292. package/dist/server/plugins/mcp/docs-mcp/tools/graphql/get-graphql-type-list.js +1 -1
  293. package/dist/server/plugins/mcp/docs-mcp/tools/graphql/get-graphql-type.js +7 -4
  294. package/dist/server/plugins/mcp/docs-mcp/tools/graphql/types.d.ts +7 -1
  295. package/dist/server/plugins/mcp/docs-mcp/tools/graphql/types.js +0 -1
  296. package/dist/server/plugins/mcp/docs-mcp/tools/graphql/utils.d.ts +5 -1
  297. package/dist/server/plugins/mcp/docs-mcp/tools/graphql/utils.js +4 -2
  298. package/dist/server/plugins/mcp/docs-mcp/tools/index.d.ts +4 -0
  299. package/dist/server/plugins/mcp/docs-mcp/tools/index.js +1 -1
  300. package/dist/server/plugins/mcp/docs-mcp/tools/openapi/constants.d.ts +2 -0
  301. package/dist/server/plugins/mcp/docs-mcp/tools/openapi/constants.js +1 -0
  302. package/dist/server/plugins/mcp/docs-mcp/tools/openapi/get-endpoint-info.js +1 -1
  303. package/dist/server/plugins/mcp/docs-mcp/tools/openapi/get-endpoints.js +1 -1
  304. package/dist/server/plugins/mcp/docs-mcp/tools/openapi/get-full-api-description.js +1 -1
  305. package/dist/server/plugins/mcp/docs-mcp/tools/openapi/get-security-schemes.js +1 -1
  306. package/dist/server/plugins/mcp/docs-mcp/tools/openapi/list-apis.js +1 -1
  307. package/dist/server/plugins/mcp/docs-mcp/tools/openapi/load-api-description.d.ts +6 -2
  308. package/dist/server/plugins/mcp/docs-mcp/tools/openapi/load-api-description.js +1 -1
  309. package/dist/server/plugins/mcp/docs-mcp/tools/openapi/types.d.ts +2 -0
  310. package/dist/server/plugins/mcp/docs-mcp/tools/openapi/utils.d.ts +2 -2
  311. package/dist/server/plugins/mcp/docs-mcp/tools/openapi/utils.js +1 -1
  312. package/dist/server/plugins/mcp/docs-mcp/utils.d.ts +3 -3
  313. package/dist/server/plugins/mcp/docs-mcp/utils.js +1 -1
  314. package/dist/server/plugins/mcp/gateway-mcp/elicitation.d.ts +28 -0
  315. package/dist/server/plugins/mcp/gateway-mcp/elicitation.js +2 -0
  316. package/dist/server/plugins/mcp/gateway-mcp/eligibility.d.ts +5 -17
  317. package/dist/server/plugins/mcp/gateway-mcp/eligibility.js +1 -1
  318. package/dist/server/plugins/mcp/gateway-mcp/fetch/allowed-hosts.d.ts +9 -9
  319. package/dist/server/plugins/mcp/gateway-mcp/fetch/allowed-hosts.js +1 -1
  320. package/dist/server/plugins/mcp/gateway-mcp/fetch/fetch-bridge.d.ts +17 -1
  321. package/dist/server/plugins/mcp/gateway-mcp/fetch/fetch-bridge.js +1 -1
  322. package/dist/server/plugins/mcp/gateway-mcp/fetch/fetch-errors.d.ts +11 -0
  323. package/dist/server/plugins/mcp/gateway-mcp/fetch/fetch-errors.js +1 -0
  324. package/dist/server/plugins/mcp/gateway-mcp/fetch/fetch-telemetry.d.ts +14 -0
  325. package/dist/server/plugins/mcp/gateway-mcp/fetch/fetch-telemetry.js +1 -0
  326. package/dist/server/plugins/mcp/gateway-mcp/fetch/normalize-path.d.ts +6 -0
  327. package/dist/server/plugins/mcp/gateway-mcp/fetch/normalize-path.js +1 -0
  328. package/dist/server/plugins/mcp/gateway-mcp/fetch/redact.d.ts +4 -0
  329. package/dist/server/plugins/mcp/gateway-mcp/fetch/redact.js +1 -0
  330. package/dist/server/plugins/mcp/gateway-mcp/fetch/ssrf-blocklist.d.ts +22 -0
  331. package/dist/server/plugins/mcp/gateway-mcp/fetch/ssrf-blocklist.js +1 -0
  332. package/dist/server/plugins/mcp/gateway-mcp/fetch/ssrf-guard.d.ts +1 -1
  333. package/dist/server/plugins/mcp/gateway-mcp/fetch/ssrf-guard.js +1 -1
  334. package/dist/server/plugins/mcp/gateway-mcp/fetch/ssrf-safe-lookup.d.ts +13 -0
  335. package/dist/server/plugins/mcp/gateway-mcp/fetch/ssrf-safe-lookup.js +1 -0
  336. package/dist/server/plugins/mcp/gateway-mcp/fetch-capability.d.ts +8 -1
  337. package/dist/server/plugins/mcp/gateway-mcp/fetch-capability.js +1 -1
  338. package/dist/server/plugins/mcp/gateway-mcp/rate-limit/apply-edge-rate-limit.d.ts +3 -0
  339. package/dist/server/plugins/mcp/gateway-mcp/rate-limit/apply-edge-rate-limit.js +1 -0
  340. package/dist/server/plugins/mcp/gateway-mcp/rate-limit/edge-limiter.d.ts +16 -0
  341. package/dist/server/plugins/mcp/gateway-mcp/rate-limit/edge-limiter.js +1 -0
  342. package/dist/server/plugins/mcp/gateway-mcp/rate-limit/ip-key.d.ts +2 -0
  343. package/dist/server/plugins/mcp/gateway-mcp/rate-limit/ip-key.js +1 -0
  344. package/dist/server/plugins/mcp/gateway-mcp/rate-limit/limits.d.ts +7 -0
  345. package/dist/server/plugins/mcp/gateway-mcp/rate-limit/limits.js +1 -0
  346. package/dist/server/plugins/mcp/gateway-mcp/rate-limit/rate-limit-telemetry.d.ts +8 -0
  347. package/dist/server/plugins/mcp/gateway-mcp/rate-limit/rate-limit-telemetry.js +1 -0
  348. package/dist/server/plugins/mcp/gateway-mcp/rate-limit/window-counter.d.ts +15 -0
  349. package/dist/server/plugins/mcp/gateway-mcp/rate-limit/window-counter.js +1 -0
  350. package/dist/server/plugins/mcp/gateway-mcp/secret-store.d.ts +24 -0
  351. package/dist/server/plugins/mcp/gateway-mcp/secret-store.js +1 -0
  352. package/dist/server/plugins/mcp/gateway-mcp/subject.d.ts +20 -0
  353. package/dist/server/plugins/mcp/gateway-mcp/subject.js +1 -0
  354. package/dist/server/plugins/mcp/gateway-mcp/upstream-auth-scheme.d.ts +18 -0
  355. package/dist/server/plugins/mcp/gateway-mcp/upstream-auth-scheme.js +1 -0
  356. package/dist/server/plugins/mcp/gateway-mcp/upstream-auth.d.ts +10 -0
  357. package/dist/server/plugins/mcp/gateway-mcp/upstream-auth.js +1 -0
  358. package/dist/server/plugins/mcp/handlers/docs-mcp-handler.js +1 -1
  359. package/dist/server/plugins/mcp/handlers/errors.d.ts +3 -3
  360. package/dist/server/plugins/mcp/handlers/errors.js +1 -1
  361. package/dist/server/plugins/mcp/handlers/handle-mcp-request.js +1 -1
  362. package/dist/server/plugins/mcp/handlers/mcp-credentials-handler.d.ts +5 -0
  363. package/dist/server/plugins/mcp/handlers/mcp-credentials-handler.js +101 -0
  364. package/dist/server/plugins/mcp/index.d.ts +1 -0
  365. package/dist/server/plugins/mcp/index.js +1 -1
  366. package/dist/server/plugins/mcp/servers/docs-server.d.ts +3 -1
  367. package/dist/server/plugins/mcp/servers/docs-server.js +1 -1
  368. package/dist/server/plugins/mcp/servers/mcp-server.d.ts +15 -8
  369. package/dist/server/plugins/mcp/servers/mcp-server.js +1 -1
  370. package/dist/server/plugins/mcp/types.d.ts +16 -20
  371. package/dist/server/plugins/mcp/utils/json-schema-validator.d.ts +9 -0
  372. package/dist/server/plugins/mcp/utils/json-schema-validator.js +1 -0
  373. package/dist/server/plugins/mcp/utils/jwt.d.ts +0 -9
  374. package/dist/server/plugins/mcp/utils/jwt.js +1 -1
  375. package/dist/server/plugins/mcp/utils/mode.d.ts +12 -2
  376. package/dist/server/plugins/mcp/utils/mode.js +1 -1
  377. package/dist/server/plugins/mcp/utils/telemetry-attributes.d.ts +8 -0
  378. package/dist/server/plugins/mcp/utils/telemetry-attributes.js +1 -0
  379. package/dist/server/plugins/mcp/utils/xmcp-utils.d.ts +1 -1
  380. package/dist/server/plugins/mcp/utils.d.ts +17 -5
  381. package/dist/server/plugins/mcp/utils.js +1 -1
  382. package/dist/server/plugins/mcp/workers/execute-mcp-tool.js +1 -1
  383. package/dist/server/plugins/mcp/workers/mcp-tool-telemetry.d.ts +10 -2
  384. package/dist/server/plugins/mcp/workers/mcp-tool-telemetry.js +1 -1
  385. package/dist/server/plugins/openapi-docs/index.js +1 -1
  386. package/dist/server/plugins/openapi-docs/search/get-ai-search-documents.js +16 -16
  387. package/dist/server/plugins/openapi-docs/utils.js +1 -1
  388. package/dist/server/plugins/pages/index.js +1 -1
  389. package/dist/server/plugins/scorecard-classic/compute-scorecard.d.ts +1 -1
  390. package/dist/server/plugins/scorecard-classic/compute-scorecard.js +4 -4
  391. package/dist/server/plugins/scorecard-classic/index.d.ts +1 -1
  392. package/dist/server/plugins/scorecard-classic/index.js +1 -1
  393. package/dist/server/plugins/scorecard-classic/template/components.d.ts +1 -1
  394. package/dist/server/plugins/scorecard-classic/template/useData.d.ts +1 -1
  395. package/dist/server/plugins/scorecards/plugin.js +1 -1
  396. package/dist/server/plugins/search/ai-indexer/prepare-semantic-documents.d.ts +1 -1
  397. package/dist/server/plugins/search/ai-indexer/prepare-semantic-documents.js +2 -2
  398. package/dist/server/plugins/search/documents/search-documents.js +1 -1
  399. package/dist/server/plugins/search/engines/flexsearch/index.js +1 -1
  400. package/dist/server/plugins/search/engines/flexsearch/search-index.js +1 -1
  401. package/dist/server/plugins/search/engines/search-engine.d.ts +1 -1
  402. package/dist/server/plugins/search/engines/typesense/index.js +1 -1
  403. package/dist/server/plugins/search/index.js +1 -1
  404. package/dist/server/plugins/search/llmstxt/index.d.ts +1 -1
  405. package/dist/server/plugins/search/llmstxt/index.js +4 -4
  406. package/dist/server/plugins/sidebars/index.d.ts +1 -1
  407. package/dist/server/plugins/sidebars/index.js +1 -1
  408. package/dist/server/plugins/sitemap/index.js +1 -1
  409. package/dist/server/plugins/sso/index.js +1 -1
  410. package/dist/server/providers/database/database-path-generator.d.ts +2 -2
  411. package/dist/server/providers/database/utils/storage-limit-validator.d.ts +1 -1
  412. package/dist/server/sandbox/constants/host-functions.d.ts +3 -0
  413. package/dist/server/sandbox/constants/host-functions.js +1 -0
  414. package/dist/server/sandbox/constants/sandbox.d.ts +6 -0
  415. package/dist/server/sandbox/constants/sandbox.js +1 -0
  416. package/dist/server/sandbox/sandbox.d.ts +8 -0
  417. package/dist/server/sandbox/sandbox.js +3 -0
  418. package/dist/server/sandbox/types.d.ts +25 -0
  419. package/dist/server/sandbox/utils/eval-guest-code.d.ts +15 -0
  420. package/dist/server/sandbox/utils/eval-guest-code.js +1 -0
  421. package/dist/server/sandbox/utils/execution-budget.d.ts +12 -0
  422. package/dist/server/sandbox/utils/execution-budget.js +1 -0
  423. package/dist/server/sandbox/utils/setup-host-functions.d.ts +18 -0
  424. package/dist/server/sandbox/utils/setup-host-functions.js +5 -0
  425. package/dist/server/ssr/render.js +1 -1
  426. package/dist/server/ssr/server-side-props/get-default-static-props.d.ts +1 -1
  427. package/dist/server/ssr/server-side-props/get-server-props-from-user-handler.d.ts +1 -1
  428. package/dist/server/ssr/template.d.ts +1 -1
  429. package/dist/server/ssr/utils.d.ts +1 -0
  430. package/dist/server/ssr/utils.js +5 -5
  431. package/dist/server/store.d.ts +2 -6
  432. package/dist/server/store.js +1 -1
  433. package/dist/server/tools/notifiers/logger.js +1 -1
  434. package/dist/server/tools/notifiers/reporter.js +6 -6
  435. package/dist/server/types/plugins/common.d.ts +4 -6
  436. package/dist/server/types/plugins/markdown.d.ts +1 -3
  437. package/dist/server/types/plugins/search.d.ts +1 -0
  438. package/dist/server/utils/catalog-classic/get-route-slug-to-catalog-slug-map.test.js +1 -1
  439. package/dist/server/utils/crypto/constants.d.ts +5 -0
  440. package/dist/server/utils/crypto/constants.js +1 -0
  441. package/dist/server/utils/crypto/decrypt-aes-gcm.d.ts +6 -0
  442. package/dist/server/utils/crypto/decrypt-aes-gcm.js +1 -0
  443. package/dist/server/utils/crypto/decrypt-claim-value.d.ts +6 -0
  444. package/dist/server/utils/crypto/decrypt-claim-value.js +1 -0
  445. package/dist/server/utils/crypto/derive-key.d.ts +5 -0
  446. package/dist/server/utils/crypto/derive-key.js +1 -0
  447. package/dist/server/utils/crypto/encrypt-aes-gcm.d.ts +6 -0
  448. package/dist/server/utils/crypto/encrypt-aes-gcm.js +1 -0
  449. package/dist/server/utils/crypto/encrypt-claim-value.d.ts +6 -0
  450. package/dist/server/utils/crypto/encrypt-claim-value.js +1 -0
  451. package/dist/server/utils/fetch-with-client.d.ts +10 -0
  452. package/dist/server/utils/fetch-with-client.js +1 -0
  453. package/dist/server/utils/l10n/get-build-translate-context.d.ts +7 -0
  454. package/dist/server/utils/l10n/get-build-translate-context.js +1 -0
  455. package/dist/server/utils/llmstxt/agent-feedback-llms-footer.js +1 -1
  456. package/dist/server/utils/rbac.d.ts +4 -0
  457. package/dist/server/utils/rbac.js +1 -1
  458. package/dist/server/utils/report-all-errors.js +1 -1
  459. package/dist/server/utils/sandbox-context.d.ts +18 -0
  460. package/dist/server/utils/sandbox-context.js +1 -0
  461. package/dist/server/utils/shared-data.js +1 -1
  462. package/dist/server/web-server/auth.d.ts +34 -4
  463. package/dist/server/web-server/auth.js +3 -3
  464. package/dist/server/web-server/handle-api-route-request.js +1 -1
  465. package/dist/server/web-server/middleware/apiKeyMiddleware.js +1 -1
  466. package/dist/server/web-server/middleware/catalogAuthMiddleware.d.ts +1 -1
  467. package/dist/server/web-server/middleware/catalogAuthMiddleware.js +1 -1
  468. package/dist/server/web-server/middleware/telemetry-middleware.js +1 -1
  469. package/dist/server/web-server/routes/api-routes/api-routes.js +1 -1
  470. package/dist/server/web-server/routes/ask-ai.js +1 -1
  471. package/dist/server/web-server/routes/auth.js +1 -1
  472. package/dist/server/web-server/routes/catalog/bff-catalog-related-entities.js +1 -1
  473. package/dist/server/web-server/routes/catalog/bff-catalog-revisions.js +1 -1
  474. package/dist/server/web-server/routes/catalog/bff-catalog.js +1 -1
  475. package/dist/server/web-server/routes/catalog/catalog-relations.js +1 -1
  476. package/dist/server/web-server/routes/catalog/catalog.js +1 -1
  477. package/dist/server/web-server/routes/catalog/helpers/has-access-to-entity.d.ts +1 -1
  478. package/dist/server/web-server/routes/catalog/helpers/upsert-pages-stats.d.ts +1 -1
  479. package/dist/server/web-server/routes/catalog/helpers/upsert-pages-stats.js +1 -1
  480. package/dist/server/web-server/routes/dynamic-route.js +1 -1
  481. package/dist/server/web-server/routes/feedback.d.ts +1 -1
  482. package/dist/server/web-server/routes/feedback.js +1 -1
  483. package/dist/server/web-server/routes/helpers/process-redirects.d.ts +1 -1
  484. package/dist/server/web-server/routes/mcp-routes/a2a.js +1 -1
  485. package/dist/server/web-server/routes/mcp-routes/agent-card.js +1 -1
  486. package/dist/server/web-server/routes/mcp-routes/mcp-oauth.d.ts +10 -6
  487. package/dist/server/web-server/routes/mcp-routes/mcp-oauth.js +1 -1
  488. package/dist/server/web-server/routes/mcp-routes/mcp-routes.js +1 -1
  489. package/dist/server/web-server/routes/mcp-routes/mcp-server-card.js +1 -1
  490. package/dist/server/web-server/routes/mcp-routes/utils/build-agent-card.d.ts +1 -1
  491. package/dist/server/web-server/routes/page-data.js +1 -1
  492. package/dist/server/web-server/routes/resolve-route.js +1 -1
  493. package/dist/server/web-server/routes/search.js +1 -1
  494. package/dist/server/web-server/routes/semantic-search.js +1 -1
  495. package/dist/server/web-server/routes/skills/skill-markdown.js +1 -1
  496. package/dist/server/web-server/routes/skills/skills-index.js +1 -1
  497. package/dist/server/web-server/utils/prepare-list-response.d.ts +1 -1
  498. package/dist/server/workers/api-routes-worker-pool.js +1 -1
  499. package/dist/server/workers/mcp-tool-worker-pool.js +1 -1
  500. package/dist/server/workers/worker-pool.d.ts +1 -0
  501. package/dist/server/workers/worker-pool.js +1 -1
  502. package/dist/types/entitlements.d.ts +6 -1
  503. package/dist/types/markdoc.d.ts +2 -1
  504. package/dist/utils/l10n/build-i18n-config.d.ts +24 -0
  505. package/dist/utils/l10n/build-i18n-config.js +1 -0
  506. package/dist/utils/l10n/create-translate.d.ts +19 -0
  507. package/dist/utils/l10n/create-translate.js +1 -0
  508. package/dist/utils/url/get-shared-data-fetch-url.d.ts +17 -0
  509. package/dist/utils/url/get-shared-data-fetch-url.js +1 -0
  510. package/dist/utils/url/parse-preview-url.d.ts +22 -0
  511. package/dist/utils/url/parse-preview-url.js +1 -0
  512. package/package.json +16 -15
  513. package/dist/markdoc/helpers/get-operation/get-operation-info-by-id.d.ts +0 -4
  514. package/dist/markdoc/helpers/get-operation/get-operation-info-by-id.js +0 -1
  515. package/dist/markdoc/helpers/get-operation/get-operation-info-by-pointer.d.ts +0 -4
  516. package/dist/markdoc/helpers/get-operation/get-operation-info-by-pointer.js +0 -1
  517. package/dist/markdoc/helpers/get-operation/get-operation.d.ts +0 -14
  518. package/dist/markdoc/helpers/get-operation/get-operation.js +0 -1
  519. package/dist/markdoc/helpers/get-operation/index.d.ts +0 -4
  520. package/dist/markdoc/helpers/get-operation/index.js +0 -1
  521. package/dist/markdoc/helpers/get-operation/types/index.d.ts +0 -4
  522. package/dist/markdoc/helpers/get-operation/types/operation-identifier.d.ts +0 -5
  523. package/dist/markdoc/helpers/get-operation/types/operation-identifier.js +0 -0
  524. package/dist/markdoc/helpers/get-operation/types/operation-info.d.ts +0 -6
  525. package/dist/markdoc/helpers/get-operation/types/operation-info.js +0 -0
  526. package/dist/markdoc/helpers/get-operation/types/operation-parameters.d.ts +0 -3
  527. package/dist/markdoc/helpers/get-operation/types/operation-parameters.js +0 -0
  528. package/dist/server/plugins/markdown/attribute-resolvers/helpers/get-media-content-samples.d.ts +0 -4
  529. package/dist/server/plugins/markdown/attribute-resolvers/helpers/get-media-content-samples.js +0 -1
  530. package/dist/server/plugins/mcp/codemode/sandbox/sandbox-polyfills.d.ts +0 -3
  531. package/dist/server/plugins/mcp/codemode/sandbox/sandbox.d.ts +0 -3
  532. package/dist/server/plugins/mcp/codemode/sandbox/sandbox.js +0 -15
  533. package/dist/server/plugins/mcp/handlers/sse-keepalive.d.ts +0 -15
  534. package/dist/server/plugins/mcp/handlers/sse-keepalive.js +0 -3
  535. /package/dist/{markdoc/helpers/get-operation/types/index.js → server/sandbox/types.js} +0 -0
@@ -1,12 +1,12 @@
1
- import"../node-crypto-polyfill.js";import{DOMParser as P}from"@xmldom/xmldom";import{SignedXml as q}from"xml-crypto";import K from"xpath";import{deflateSync as Y,inflateSync as Q}from"fflate";import{createHash as X}from"crypto";import{ulid as Z}from"ulid";import{AuthProviderType as u,DEFAULT_TEAM_CLAIM_NAME as N}from"@redocly/config";import{AUTH_URL as G,JWT_SECRET_KEY as C}from"../constants/common.js";import{envConfig as ee}from"../config/env-config.js";import{getPathPrefix as te,withPathPrefix as ne}from"@redocly/theme/core/utils";import{ServerRoutes as R}from"../../constants/api.js";import{AuthCookieNames as A,DEFAULT_AUTHENTICATED_TEAM as re,REQUIRED_OIDC_SCOPES as b}from"../../constants/common.js";import{appendQueryParams as oe}from"../../utils/url/append-query-params.js";import{parseHttpsUrl as v}from"../../utils/url/parse-https-url.js";import{logger as ae}from"../tools/notifiers/logger.js";import{randomString as se}from"../utils/crypto/random-string.js";import{randomUUID as U}from"../utils/crypto/random-uuid.js";import{AlgorithmTypes as w,JwtTokenExpired as ie}from"./jwt/types.js";import*as f from"./jwt/jwt.js";import{parseTeamClaimToArray as ce}from"../utils/index.js";import{arrayBufferToBase64 as ue,decodeBase64 as j,encodeBase64URL as le,urlSafeBase64 as V}from"./jwt/encode.js";import{formatSamlCertificate as de}from"./utils/format-saml-certificate.js";function $(e){return e?.type===u.OIDC}function me(e){return e?.type===u.SAML2}async function Ze(e,t){if($(t))return pe(e,t);if(me(t))return fe(e,t)}async function pe(e,t){const n=await z(e,t),r=new Set((t.scopes||[]).concat(b)),o=t.authorizationRequestCustomParams||{};return{type:u.OIDC,idpId:e,name:"OAuth provider",authorizationEndpoint:n.authorization_endpoint,clientId:t.clientId,responseType:"code",scope:Array.from(r).join(" "),extraParams:o,pkce:t.pkce}}function fe(e,t){return{type:u.SAML2,idpId:e,name:"SAML2 provider",ssoUrl:t.ssoUrl,issuerId:t.issuerId,entityId:t.entityId||t.issuerId}}async function Ge(e,t,n,r,o={}){const a=new Set((r.scopes||[]).concat(b));return await fetch(e,{method:"POST",body:new URLSearchParams({client_id:r.clientId,scope:Array.from(a).join(" "),code:t,redirect_uri:H(n),grant_type:"authorization_code",...r.clientSecret?{client_secret:r.clientSecret}:{},...o}).toString(),headers:{"Content-Type":"application/x-www-form-urlencoded",Accept:"application/json"}}).then(s=>s.json())}function he(e,{authorizationEndpoint:t,clientId:n,responseType:r,scope:o,extraParams:a,idpId:s,pkce:l},m,g,p){if(!t||!n||!r||!o)return{loginUrl:void 0};const i=new URL(t),h=p?.redirectUriOverride??`${e}${ne(R.OIDC_CALLBACK)}`,_={state:U(),idpId:s,redirectUri:h,redirectTo:m,branch:p?.branchOverride??ye(e),inviteCode:g,source:p?.sourceOverride??"portal",uiLocales:p?.uiLocales},y={};if(l){const d=V(se(50)),x=V(X("sha256").update(d).digest("base64")),I="S256";i.searchParams.append("code_challenge",x),i.searchParams.append("code_challenge_method",I),y.code_verifier={value:d,options:{secure:!0,httpOnly:!0,expires:new Date(Date.now()+1e3*60*10),path:te()||"/"}}}i.searchParams.append("client_id",n),i.searchParams.append("scope",o),i.searchParams.append("response_type",r),i.searchParams.append("redirect_uri",H(h)),i.searchParams.append("state",le(JSON.stringify(_))),p?.uiLocales&&i.searchParams.append("ui_locales",p.uiLocales);for(const d in a)a[d]!==void 0&&i.searchParams.append(d,a[d]);return{loginUrl:i.toString(),cookies:y}}function et(e,t,n,r){const o=new URL(e);return o.searchParams.append("post_logout_redirect_uri",t),r&&o.searchParams.append("state",r),o.searchParams.append("id_token_hint",n),o.toString()}async function tt(e){const t=Math.floor(Date.now()/1e3),n=t+(e.ttlSec??600);return f.sign({type:"mcp_auth_code",client_id:e.clientId,redirect_uri:e.redirectUri,id_token:e.idToken,...e.idpAccessToken?{idp_access_token:e.idpAccessToken}:{},...e.codeChallenge?{code_challenge:e.codeChallenge}:{},...e.codeChallengeMethod?{code_challenge_method:e.codeChallengeMethod}:{},iat:t,exp:n},C,w.HS256)}async function nt(e){await f.verify(e,C,w.HS256);const{payload:t}=f.decode(e);if(t.type!=="mcp_auth_code")throw new Error("Invalid authorization code type");if(!t.client_id||!t.redirect_uri)throw new Error("Authorization code missing required claims");if(typeof t.exp=="number"&&Date.now()>=t.exp*1e3)throw new Error("Authorization code expired");return t}function rt(e){const t=e||Z(),n=t.startsWith("mcp_")?t:`mcp_${t}`;return{id:n,object:"mcpSession",uri:`urn:redocly:realm:mcp:session:${n}`}}function H(e){const t=v(e);if(!t)return e;const n=we(t.hostname);if(n)return t.hostname=`previewauth--${n.previewBranch}${n.after}`,B(e,t);const r=F(t.hostname);return r?(t.hostname=`${r.projectSlug}.previewauth.${r.after}`,B(e,t)):e}function ye(e){const t=v(e);if(t)return F(t.hostname)?.previewBranch}function B(e,t){return e.replace(/^https:\/\/[^/?#]+/i,`https://${t.host}`)}function F(e){const t=e.split(".preview.",2);if(t.length<2)return null;const[n,r]=t,o=n.indexOf("--");if(o===-1)return null;const a=n.slice(0,o),s=n.slice(o+2);return!a||!s||s.includes(".")?null:{projectSlug:a,previewBranch:s,after:r}}function we(e){const t=e.indexOf("."),n=t===-1?e:e.slice(0,t);if(!n.startsWith("preview-"))return null;const r=n.indexOf("--");if(r===-1)return null;const o=n.slice(r+2);if(!o)return null;const a=t===-1?"":e.slice(t);return{previewBranch:o,after:a}}function Se(e){return e.type===u.OIDC}function Ae(e){return e.type===u.SAML2}function ot(e,t,n,r,o){return Se(e)?he(t,e,n,r,{uiLocales:o}):Ae(e)?ge(t,e,n,r,o):{}}function ge(e,t,n,r,o){const s=`<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
1
+ import"../node-crypto-polyfill.js";import{DOMParser as M}from"@xmldom/xmldom";import{SignedXml as Y}from"xml-crypto";import G from"xpath";import{deflateSync as Q,inflateSync as X}from"fflate";import{createHash as Z}from"crypto";import{ulid as ee}from"ulid";import{AuthProviderType as u,DEFAULT_TEAM_CLAIM_NAME as P}from"@redocly/config";import{AUTH_URL as te,JWT_SECRET_KEY as y}from"../constants/common.js";import{envConfig as ne}from"../config/env-config.js";import{decryptClaimValue as re}from"../utils/crypto/decrypt-claim-value.js";import{getPathPrefix as oe,withPathPrefix as se}from"@redocly/theme/core/utils";import{ServerRoutes as b}from"../../constants/api.js";import{AuthCookieNames as A,DEFAULT_AUTHENTICATED_TEAM as ae,REQUIRED_OIDC_SCOPES as v}from"../../constants/common.js";import{appendQueryParams as ie}from"../../utils/url/append-query-params.js";import{parsePreviewUrl as N}from"../../utils/url/parse-preview-url.js";import{logger as ce}from"../tools/notifiers/logger.js";import{randomString as ue}from"../utils/crypto/random-string.js";import{randomUUID as U}from"../utils/crypto/random-uuid.js";import{AlgorithmTypes as h,JwtTokenExpired as de}from"./jwt/types.js";import*as d from"./jwt/jwt.js";import{parseTeamClaimToArray as le}from"../utils/index.js";import{arrayBufferToBase64 as me,decodeBase64 as j,encodeBase64URL as pe,urlSafeBase64 as V}from"./jwt/encode.js";import{formatSamlCertificate as fe}from"./utils/format-saml-certificate.js";function $(e){return e?.type===u.OIDC}function he(e){return e?.type===u.SAML2}async function rt(e,t){if($(t))return ye(e,t);if(he(t))return we(e,t)}async function ye(e,t){const n=await q(e,t),r=new Set((t.scopes||[]).concat(v)),o=t.authorizationRequestCustomParams||{};return{type:u.OIDC,idpId:e,name:"OAuth provider",authorizationEndpoint:n.authorization_endpoint,clientId:t.clientId,responseType:"code",scope:Array.from(r).join(" "),extraParams:o,pkce:t.pkce}}function we(e,t){return{type:u.SAML2,idpId:e,name:"SAML2 provider",ssoUrl:t.ssoUrl,issuerId:t.issuerId,entityId:t.entityId||t.issuerId}}function B(e){return Array.from(new Set((e.scopes||[]).concat(v))).join(" ")}async function H(e,t,n){return await fetch(e,{method:"POST",body:new URLSearchParams({client_id:t.clientId,...t.clientSecret?{client_secret:t.clientSecret}:{},...n}).toString(),headers:{"Content-Type":"application/x-www-form-urlencoded",Accept:"application/json"}}).then(r=>r.json())}async function ot(e,t,n,r,o={}){return await H(e,r,{scope:B(r),code:t,redirect_uri:F(n),grant_type:"authorization_code",...o})}async function st(e,t,n){return await H(e,n,{scope:B(n),grant_type:"refresh_token",refresh_token:t})}function Se(e,{authorizationEndpoint:t,clientId:n,responseType:r,scope:o,extraParams:s,idpId:a,pkce:l},p,x,f){if(!t||!n||!r||!o)return{loginUrl:void 0};const i=new URL(t),w=f?.redirectUriOverride??`${e}${se(b.OIDC_CALLBACK)}`,g={state:U(),idpId:a,redirectUri:w,redirectTo:p,branch:f?.branchOverride??_e(e),inviteCode:x,source:f?.sourceOverride??"portal",uiLocales:f?.uiLocales},S={};if(l){const m=V(ue(50)),k=V(Z("sha256").update(m).digest("base64")),I="S256";i.searchParams.append("code_challenge",k),i.searchParams.append("code_challenge_method",I),S.code_verifier={value:m,options:{secure:!0,httpOnly:!0,expires:new Date(Date.now()+1e3*60*10),path:oe()||"/"}}}i.searchParams.append("client_id",n),i.searchParams.append("scope",o),i.searchParams.append("response_type",r),i.searchParams.append("redirect_uri",F(w)),i.searchParams.append("state",pe(JSON.stringify(g))),f?.uiLocales&&i.searchParams.append("ui_locales",f.uiLocales);for(const m in s)s[m]!==void 0&&i.searchParams.append(m,s[m]);return{loginUrl:i.toString(),cookies:S}}function at(e,t,n,r){const o=new URL(e);return o.searchParams.append("post_logout_redirect_uri",t),r&&o.searchParams.append("state",r),o.searchParams.append("id_token_hint",n),o.toString()}async function it(e){const t=Math.floor(Date.now()/1e3),n=t+(e.ttlSec??600);return d.sign({type:"mcp_auth_code",client_id:e.clientId,redirect_uri:e.redirectUri,id_token:e.idToken,...e.idpId?{idp_id:e.idpId}:{},...e.idpAccessTokenEnc?{idp_access_token_enc:e.idpAccessTokenEnc}:{},...e.idpRefreshTokenEnc?{idp_refresh_token_enc:e.idpRefreshTokenEnc}:{},...e.codeChallenge?{code_challenge:e.codeChallenge}:{},...e.codeChallengeMethod?{code_challenge_method:e.codeChallengeMethod}:{},iat:t,exp:n},y,h.HS256)}async function ct(e){await d.verify(e,y,h.HS256);const{payload:t}=d.decode(e);if(t.type!=="mcp_auth_code")throw new Error("Invalid authorization code type");if(!t.client_id||!t.redirect_uri)throw new Error("Authorization code missing required claims");if(typeof t.exp=="number"&&Date.now()>=t.exp*1e3)throw new Error("Authorization code expired");return t}async function ut(e){const t=Math.floor(Date.now()/1e3);return d.sign({type:"mcp_refresh_token",client_id:e.clientId,...e.idpId?{idp_id:e.idpId}:{},claims:e.claims,...e.idpAccessTokenEnc?{idp_access_token_enc:e.idpAccessTokenEnc}:{},...e.idpRefreshTokenEnc?{idp_refresh_token_enc:e.idpRefreshTokenEnc}:{},session_exp:e.sessionExp,iat:t,exp:e.sessionExp},y,h.HS256)}async function dt(e){await d.verify(e,y,h.HS256);const{payload:t}=d.decode(e);if(t.type!=="mcp_refresh_token")throw new Error("Invalid refresh token type");if(!t.client_id||typeof t.claims!="object"||t.claims===null)throw new Error("Refresh token missing required claims");if(typeof t.session_exp!="number")throw new Error("Refresh token missing session expiry");return t}function lt(e){const t=e||ee(),n=t.startsWith("mcp_")?t:`mcp_${t}`;return{id:n,object:"mcpSession",uri:`urn:redocly:realm:mcp:session:${n}`}}function F(e){const t=N(e);if(!t)return e;const n=Ae(t.hostname);if(n)return t.hostname=`previewauth--${n.previewBranch}${n.after}`,z(e,t);const r=W(t.hostname);return r?(t.hostname=`${r.projectSlug}.previewauth.${r.after}`,z(e,t)):e}function _e(e){const t=N(e);if(t)return W(t.hostname)?.previewBranch}function z(e,t){return e.replace(/^https?:\/\/[^/?#]+/i,`${t.protocol}//${t.host}`)}function W(e){const t=e.split(".preview.",2);if(t.length<2)return null;const[n,r]=t,o=n.indexOf("--");if(o===-1)return null;const s=n.slice(0,o),a=n.slice(o+2);return!s||!a||a.includes(".")?null:{projectSlug:s,previewBranch:a,after:r}}function Ae(e){const t=e.indexOf("."),n=t===-1?e:e.slice(0,t);if(!n.startsWith("preview-"))return null;const r=n.indexOf("--");if(r===-1)return null;const o=n.slice(r+2);if(!o)return null;const s=t===-1?"":e.slice(t);return{previewBranch:o,after:s}}function xe(e){return e.type===u.OIDC}function ge(e){return e.type===u.SAML2}function mt(e,t,n,r,o){return xe(e)?Se(t,e,n,r,{uiLocales:o}):ge(e)?ke(t,e,n,r,o):{}}function ke(e,t,n,r,o){const a=`<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
2
2
  xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
3
3
  Version="2.0"
4
4
  ID="_${U()}"
5
5
  IssueInstant="${new Date().toISOString()}"
6
- AssertionConsumerServiceURL="${e}${R.SAML_CALLBACK}"
6
+ AssertionConsumerServiceURL="${e}${b.SAML_CALLBACK}"
7
7
  AttributeConsumingServiceIndex="0">
8
8
  <saml:Issuer>${t.entityId}</saml:Issuer>
9
9
  <samlp:NameIDPolicy
10
10
  AllowCreate="true"
11
11
  Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"/>
12
- </samlp:AuthnRequest>`,l=_e(s);return{loginUrl:oe(t.ssoUrl,{SAMLRequest:l,RelayState:JSON.stringify({idpId:t.idpId,redirectTo:n,inviteCode:r,source:"portal",uiLocales:o})})}}function _e(e){return ue(Y(new TextEncoder().encode(e)).buffer)}function at(e){const t=j(e);if(t.startsWith("<samlp:Response")||t.indexOf("<saml2p:Response")>-1)return t;const n=Q(new Uint8Array(atob(e).split("").map(r=>r.charCodeAt(0))));return new TextDecoder().decode(n)}function st(e){try{return JSON.parse(j(e||""))}catch{throw new Error("Invalid OAuth2 state")}}function it(e){const t=new P().parseFromString(e,"application/xml"),r=c(t,"//*[local-name(.)='StatusCode']/@Value")[0]?.nodeValue?.endsWith("Success")||!1,a=c(t,"//*[local-name(.)='Response']/@Destination")[0]?.nodeValue||"",s=c(t,"//*[local-name(.)='Assertion']//*[local-name(.)='Issuer']/text()")[0],l=s&&s.nodeValue||void 0,m=c(t,"//*[local-name(.)='Audience']/text()")[0],g=m&&m.nodeValue||void 0,i=c(t,"//*[local-name(.)='Assertion']//*[local-name(.)='X509Certificate']/text()")[0]?.nodeValue||"",h=c(t,"//*[local-name(.)='Subject']//*[local-name(.)='NameID']/text()")[0],_=h&&h.nodeValue||"",y=c(t,"//*[local-name(.)='Subject']//*[local-name(.)='NameID']/@Format")[0],d=y&&y.nodeValue||"",x=c(t,"//*[local-name(.)='Conditions']/@NotOnOrAfter")[0],I=xe(x),O={},D=c(t,"//*[local-name(.)='AttributeStatement']//*[local-name(.)='Attribute']");if(D.length)for(const M of D){const k=c(M,"./@Name")[0];if(k.nodeValue){const E=c(M,"./*[local-name(.)='AttributeValue']/text()")[0];E?.nodeValue&&(O[k.nodeValue]=E.nodeValue)}}return{uid:_,success:r,expiresAt:I,issuerId:l,entityId:g,attrs:O,cert:i,nameFormat:d,destination:a}}function xe(e){const t=typeof e?.nodeValue=="string"&&L(Date.parse(e.nodeValue)),n=L(Date.now()),r=L(Date.now()+720*60*1e3);return t?t>n&&t<r?r:t:n}function L(e){return Math.floor(e/1e3)}const T={},S={jwks:{}};async function z(e,t){if(!T[e]){const n=t.configurationUrl?await W(t.configurationUrl):t.configuration;T[e]=Ie()?Ce(n):n}return T[e]}function Ie(){const e=ee.REDOCLY_ENFORCE_RESIDENCY;return!!e&&e.includes("host.docker.internal")}function Ce(e){if(typeof e!="object"||e===null)return e;const t={...e};for(const n of Object.keys(t)){const r=t[n];typeof r=="string"&&r.includes("://localhost")&&(t[n]=r.replace("://localhost","://host.docker.internal"))}return t}async function Le(e){for(const t of Object.keys(e)){const n=e[t];if(!$(n))continue;const r=await z(t,n);if(r.jwks_uri){const o=await W(r.jwks_uri);for(const a of o.keys)S.jwks[a.kid]={...a,idpId:t}}}}async function W(e){return fetch(e,{headers:{Accept:"application/json"}}).then(t=>t.json())}async function ct(e){return fetch(`${G}/oidc/userinfo`,{headers:{Accept:"application/json",Authorization:`Bearer ${e}`}}).then(t=>t.status===200?t.json():void 0).catch(()=>{})}function ut(e){if(!e.configurationUrl)return!1;const t=new URL(e.configurationUrl);return["localhost","127.0.0.1","blueharvest.cloud","bhstage.cloud","cloud.redocly.com","beta.redocly.com","cloud.eu.redocly.com","beta.eu.redocly.com","cba.au.redocly.com"].some(r=>Te(t.hostname,r))}function Te(e,t){return e===t||e.endsWith(`.${t}`)}async function lt(e,t){const n=new P().parseFromString(e,"application/xml"),r=c(n,"//*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']")[0];if(!r)throw new Error("Cannot find Signature in the SAML response");const o=de(t),a=new q({publicCert:o});a.loadSignature(r);try{return a.checkSignature(e)}catch{return!1}}function dt(e,t,n,r){t==="urn:oasis:names:tc:SAML:2.0:nameid-format:transient"&&(e=n["http://schemas.microsoft.com/identity/claims/objectidentifier"]);let o;(t==="urn:oasis:names:tc:SAML:2.0:nameid-format:email"||t==="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress")&&(o=e),t==="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"&&e?.match(/.+@.+/)&&(o=e);const a=n["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"],s=a?.match(/.+@.+/);return o=o||n["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"]||(s?a:void 0),o=o?.toLowerCase(),{sub:e,given_name:n["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname"],family_name:n["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname"],name:n["http://schemas.microsoft.com/identity/claims/displayname"]||a,email:o,email_verified:!0,teams:r?ce(n[r]):[]}}function J(e,t={}){return e.map(n=>t[n]||n)}async function mt(e,t){if(!t)return{};const n=t[A.AUTHORIZATION];if(!n)return{};try{const r=f.decode(n);if(r.header.alg===w.RS256){S.jwks[r.header.kid]===void 0&&await Le(e);const m=S.jwks[r.header.kid];if(!m)return S.jwks[r.header.kid]=null,{};await f.verify(n,m,w.RS256)}else await f.verify(n,C,w.HS256);const o=r.payload.idpId||S.jwks[r.header.kid]?.idpId,a=e[o]||{},s=Me(a),l=De(a);return{...r.payload,email:r.payload.email?.toLowerCase(),idpId:o,teams:Array.from(new Set([...J(r.payload.teams||[],l),..."defaultTeams"in a&&a.defaultTeams||[],...J("teamsClaimName"in a&&r.payload[s||""]||[],l),re])),name:Oe(r.payload),isAuthenticated:!0,idpAccessToken:r.payload.idp_access_token||t[A.IDP_ACCESS_TOKEN],federatedAccessToken:t[A.FEDERATED_ACCESS_TOKEN],federatedIdToken:t[A.FEDERATED_ID_TOKEN],authCookie:n}}catch(r){r instanceof ie||ae.error("Malformed JWT token: %s",r.message)}return{}}function Oe(e){return(e.firstName&&e.lastName?`${e.firstName} ${e.lastName}`:e.name||e.given_name||e.firstName||e.lastName)||e.email}function De(e){switch(e.type){case u.SAML2:return e.teamsAttributeMap;case u.OIDC:return e.teamsClaimMap;default:return}}function Me(e){switch(e.type){case u.SAML2:return e.teamsAttributeName??N;case u.OIDC:return e.teamsClaimName;default:return N}}function c(e,t){return K.select(t,e)||[]}export{ot as buildLoginUrl,he as buildOidcLoginUrl,et as buildOidcLogoutUrl,ge as buildSAML2LoginUrl,tt as createMcpAuthorizationCode,rt as createMcpSessionResource,at as decodeSamlResponse,_e as encodeSAML2,dt as extractUserClaims,Ze as getAuthProviderLoginParams,pe as getOidcLoginParams,z as getOidcMetadata,ct as getRedoclyTokenPayload,fe as getSaml2LoginParams,mt as getUserParamsFromCookies,Oe as getUsernameFromPayload,$ as isOidcProviderConfig,ut as isRedoclySso,me as isSaml2ProviderConfig,Ge as oidcExchangeCodeForToken,S as oidcJwksCache,T as oidcMetadataCache,st as parseOidcState,ye as parsePreviewBranch,it as parseSamlResponse,H as rewritePreviewAuthRedirectUri,nt as verifyMcpAuthorizationCode,lt as verifySAMLResponse};
12
+ </samlp:AuthnRequest>`,l=Ie(a);return{loginUrl:ie(t.ssoUrl,{SAMLRequest:l,RelayState:JSON.stringify({idpId:t.idpId,redirectTo:n,inviteCode:r,source:"portal",uiLocales:o})})}}function Ie(e){return me(Q(new TextEncoder().encode(e)).buffer)}function pt(e){const t=j(e);if(t.startsWith("<samlp:Response")||t.indexOf("<saml2p:Response")>-1)return t;const n=X(new Uint8Array(atob(e).split("").map(r=>r.charCodeAt(0))));return new TextDecoder().decode(n)}function ft(e){try{return JSON.parse(j(e||""))}catch{throw new Error("Invalid OAuth2 state")}}function ht(e){const t=new M().parseFromString(e,"application/xml"),r=c(t,"//*[local-name(.)='StatusCode']/@Value")[0]?.nodeValue?.endsWith("Success")||!1,s=c(t,"//*[local-name(.)='Response']/@Destination")[0]?.nodeValue||"",a=c(t,"//*[local-name(.)='Assertion']//*[local-name(.)='Issuer']/text()")[0],l=a&&a.nodeValue||void 0,p=c(t,"//*[local-name(.)='Audience']/text()")[0],x=p&&p.nodeValue||void 0,i=c(t,"//*[local-name(.)='Assertion']//*[local-name(.)='X509Certificate']/text()")[0]?.nodeValue||"",w=c(t,"//*[local-name(.)='Subject']//*[local-name(.)='NameID']/text()")[0],g=w&&w.nodeValue||"",S=c(t,"//*[local-name(.)='Subject']//*[local-name(.)='NameID']/@Format")[0],m=S&&S.nodeValue||"",k=c(t,"//*[local-name(.)='Conditions']/@NotOnOrAfter")[0],I=Te(k),C={},R=c(t,"//*[local-name(.)='AttributeStatement']//*[local-name(.)='Attribute']");if(R.length)for(const L of R){const O=c(L,"./@Name")[0];if(O.nodeValue){const D=c(L,"./*[local-name(.)='AttributeValue']/text()")[0];D?.nodeValue&&(C[O.nodeValue]=D.nodeValue)}}return{uid:g,success:r,expiresAt:I,issuerId:l,entityId:x,attrs:C,cert:i,nameFormat:m,destination:s}}function Te(e){const t=typeof e?.nodeValue=="string"&&T(Date.parse(e.nodeValue)),n=T(Date.now()),r=T(Date.now()+720*60*1e3);return t?t>n&&t<r?r:t:n}function T(e){return Math.floor(e/1e3)}const E={},_={jwks:{}};async function q(e,t){if(!E[e]){const n=t.configurationUrl?await J(t.configurationUrl):t.configuration;E[e]=Ee()?Re(n):n}return E[e]}function Ee(){const e=ne.REDOCLY_ENFORCE_RESIDENCY;return!!e&&e.includes("host.docker.internal")}const Ce=["authorization_endpoint","end_session_endpoint"];function Re(e){if(typeof e!="object"||e===null)return e;const t={...e};for(const n of Object.keys(t)){if(Ce.includes(String(n)))continue;const r=t[n];typeof r=="string"&&r.includes("://localhost")&&(t[n]=r.replace("://localhost","://host.docker.internal"))}return t}async function Le(e){for(const t of Object.keys(e)){const n=e[t];if(!$(n))continue;const r=await q(t,n);if(r.jwks_uri){const o=await J(r.jwks_uri);for(const s of o.keys)_.jwks[s.kid]={...s,idpId:t}}}}async function J(e){return fetch(e,{headers:{Accept:"application/json"}}).then(t=>t.json())}async function yt(e){return fetch(`${te}/oidc/userinfo`,{headers:{Accept:"application/json",Authorization:`Bearer ${e}`}}).then(t=>t.status===200?t.json():void 0).catch(()=>{})}function wt(e){if(!e.configurationUrl)return!1;const t=new URL(e.configurationUrl);return["localhost","127.0.0.1","blueharvest.cloud","bhstage.cloud","cloud.redocly.com","beta.redocly.com","cloud.eu.redocly.com","beta.eu.redocly.com","cba.au.redocly.com"].some(r=>Oe(t.hostname,r))}function Oe(e,t){return e===t||e.endsWith(`.${t}`)}async function St(e,t){const n=new M().parseFromString(e,"application/xml"),r=c(n,"//*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']")[0];if(!r)throw new Error("Cannot find Signature in the SAML response");const o=fe(t),s=new Y({publicCert:o});s.loadSignature(r);try{return s.checkSignature(e)}catch{return!1}}function _t(e,t,n,r){t==="urn:oasis:names:tc:SAML:2.0:nameid-format:transient"&&(e=n["http://schemas.microsoft.com/identity/claims/objectidentifier"]);let o;(t==="urn:oasis:names:tc:SAML:2.0:nameid-format:email"||t==="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress")&&(o=e),t==="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"&&e?.match(/.+@.+/)&&(o=e);const s=n["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"],a=s?.match(/.+@.+/);return o=o||n["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"]||(a?s:void 0),o=o?.toLowerCase(),{sub:e,given_name:n["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname"],family_name:n["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname"],name:n["http://schemas.microsoft.com/identity/claims/displayname"]||s,email:o,email_verified:!0,teams:r?le(n[r]):[]}}function K(e,t={}){return e.map(n=>t[n]||n)}async function At(e,t){if(!t)return{};const n=t[A.AUTHORIZATION];if(!n)return{};try{const r=d.decode(n);if(r.header.alg===h.RS256){_.jwks[r.header.kid]===void 0&&await Le(e);const p=_.jwks[r.header.kid];if(!p)return _.jwks[r.header.kid]=null,{};await d.verify(n,p,h.RS256)}else await d.verify(n,y,h.HS256);const o=r.payload.idpId||_.jwks[r.header.kid]?.idpId,s=e[o]||{},a=Pe(s),l=Me(s);return{...r.payload,email:r.payload.email?.toLowerCase(),idpId:o,teams:Array.from(new Set([...K(r.payload.teams||[],l),..."defaultTeams"in s&&s.defaultTeams||[],...K("teamsClaimName"in s&&r.payload[a||""]||[],l),ae])),name:De(r.payload),isAuthenticated:!0,idpAccessToken:re(r.payload.idp_access_token,y)||t[A.IDP_ACCESS_TOKEN],federatedAccessToken:t[A.FEDERATED_ACCESS_TOKEN],federatedIdToken:t[A.FEDERATED_ID_TOKEN],authCookie:n}}catch(r){r instanceof de||ce.error("Malformed JWT token: %s",r.message)}return{}}function De(e){return(e.firstName&&e.lastName?`${e.firstName} ${e.lastName}`:e.name||e.given_name||e.firstName||e.lastName)||e.email}function Me(e){switch(e.type){case u.SAML2:return e.teamsAttributeMap;case u.OIDC:return e.teamsClaimMap;default:return}}function Pe(e){switch(e.type){case u.SAML2:return e.teamsAttributeName??P;case u.OIDC:return e.teamsClaimName;default:return P}}function c(e,t){return G.select(t,e)||[]}export{mt as buildLoginUrl,Se as buildOidcLoginUrl,at as buildOidcLogoutUrl,ke as buildSAML2LoginUrl,it as createMcpAuthorizationCode,ut as createMcpRefreshToken,lt as createMcpSessionResource,pt as decodeSamlResponse,Le as discoverJwks,Ie as encodeSAML2,_t as extractUserClaims,rt as getAuthProviderLoginParams,ye as getOidcLoginParams,q as getOidcMetadata,yt as getRedoclyTokenPayload,we as getSaml2LoginParams,At as getUserParamsFromCookies,De as getUsernameFromPayload,$ as isOidcProviderConfig,wt as isRedoclySso,he as isSaml2ProviderConfig,ot as oidcExchangeCodeForToken,_ as oidcJwksCache,E as oidcMetadataCache,st as oidcRefreshTokenGrant,ft as parseOidcState,_e as parsePreviewBranch,ht as parseSamlResponse,F as rewritePreviewAuthRedirectUri,ct as verifyMcpAuthorizationCode,dt as verifyMcpRefreshToken,St as verifySAMLResponse};
@@ -1 +1 @@
1
- import{logger as n}from"../tools/notifiers/logger.js";import{envConfig as o}from"../config/env-config.js";import{runApiRoutesWorker as m}from"../api-routes/run-api-routes-worker.js";import{MCP_DOCS_SERVER_HANDLER_ID as i}from"../plugins/mcp/index.js";import{handleMcpRequest as u}from"../plugins/mcp/handlers/handle-mcp-request.js";async function l(r,s,a){try{const e=n.startTiming(),t=r.requestHandlerId===i?await u(r,s,a):await m(r,s,a);return n.infoTime(e,`API request handled "${new URL(s.req.url).pathname}" with status "${t.status}" and content type "${t.headers?.get("content-type")}"`),t.headers.set("X-Source","REALM_API_FUNCTION"),t}catch(e){return n.error(`[${r.requestHandlerId}] ${e.stack}`),e.name==="RequestBodySizeLimitError"?s.json({message:e.message},{status:413}):e.name==="ResponseSizeLimitError"?s.json({message:e.message},{status:500}):e.name==="MemoryUsageLimitError"?s.json({message:e.message},{status:502}):e.name==="TimeoutExceededError"?s.json({message:e.message},{status:504}):o.isDevelopMode?s.json({message:e.message},{status:500}):s.json({message:"Internal server error"},{status:500})}}export{l as handleApiRouteRequest};
1
+ import{logger as n}from"../tools/notifiers/logger.js";import{envConfig as o}from"../config/env-config.js";import{runApiRoutesWorker as m}from"../api-routes/run-api-routes-worker.js";import{MCP_CREDENTIALS_HANDLER_ID as i,MCP_DOCS_SERVER_HANDLER_ID as u}from"../plugins/mcp/index.js";import{handleMcpRequest as d}from"../plugins/mcp/handlers/handle-mcp-request.js";async function l(r,s,a){try{const e=n.startTiming(),t=r.requestHandlerId===u||r.requestHandlerId===i?await d(r,s,a):await m(r,s,a);return n.infoTime(e,`API request handled "${new URL(s.req.url).pathname}" with status "${t.status}" and content type "${t.headers?.get("content-type")}"`),t.headers.set("X-Source","REALM_API_FUNCTION"),t}catch(e){return n.error(`[${r.requestHandlerId}] ${e.stack}`),e.name==="RequestBodySizeLimitError"?s.json({message:e.message},{status:413}):e.name==="ResponseSizeLimitError"?s.json({message:e.message},{status:500}):e.name==="MemoryUsageLimitError"?s.json({message:e.message},{status:502}):e.name==="TimeoutExceededError"?s.json({message:e.message},{status:504}):o.isDevelopMode?s.json({message:e.message},{status:500}):s.json({message:"Internal server error"},{status:500})}}export{l as handleApiRouteRequest};
@@ -1 +1 @@
1
- import{envConfig as o}from"../../config/env-config.js";const t=(r,e)=>r.secureMethods?.includes(e)??!1;function f(r={}){return async(e,n)=>{const a=e.req.method;if(!t(r,a))return await n();const i=e.req.header("apiKey");if(!i)return e.json({message:"API key is required"},401);try{if(!o.BH_API_URL)return e.json({message:"API key validation service not configured"},500);const s=new URL("api-keys-verify",o.BH_API_URL).toString();if(!(await fetch(s,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({apiKey:i})})).ok)return e.json({message:"Invalid API key"},401);await n()}catch{return e.json({message:"API key validation failed"},400)}}}export{f as apiKeyMiddleware};
1
+ import{envConfig as s}from"../../config/env-config.js";import{fetchWithClient as a}from"../../utils/fetch-with-client.js";const d=(r,e)=>r.secureMethods?.includes(e)??!1;function u(r={}){return async(e,i)=>{const t=e.req.method;if(!d(r,t))return await i();const n=e.req.header("apiKey");if(!n)return e.json({message:"API key is required"},401);try{if(!s.BH_API_URL)return e.json({message:"API key validation service not configured"},500);const o=new URL("api-keys-verify",s.BH_API_URL).toString();if(!(await a(o,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({apiKey:n})})).ok)return e.json({message:"Invalid API key"},401);await i()}catch{return e.json({message:"API key validation failed"},400)}}}export{u as apiKeyMiddleware};
@@ -1,5 +1,5 @@
1
1
  import type { Context, Next } from 'hono';
2
- export declare function catalogAuthMiddleware({ serverOutDir, protectReadMethods }: {
2
+ export declare function catalogAuthMiddleware({ serverOutDir, protectReadMethods, }: {
3
3
  serverOutDir: string;
4
4
  protectReadMethods?: boolean;
5
5
  }): (ctx: Context, next: Next) => Promise<Response | void>;
@@ -1 +1 @@
1
- import{KvService as l}from"../../persistence/kv/services/kv-service.js";import{DEFAULT_AUTHENTICATED_TEAM as T}from"../../../constants/common.js";import{envConfig as s}from"../../config/env-config.js";import{CACHE_CONTROL_NO_STORE_HEADER_VALUE as h,JWT_SECRET_KEY as y}from"../../constants/common.js";import*as m from"../jwt/jwt.js";import{AlgorithmTypes as I}from"../jwt/types.js";const p=60,f=e=>["POST","PUT","DELETE","PATCH"].includes(e),E=e=>["GET"].includes(e);function R({serverOutDir:e,protectReadMethods:t=!0}){return async(r,a)=>await _(r,a,e,t)}const _=async(e,t,r,a=!0)=>{e.header("Cache-Control",h);const n=e.req.method,o=f(n)||E(n)&&a,i=e.req.header("apiKey");if(i)return await w(e,t,i,r);const u=e.req.header("authorization")?.replace("Bearer ","");return u?await C(e,t,u):o?e.json({message:"API key is required"},401):await t()},w=async(e,t,r,a)=>{if(!s.BH_API_URL||!s.ORGANIZATION_ID)return e.json({message:"API key validation service not configured"},500);try{const n=await l.getInstance({baseDbDir:a});let o=await g(n,r);if(o)return e.set("apiKeyTeams",o.teams),await t();const i=new URL(`/api/orgs/${s.ORGANIZATION_ID}/session`,s.BH_API_URL).toString(),c=await fetch(i,{method:"GET",headers:{Authorization:`Bearer ${r}`}});if(!c.ok)return e.json({message:"Invalid API key"},401);const A=(await c.json())?.user?.teams?.[s.ORGANIZATION_ID]??[],d=[T,...A];return e.set("apiKeyTeams",d),await n.set(["api-keys","reunite",r],{valid:!0,teams:d},{ttlInSeconds:p}),await t()}catch{return e.json({message:"API key validation failed"},400)}},C=async(e,t,r)=>{try{const a=await m.verify(r,y,I.HS256),n=m.decode(r).payload.isInternalConnection;return!a||!n?e.json({message:"API key is required"},401):await t()}catch{return e.json({message:"API key validation failed"},400)}},g=async(e,t)=>{try{return await e.get(["api-keys","reunite",t])}catch{return null}};export{R as catalogAuthMiddleware};
1
+ import{KvService as l}from"../../persistence/kv/services/kv-service.js";import{DEFAULT_AUTHENTICATED_TEAM as h}from"../../../constants/common.js";import{envConfig as s}from"../../config/env-config.js";import{fetchWithClient as T}from"../../utils/fetch-with-client.js";import{CACHE_CONTROL_NO_STORE_HEADER_VALUE as y,JWT_SECRET_KEY as p}from"../../constants/common.js";import*as m from"../jwt/jwt.js";import{AlgorithmTypes as I}from"../jwt/types.js";const f=60,E=e=>["POST","PUT","DELETE","PATCH"].includes(e),_=e=>["GET"].includes(e);function S({serverOutDir:e,protectReadMethods:t=!0}){return async(r,a)=>await w(r,a,e,t)}const w=async(e,t,r,a=!0)=>{e.header("Cache-Control",y);const n=e.req.method,i=E(n)||_(n)&&a,o=e.req.header("apiKey");if(o)return await C(e,t,o,r);const u=e.req.header("authorization")?.replace("Bearer ","");return u?await g(e,t,u):i?e.json({message:"API key is required"},401):await t()},C=async(e,t,r,a)=>{if(!s.BH_API_URL||!s.ORGANIZATION_ID)return e.json({message:"API key validation service not configured"},500);try{const n=await l.getInstance({baseDbDir:a});let i=await v(n,r);if(i)return e.set("apiKeyTeams",i.teams),await t();const o=new URL(`/api/orgs/${s.ORGANIZATION_ID}/session`,s.BH_API_URL).toString(),c=await T(o,{method:"GET",headers:{Authorization:`Bearer ${r}`}});if(!c.ok)return e.json({message:"Invalid API key"},401);const A=(await c.json())?.user?.teams?.[s.ORGANIZATION_ID]??[],d=[h,...A];return e.set("apiKeyTeams",d),await n.set(["api-keys","reunite",r],{valid:!0,teams:d},{ttlInSeconds:f}),await t()}catch{return e.json({message:"API key validation failed"},400)}},g=async(e,t,r)=>{try{const a=await m.verify(r,p,I.HS256),n=m.decode(r).payload.isInternalConnection;return!a||!n?e.json({message:"API key is required"},401):await t()}catch{return e.json({message:"API key validation failed"},400)}},v=async(e,t)=>{try{return await e.get(["api-keys","reunite",t])}catch{return null}};export{S as catalogAuthMiddleware};
@@ -1 +1 @@
1
- import{withPathPrefix as u}from"@redocly/theme/core/utils";import{OTEL_EXCLUDED_ROUTES as o}from"../../constants/common.js";import{telemetryTraceStep as a}from"../../telemetry/helpers/trace-step.js";import{getClientIp as m}from"../utils/get-client-ip.js";function A(){return async(e,r)=>{if(o.some(t=>e.req.path===u(t)))return r();await a("request",async t=>{t?.setAttribute("method",e.req.method||""),t?.setAttribute("host",e.req.header("host")||""),t?.setAttribute("url",e.req.url||""),t?.setAttribute("path",e.req.path||""),t?.setAttribute("user_agent",e.req.header("user-agent")||"");const s=e.get("auth")?.claims?.id||e.get("auth")?.claims?.sub,i=m(e.req.raw)||e.req.raw.context.remoteAddr?.ipAddress;t?.setAttribute("user_id",s),t?.setAttribute("user_ip",i),await r()})}}export{A as telemetryMiddleware};
1
+ import{withPathPrefix as u}from"@redocly/theme/core/utils";import{OTEL_EXCLUDED_ROUTES as o}from"../../constants/common.js";import{telemetryTraceStep as m}from"../../telemetry/helpers/trace-step.js";import{getClientIp as d}from"../utils/get-client-ip.js";function A(){return async(e,t)=>{if(o.some(r=>e.req.path===u(r)))return t();await m("com.redocly.request.performed",async r=>{r?.setAttribute("id",e.req.path||""),r?.setAttribute("object","request"),r?.setAttribute("uri",e.req.url||""),r?.setAttribute("method",e.req.method||""),r?.setAttribute("host",e.req.header("host")||""),r?.setAttribute("url",e.req.url||""),r?.setAttribute("path",e.req.path||""),r?.setAttribute("user_agent",e.req.header("user-agent")||"");const i=e.get("auth")?.claims?.id||e.get("auth")?.claims?.sub,s=d(e.req.raw)||e.req.raw.context.remoteAddr?.ipAddress;r?.setAttribute("user_id",i),r?.setAttribute("user_ip",s),await t()})}}export{A as telemetryMiddleware};
@@ -1 +1 @@
1
- import{TrieRouter as E}from"hono/router/trie-router";import{REDOCLY_ROUTE_RBAC as a}from"@redocly/config";import{withPathPrefix as _}from"@redocly/theme/core/utils";import{CACHE_CONTROL_NO_STORE_HEADER_VALUE as L}from"../../../constants/common.js";import{canAccessResource as O}from"../../../utils/rbac.js";import{handleUnauthorizedApiRequest as U}from"../../utils.js";import{handleApiRouteRequest as q}from"../../handle-api-route-request.js";import{sortApiFunctionRoutes as w}from"../../utils/sort-api-function-routes.js";function u(t){return t.headers.set("Cache-Control",L),t}function z(t,o){t.all("*",async(e,m)=>{const{method:h,path:r}=e.req,p=o.getAllApiRoutes(),R=w(p),i=new E;for(const c of R){const g=c.httpMethod?.toUpperCase()||"ALL",C=_(c.slug);i.add(g,C,c)}const s=i.match(h.toUpperCase(),r);if(!s||s[0].length===0)return m();const f=s[0],[n]=f[0],{isAuthenticated:l,claims:{email:A},teams:d}=e.get("auth");return O({...n,slug:r,[a]:{...n[a],slug:r}},{isAuthenticated:l,email:A,teams:d},o.config.access?.rbac,o.config.access?.requiresLogin)?u(await q(n,e,o)):u(U(e))})}export{z as installApiRoutes};
1
+ import{TrieRouter as _}from"hono/router/trie-router";import{REDOCLY_ROUTE_RBAC as u}from"@redocly/config";import{withPathPrefix as L,withoutPathPrefix as O}from"@redocly/theme/core/utils";import{CACHE_CONTROL_NO_STORE_HEADER_VALUE as w}from"../../../constants/common.js";import{canAccessResource as P}from"../../../utils/rbac.js";import{handleUnauthorizedApiRequest as U}from"../../utils.js";import{handleApiRouteRequest as q}from"../../handle-api-route-request.js";import{sortApiFunctionRoutes as T}from"../../utils/sort-api-function-routes.js";function h(t){return t.headers.set("Cache-Control",w),t}function F(t,o){t.all("*",async(e,m)=>{const{method:p,path:c}=e.req,R=o.getAllApiRoutes(),f=T(R),i=new _;for(const n of f){const C=n.httpMethod?.toUpperCase()||"ALL",E=L(n.slug);i.add(C,E,n)}const r=i.match(p.toUpperCase(),c);if(!r||r[0].length===0)return m();const l=r[0],[s]=l[0],{isAuthenticated:A,claims:{email:d},teams:g}=e.get("auth"),a=O(c);return P({...s,slug:a,[u]:{...s[u],slug:a}},{isAuthenticated:A,email:d,teams:g},o.config.access?.rbac,o.config.access?.requiresLogin)?h(await q(s,e,o)):h(U(e))})}export{F as installApiRoutes};
@@ -1 +1 @@
1
- import{RbacFeatures as p}from"../../../constants/common.js";import{ASK_AI_API_URL as a}from"../../constants/common.js";import{canAccessFeature as h}from"../../utils/rbac.js";import{handleUnauthorizedApiRequest as f}from"../utils.js";import{isAiSearchEnabled as A}from"../../plugins/search/utils.js";function R(c){return async e=>{if(!a)return e.newResponse(null,404);const t=c.getConfig();if(!A(t))return e.newResponse(null,403,{});const o=e.get("auth");if(!h(p.AI_SEARCH,o,t.access?.rbac,t.access?.requiresLogin))return f(e);const i={"Content-Type":"application/json"},n=[];o.claims?.authCookie&&n.push(`authorization=${o.claims.authCookie}`),o.idpAccessToken&&n.push(`accessToken=${o.idpAccessToken}`),n.length>0&&(i.Cookie=n.join("; "));const r=e.req.header("Authorization");r&&(i.Authorization=r);const u=await e.req.json(),s=await fetch(a,{method:"POST",body:JSON.stringify(u),headers:i});return s.ok?e.newResponse(s.body,200,{"Content-Type":"text/event-stream"}):e.newResponse(s.body,s.status,{"Content-Type":"application/json"})}}export{R as askAiHandler};
1
+ import{RbacFeatures as p}from"../../../constants/common.js";import{ASK_AI_API_URL as a}from"../../constants/common.js";import{fetchWithClient as h}from"../../utils/fetch-with-client.js";import{canAccessFeature as f}from"../../utils/rbac.js";import{handleUnauthorizedApiRequest as m}from"../utils.js";import{isAiSearchEnabled as A}from"../../plugins/search/utils.js";function g(c){return async e=>{if(!a)return e.newResponse(null,404);const t=c.getConfig();if(!A(t))return e.newResponse(null,403,{});const o=e.get("auth");if(!f(p.AI_SEARCH,o,t.access?.rbac,t.access?.requiresLogin))return m(e);const i={"Content-Type":"application/json"},n=[];o.claims?.authCookie&&n.push(`authorization=${o.claims.authCookie}`),o.idpAccessToken&&n.push(`accessToken=${o.idpAccessToken}`),n.length>0&&(i.Cookie=n.join("; "));const r=e.req.header("Authorization");r&&(i.Authorization=r);const u=await e.req.json(),s=await h(a,{method:"POST",body:JSON.stringify(u),headers:i});return s.ok?e.newResponse(s.body,200,{"Content-Type":"text/event-stream"}):e.newResponse(s.body,s.status,{"Content-Type":"application/json"})}}export{g as askAiHandler};
@@ -1 +1 @@
1
- import{setCookie as R,deleteCookie as Y}from"hono/cookie";import{AuthProviderType as Q,DEFAULT_TEAM_CLAIM_NAME as x}from"@redocly/config";import{withPathPrefix as _,getPathPrefix as y}from"@redocly/theme/core/utils";import{compareURIs as ee}from"../../../utils/url/compare-uris.js";import{ensureArray as q}from"../../../utils/array/ensure-array.js";import{ALTERNATIVE_AUD_CLAIM_NAME as F,JWT_SECRET_KEY as v,ORG_SLUG as re,ORG_ID as oe}from"../../constants/common.js";import{AUTH_SEGMENT as ne,ServerRoutes as P}from"../../../constants/api.js";import{AuthCookieNames as L,DEFAULT_COOKIE_EXPIRATION as H}from"../../../constants/common.js";import{sanitizeRedirectPathname as B}from"../../../utils/url/sanitize-redirect-pathname.js";import{telemetry as T}from"../../telemetry/index.js";import{envConfig as j}from"../../config/env-config.js";import{clearAuthCookies as K,clearPostLogoutCookie as $,hasPostLogoutCookie as te,setPostLogoutCookie as z}from"../../utils/cookie.js";import{getAuthProviderLoginParams as se,isOidcProviderConfig as E,isSaml2ProviderConfig as ie,oidcExchangeCodeForToken as ae,buildLoginUrl as de,decodeSamlResponse as ce,extractUserClaims as le,parseSamlResponse as ue,parseOidcState as pe,verifySAMLResponse as ge,getUsernameFromPayload as fe,buildOidcLogoutUrl as me,getOidcMetadata as G,getRedoclyTokenPayload as he,isRedoclySso as Ce,rewritePreviewAuthRedirectUri as Ae,parsePreviewBranch as J,buildOidcLoginUrl as Ie,createMcpSessionResource as D}from"../auth.js";import*as k from"../jwt/jwt.js";import{AlgorithmTypes as U}from"../jwt/types.js";import{handleErrorPageRender as we}from"../utils.js";import{encodeBase64URL as Le}from"../jwt/encode.js";import{resolveUiLocalesForIdpLogin as Re}from"./helpers/resolve-ui-locales-for-idp-login.js";async function He(s){if(j.isProductionEnv)return s.newResponse(null,404,{});const{password:e,...r}=await s.req.json(),a=await k.sign({...r,name:r.username||r.email||"Unknown"},v,U.HS256);return R(s,L.AUTHORIZATION,a,{path:y()||"/",httpOnly:!0,secure:!0,sameSite:"none"}),$(s),s.newResponse(null,200,{})}function Be(){return async s=>{const e=s.get("logger"),r=encodeURIComponent(s.req.query("message")||"");e.error(`Login error: ${r}`);const a=`${P.LOGIN}/?error=${encodeURIComponent(r)}`;return s.newResponse(null,301,{Location:a})}}function Z(s){if(!s||!s.includes(P.MCP_CALLBACK))return null;try{const e=s.split("/"),r=e[e.length-1];if(r){const a=Buffer.from(r,"base64url").toString("utf-8");return JSON.parse(a).mcpSessionId||null}}catch{}return null}function je(s){return async e=>{const r=e.get("logger"),a=s.getConfig().ssoDirect,o=pe(e.req.query("state")),m=o.idpId,t=o.source==="mcp"||o.redirectTo&&typeof o.redirectTo=="string"&&o.redirectTo.includes(P.MCP_CALLBACK),c=t?Z(typeof o.redirectTo=="string"?o.redirectTo:void 0):null,i=a?.[m];if(!E(i))return r.error("OIDC login error: missing OIDC provider config"),e.text("Forbidden",403);const d=await G(m,i);if(a&&!d.token_endpoint){const p="Invalid OIDC configuration: token_endpoint is required";return r.error(`OIDC login error: ${p}`),e.text(p,500)}try{const p=d.token_endpoint,u=e.req.query("code"),h=e.req.query("error");if(h)return t&&T.sendMcpAuthorizationFailedMessage([{...D(c),error:`OIDC error: ${h}`,error_details:e.req.query("error_description")||null}]),we(e,s,{slug:"/"},403,"403OIDC");if(!u){const A="Code is expected but not present";return r.error(`OIDC login error: ${A}`),t&&T.sendMcpAuthorizationFailedMessage([{...D(c),error:A,error_details:null}]),new Response(`Forbidden: ${A}`,{status:403})}const w=typeof o.redirectUri=="string"?o.redirectUri:new URL(_(P.OIDC_CALLBACK),e.req.url).toString(),C=e.get("cookies")?.code_verifier,l=await ae(p,u,w,i,{...i.tokenRequestCustomParams,...C?{code_verifier:C}:{}});if(l.error)return r.error(`Error from OIDC provider: "${l.error}"`),t&&T.sendMcpAuthorizationFailedMessage([{...D(c),error:`Token exchange error: ${l.error}`,error_details:l.error_description||null}]),e.text(`Forbidden: ${l.error_description||l.error}`,403);if(!l?.id_token){const A="No id_token, please, add openid to scopes";return r.error(`OIDC login error: ${A}`),t&&T.sendMcpAuthorizationFailedMessage([{...D(c),error:A,error_details:null}]),new Response(`Forbidden: ${A}`,{status:403})}const{payload:f,header:M}=k.decode(l.id_token),n=M.alg===U.RS256;if(i.audience?.length&&![...q(f.aud||[]),...q(f[F]||[])].some(O=>i.audience?.includes(O))){const O="No valid audience found in id_token";return r.error(`OIDC login error: ${O}`),t&&T.sendMcpAuthorizationFailedMessage([{...D(c),error:O,error_details:null}]),new Response(`Forbidden: ${O}`)}const g=n?l.id_token:await k.sign({...f,idpId:m},v,U.HS256);fe(f)||r.warn("To display your username, the required 'email' or 'full_profile' scope must be added to the identity provider configuration");const S=i?.tokenExpirationTime?Date.now()+i.tokenExpirationTime*1e3:f.exp*1e3||Date.now()+H*1e3;if(i.introspectEndpoint){const A=await fetch(i.introspectEndpoint,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({access_token:l.access_token})});if(A.ok){const b=(await A.json()).ext?.federatedIdentity;b&&(R(e,L.FEDERATED_ACCESS_TOKEN,b.access_token||"",{path:y()||"/",httpOnly:!1,expires:new Date(S)}),R(e,L.FEDERATED_ID_TOKEN,b.id_token||"",{path:y()||"/",httpOnly:!1,expires:new Date(S)}))}else r.warn(`OIDC introspect error: ${A.statusText}`)}if(R(e,L.AUTHORIZATION,g,{path:y()||"/",httpOnly:!0,expires:new Date(S)}),g!==l.id_token&&R(e,L.IDP_ID_TOKEN,l.id_token||"",{path:y()||"/",httpOnly:!0,expires:new Date(S)}),R(e,L.IDP_ACCESS_TOKEN,l.access_token||"",{path:y()||"/",httpOnly:!0,expires:new Date(S)}),Y(e,"code_verifier",{path:y()||"/"}),$(e),t&&o.redirectTo&&typeof o.redirectTo=="string"&&o.redirectTo.includes(P.MCP_CALLBACK)){const O=`${e.req.url.split("?")[0].replace(P.OIDC_CALLBACK,"")}${o.redirectTo}`;return e.newResponse(null,302,{Location:O})}const V=typeof o.redirectTo=="string"?o.redirectTo:void 0;let X=B(new URL(V||"/",e.req.url).pathname);const W=e.newResponse(null,302,{Location:X});return r.updateContext({email:f.email,subject:f.sub}),r.info("OIDC login successful"),W}catch(p){const u=p instanceof Error?p.message:String(p),h=p instanceof Error?p.stack:String(p);if(r.error(`OIDC login error: ${u}`),t&&T.sendMcpAuthorizationFailedMessage([{...D(c),error:u,error_details:h}]),p.error==="access_denied")return r.info("Access denied"),e.text("Forbidden",403)}const I="Something went wrong";return r.error(`OIDC login error: ${I}`),t&&T.sendMcpAuthorizationFailedMessage([{...D(c),error:I,error_details:null}]),e.text(I,500)}}function Ke(s){return async e=>{const r=e.get("logger"),o=e.get("auth").claims?.idpId,t=s.getConfig().ssoDirect?.[o];if(e.req.method==="POST")return E(t)||(K(e),z(e)),r.info("Logout successful"),e.newResponse(null,200,{});let c;if(E(t)){const i=(await G(o,t)).end_session_endpoint;if(i){const d=new URL(e.req.url),I=e.req.header("x-forwarded-proto")||d.protocol.slice(0,-1)||"https",p=e.req.header("x-forwarded-host")||d.host,u=`${I}://${p}`,h=J(u),w=h?Le(JSON.stringify({branch:J(u)})):void 0,C=h?`${Ae(u)}/${ne}/logout`:`${u}${_(P.POST_LOGOUT)}`;c=me(i,C,e.get("cookies")?.[L.IDP_ID_TOKEN]||e.get("cookies")?.[L.AUTHORIZATION]||"",w)}}return r.info("Logout successful"),K(e),z(e),e.newResponse(null,302,{Location:c||_("/")})}}function ze(s){return async e=>{const r=s.getConfig().access?.logoutReturnUrl,a=r||_("/");return e.newResponse(null,302,{Location:a})}}function Ge(s){return async e=>{const r=e.get("logger"),a=e.req.param("code"),o=j.BH_API_URL,m=(t,c,i)=>t&&c?`${t} ${c.charAt(0)}`:i;try{if(!o)throw new Error("BH_API_URL is not set");const t=s.getConfig().ssoDirect;if(!t||!Object.keys(t).length)return r.warn("Invite no sso configured to handle"),e.redirect(_("/"));const c=await fetch(`${o}/user-invites/public/${a}`);if(!c.ok)return c.status===404?(r.warn(`Invite ${a} not found redirect to homepage`),e.redirect(_("/"))):(r.error("Invite error",await c.text()),e.redirect(_("/")));const i=await c.json(),d=new URL(_("/invite"),e.req.url);return d.searchParams.set("code",a),d.searchParams.set("org",i.organization.name),d.searchParams.set("invitedBy",m(i.invitedBy.firstName,i.invitedBy.lastName,i.invitedBy.name)),e.newResponse(null,302,{Location:d.toString()})}catch(t){return r.error("Error processing invite",{error:t,inviteCode:a}),e.text(t.message||"Failed to process invite",400)}}}function Je(s){return async e=>{const r=e.get("logger"),a=s.getConfig().ssoDirect,o=new URL(e.req.url),m=e.req.query("inviteCode"),t=e.req.header("x-forwarded-proto")||o.protocol.slice(0,-1)||"https",c=e.req.header("x-forwarded-host")||o.host,i=`${t}://${c}`;let d=o.searchParams.get("idpId");const I=o.searchParams.get("redirectTo"),p=Object.keys(a||{})[0];d=d||p;const u=o.searchParams.get("mcp_redirect_uri"),h=!!u;if(!a?.[d]){const g="Invalid idpId";if(r.error(`IdP login error: ${g}`),h){const N=Z(I||void 0);T.sendMcpAuthorizationFailedMessage([{...D(N),error:g,error_details:null}])}return e.text(`Forbidden: ${g}`,403)}const C=Re({localePrefixParam:o.searchParams.get("localePrefix"),l10n:s.getGlobalData()?.l10n}),l=d&&a?await se(d,a[d]):void 0,f={};for(const g of Object.keys(l?.extraParams||{}))f[g]=o.searchParams.get(g)||l?.extraParams?.[g]||void 0;te(e)&&(f.prompt="login",f.post_logout="1");let M,n={};if(h&&u&&l&&l.type===Q.OIDC){r.info(`Building MCP OAuth login URL with redirect_uri: ${u}`);const g=Ie("",{...l,extraParams:f},I,m,{redirectUriOverride:u,sourceOverride:"mcp",branchOverride:void 0,uiLocales:C});M=g.loginUrl,n=g.cookies||{}}else if(l){const g=de({...l,extraParams:f},i,I,m,C);M=g.loginUrl,n=g.cookies||{}}return Object.keys(n).forEach(g=>{R(e,g,n[g].value,n[g].options)}),r.info(`IdP login initiated for ID '${d}'`),e.newResponse(null,302,{Location:M||new URL(e.req.url).pathname})}}function Ze(s){return async e=>{const r=e.get("logger"),a=await e.req.formData(),o=a.get("SAMLResponse"),m=a.get("RelayState");if(typeof o!="string"||typeof m!="string"){const n="SAMLResponse is required";return r.error(`SAML2 login error: ${n}`),e.text(`Bad request: ${n}`,400)}const t=ce(o),{success:c,uid:i,nameFormat:d,attrs:I,issuerId:p,expiresAt:u}=ue(t),{idpId:h,redirectTo:w}=JSON.parse(m);if(!c){const n="SAML2 assertion is not successful";return r.error(`SAML2 login error: ${n}`),e.text(`Permission denied: ${n}`,401)}if(!u||Math.ceil(Date.now()/1e3)>=u){const n="SAML2 Token Expired";return r.error(`SAML2 login error: ${n}`),e.text(n,401)}const C=s.getConfig().ssoDirect?.[h];if(!C||!ie(C)){const n="Cannot find valid IdP";return r.error(`SAML2 login error: ${n}`),e.text(`Permission denied: ${n}`,401)}if(!(C.issuerId&&p&&ee(C.issuerId,p))){const n="IssuerID is misconfigured or untrusted assertions issuer received";return r.error(`SAML2 login error: ${n}`),e.text(`Permission denied: ${n}`,401)}if(!await ge(t,C.x509PublicCert)){const n="SAMLResponse signature invalid";return r.error(`SAML2 login error: ${n}`),e.text(n,401)}const f=le(i,d,I,C.teamsAttributeName??x);if(!f.sub){const n="The provider did not return a valid user identity.";return r.error(`SAML2 login error: ${n}`),e.text(n,400)}if(!f.email){const n="The provider did not return a valid user email.";return r.error(`SAML2 login error: ${n}`),e.text(n,400)}const M=await k.sign({...f,idpId:h},v,U.HS256);return R(e,L.AUTHORIZATION,M,{path:y()||"/",httpOnly:!0,expires:new Date(u*1e3)}),$(e),r.updateContext({email:f.email,subject:f.sub}),r.info("SAML2 login successful"),e.newResponse(null,302,{Location:w||"/"})}}function Ve(s){return async e=>{const r=e.get("logger"),a=new URL(e.req.query("redirectTo")||"/",e.req.url),o=_(B(a.pathname)),m=s.getConfig().ssoDirect,t=Object.entries(m||{}).find(([,w])=>E(w)&&Ce(w));if(!(m&&t))return e.newResponse(null,302,{Location:o});const i=e.req.query("token"),d=i&&await he(i);if(!d)return e.newResponse(null,302,{Location:o});if(!q(d[F]||[]).some(w=>w===re||w===oe))return e.newResponse(null,302,{Location:o});const u=await k.sign({...d,idpId:t?.at(0)},v,U.HS256),h=Date.now()+H*1e3;return R(e,L.AUTHORIZATION,u,{path:y()||"/",httpOnly:!0,expires:new Date(h),sameSite:"None",secure:!0}),$(e),r.info("Token login successful"),e.newResponse(null,302,{Location:o})}}export{He as authorizeHandler,Je as idpLoginHandler,Ge as inviteHandler,Ke as logoutHandler,je as oidcCallbackHandler,ze as postLogoutHandler,Be as redoclyLoginCallbackHandler,Ve as redoclyTokenLoginHandler,Ze as samlCallbackHandler};
1
+ import{setCookie as L,deleteCookie as U}from"hono/cookie";import{AuthProviderType as Q,DEFAULT_TEAM_CLAIM_NAME as x}from"@redocly/config";import{withPathPrefix as O,getPathPrefix as C}from"@redocly/theme/core/utils";import{compareURIs as ee}from"../../../utils/url/compare-uris.js";import{ensureArray as N}from"../../../utils/array/ensure-array.js";import{ALTERNATIVE_AUD_CLAIM_NAME as H,JWT_SECRET_KEY as v,ORG_SLUG as re,ORG_ID as oe}from"../../constants/common.js";import{AUTH_SEGMENT as ne,ServerRoutes as P}from"../../../constants/api.js";import{AuthCookieNames as _,DEFAULT_COOKIE_EXPIRATION as B}from"../../../constants/common.js";import{sanitizeRedirectPathname as K}from"../../../utils/url/sanitize-redirect-pathname.js";import{telemetry as T}from"../../telemetry/index.js";import{envConfig as j}from"../../config/env-config.js";import{fetchWithClient as te}from"../../utils/fetch-with-client.js";import{clearAuthCookies as z,clearPostLogoutCookie as $,hasPostLogoutCookie as se,setPostLogoutCookie as G}from"../../utils/cookie.js";import{getAuthProviderLoginParams as ie,isOidcProviderConfig as b,isSaml2ProviderConfig as ae,oidcExchangeCodeForToken as de,buildLoginUrl as ce,decodeSamlResponse as le,extractUserClaims as ue,parseSamlResponse as pe,parseOidcState as ge,verifySAMLResponse as fe,getUsernameFromPayload as me,buildOidcLogoutUrl as he,getOidcMetadata as J,getRedoclyTokenPayload as Re,isRedoclySso as _e,rewritePreviewAuthRedirectUri as Ie,parsePreviewBranch as Z,buildOidcLoginUrl as Ce,createMcpSessionResource as D}from"../auth.js";import*as k from"../jwt/jwt.js";import{AlgorithmTypes as E}from"../jwt/types.js";import{handleErrorPageRender as Ae}from"../utils.js";import{encodeBase64URL as we}from"../jwt/encode.js";import{resolveUiLocalesForIdpLogin as Le}from"./helpers/resolve-ui-locales-for-idp-login.js";async function Ke(s){if(j.isProductionEnv)return s.newResponse(null,404,{});const{password:e,...r}=await s.req.json(),a=await k.sign({...r,name:r.username||r.email||"Unknown"},v,E.HS256);return L(s,_.AUTHORIZATION,a,{path:C()||"/",httpOnly:!0,secure:!0,sameSite:"none"}),$(s),s.newResponse(null,200,{})}function je(){return async s=>{const e=s.get("logger"),r=encodeURIComponent(s.req.query("message")||"");e.error(`Login error: ${r}`);const a=`${P.LOGIN}/?error=${encodeURIComponent(r)}`;return s.newResponse(null,301,{Location:a})}}function V(s){if(!s||!s.includes(P.MCP_CALLBACK))return null;try{const e=s.split("/"),r=e[e.length-1];if(r){const a=Buffer.from(r,"base64url").toString("utf-8");return JSON.parse(a).mcpSessionId||null}}catch{}return null}function ze(s){return async e=>{const r=e.get("logger"),a=s.getConfig().ssoDirect,o=ge(e.req.query("state")),m=o.idpId,t=o.source==="mcp"||o.redirectTo&&typeof o.redirectTo=="string"&&o.redirectTo.includes(P.MCP_CALLBACK),l=t?V(typeof o.redirectTo=="string"?o.redirectTo:void 0):null,i=a?.[m];if(!b(i))return r.error("OIDC login error: missing OIDC provider config"),e.text("Forbidden",403);const d=await J(m,i);if(a&&!d.token_endpoint){const p="Invalid OIDC configuration: token_endpoint is required";return r.error(`OIDC login error: ${p}`),e.text(p,500)}try{const p=d.token_endpoint,u=e.req.query("code"),h=e.req.query("error");if(h)return t&&T.sendMcpAuthorizationFailedMessage([{...D(l),error:`OIDC error: ${h}`,error_details:e.req.query("error_description")||null}]),Ae(e,s,{slug:"/"},403,"403OIDC");if(!u){const I="Code is expected but not present";return r.error(`OIDC login error: ${I}`),t&&T.sendMcpAuthorizationFailedMessage([{...D(l),error:I,error_details:null}]),new Response(`Forbidden: ${I}`,{status:403})}const w=typeof o.redirectUri=="string"?o.redirectUri:new URL(O(P.OIDC_CALLBACK),e.req.url).toString(),R=e.get("cookies")?.code_verifier,c=await de(p,u,w,i,{...i.tokenRequestCustomParams,...R?{code_verifier:R}:{}});if(c.error)return r.error(`Error from OIDC provider: "${c.error}"`),t&&T.sendMcpAuthorizationFailedMessage([{...D(l),error:`Token exchange error: ${c.error}`,error_details:c.error_description||null}]),e.text(`Forbidden: ${c.error_description||c.error}`,403);if(!c?.id_token){const I="No id_token, please, add openid to scopes";return r.error(`OIDC login error: ${I}`),t&&T.sendMcpAuthorizationFailedMessage([{...D(l),error:I,error_details:null}]),new Response(`Forbidden: ${I}`,{status:403})}const{payload:f,header:M}=k.decode(c.id_token),n=M.alg===E.RS256;if(i.audience?.length&&![...N(f.aud||[]),...N(f[H]||[])].some(y=>i.audience?.includes(y))){const y="No valid audience found in id_token";return r.error(`OIDC login error: ${y}`),t&&T.sendMcpAuthorizationFailedMessage([{...D(l),error:y,error_details:null}]),new Response(`Forbidden: ${y}`)}const g=n?c.id_token:await k.sign({...f,idpId:m},v,E.HS256);me(f)||r.warn("To display your username, the required 'email' or 'full_profile' scope must be added to the identity provider configuration");const S=i?.tokenExpirationTime?Date.now()+i.tokenExpirationTime*1e3:f.exp*1e3||Date.now()+B*1e3;if(i.introspectEndpoint){const I=await fetch(i.introspectEndpoint,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({access_token:c.access_token})});if(I.ok){const q=(await I.json()).ext?.federatedIdentity;q&&(L(e,_.FEDERATED_ACCESS_TOKEN,q.access_token||"",{path:C()||"/",httpOnly:!1,expires:new Date(S)}),L(e,_.FEDERATED_ID_TOKEN,q.id_token||"",{path:C()||"/",httpOnly:!1,expires:new Date(S)}))}else r.warn(`OIDC introspect error: ${I.statusText}`)}if(L(e,_.AUTHORIZATION,g,{path:C()||"/",httpOnly:!0,expires:new Date(S)}),g!==c.id_token&&L(e,_.IDP_ID_TOKEN,c.id_token||"",{path:C()||"/",httpOnly:!0,expires:new Date(S)}),L(e,_.IDP_ACCESS_TOKEN,c.access_token||"",{path:C()||"/",httpOnly:!0,expires:new Date(S)}),c.refresh_token?L(e,_.IDP_REFRESH_TOKEN,c.refresh_token,{path:C()||"/",httpOnly:!0,expires:new Date(S)}):U(e,_.IDP_REFRESH_TOKEN,{path:C()||"/"}),U(e,"code_verifier",{path:C()||"/"}),$(e),t&&o.redirectTo&&typeof o.redirectTo=="string"&&o.redirectTo.includes(P.MCP_CALLBACK)){const y=`${e.req.url.split("?")[0].replace(P.OIDC_CALLBACK,"")}${o.redirectTo}`;return e.newResponse(null,302,{Location:y})}const W=typeof o.redirectTo=="string"?o.redirectTo:void 0;let X=K(new URL(W||"/",e.req.url).pathname);const Y=e.newResponse(null,302,{Location:X});return r.updateContext({email:f.email,subject:f.sub}),r.info("OIDC login successful"),Y}catch(p){const u=p instanceof Error?p.message:String(p),h=p instanceof Error?p.stack:String(p);if(r.error(`OIDC login error: ${u}`),t&&T.sendMcpAuthorizationFailedMessage([{...D(l),error:u,error_details:h}]),p.error==="access_denied")return r.info("Access denied"),e.text("Forbidden",403)}const A="Something went wrong";return r.error(`OIDC login error: ${A}`),t&&T.sendMcpAuthorizationFailedMessage([{...D(l),error:A,error_details:null}]),e.text(A,500)}}function Ge(s){return async e=>{const r=e.get("logger"),o=e.get("auth").claims?.idpId,t=s.getConfig().ssoDirect?.[o];if(e.req.method==="POST")return b(t)||(z(e),G(e)),r.info("Logout successful"),e.newResponse(null,200,{});let l;if(b(t)){const i=(await J(o,t)).end_session_endpoint;if(i){const d=new URL(e.req.url),A=e.req.header("x-forwarded-proto")||d.protocol.slice(0,-1)||"https",p=e.req.header("x-forwarded-host")||d.host,u=`${A}://${p}`,h=Z(u),w=h?we(JSON.stringify({branch:Z(u)})):void 0,R=h?`${Ie(u)}/${ne}/logout`:`${u}${O(P.POST_LOGOUT)}`;l=he(i,R,e.get("cookies")?.[_.IDP_ID_TOKEN]||e.get("cookies")?.[_.AUTHORIZATION]||"",w)}}return r.info("Logout successful"),z(e),G(e),e.newResponse(null,302,{Location:l||O("/")})}}function Je(s){return async e=>{const r=s.getConfig().access?.logoutReturnUrl,a=r||O("/");return e.newResponse(null,302,{Location:a})}}function Ze(s){return async e=>{const r=e.get("logger"),a=e.req.param("code"),o=j.BH_API_URL,m=(t,l,i)=>t&&l?`${t} ${l.charAt(0)}`:i;try{if(!o)throw new Error("BH_API_URL is not set");const t=s.getConfig().ssoDirect;if(!t||!Object.keys(t).length)return r.warn("Invite no sso configured to handle"),e.redirect(O("/"));const l=await te(`${o}/public-user-invites/${a}`);if(!l.ok)return l.status===404?(r.warn(`Invite ${a} not found redirect to homepage`),e.redirect(O("/"))):(r.error("Invite error",await l.text()),e.redirect(O("/")));const i=await l.json(),d=new URL(O("/invite"),e.req.url);return d.searchParams.set("code",a),d.searchParams.set("org",i.organization.name),d.searchParams.set("invitedBy",m(i.invitedBy.firstName,i.invitedBy.lastName,i.invitedBy.name)),e.newResponse(null,302,{Location:d.toString()})}catch(t){return r.error("Error processing invite",{error:t,inviteCode:a}),e.text(t.message||"Failed to process invite",400)}}}function Ve(s){return async e=>{const r=e.get("logger"),a=s.getConfig().ssoDirect,o=new URL(e.req.url),m=e.req.query("inviteCode"),t=e.req.header("x-forwarded-proto")||o.protocol.slice(0,-1)||"https",l=e.req.header("x-forwarded-host")||o.host,i=`${t}://${l}`;let d=o.searchParams.get("idpId");const A=o.searchParams.get("redirectTo"),p=Object.keys(a||{})[0];d=d||p;const u=o.searchParams.get("mcp_redirect_uri"),h=!!u;if(!a?.[d]){const g="Invalid idpId";if(r.error(`IdP login error: ${g}`),h){const F=V(A||void 0);T.sendMcpAuthorizationFailedMessage([{...D(F),error:g,error_details:null}])}return e.text(`Forbidden: ${g}`,403)}const R=Le({localePrefixParam:o.searchParams.get("localePrefix"),l10n:s.getGlobalData()?.l10n}),c=d&&a?await ie(d,a[d]):void 0,f={};for(const g of Object.keys(c?.extraParams||{}))f[g]=o.searchParams.get(g)||c?.extraParams?.[g]||void 0;se(e)&&(f.prompt="login",f.post_logout="1");let M,n={};if(h&&u&&c&&c.type===Q.OIDC){r.info(`Building MCP OAuth login URL with redirect_uri: ${u}`);const g=Ce("",{...c,extraParams:f},A,m,{redirectUriOverride:u,sourceOverride:"mcp",branchOverride:void 0,uiLocales:R});M=g.loginUrl,n=g.cookies||{}}else if(c){const g=ce({...c,extraParams:f},i,A,m,R);M=g.loginUrl,n=g.cookies||{}}return Object.keys(n).forEach(g=>{L(e,g,n[g].value,n[g].options)}),r.info(`IdP login initiated for ID '${d}'`),e.newResponse(null,302,{Location:M||new URL(e.req.url).pathname})}}function We(s){return async e=>{const r=e.get("logger"),a=await e.req.formData(),o=a.get("SAMLResponse"),m=a.get("RelayState");if(typeof o!="string"||typeof m!="string"){const n="SAMLResponse is required";return r.error(`SAML2 login error: ${n}`),e.text(`Bad request: ${n}`,400)}const t=le(o),{success:l,uid:i,nameFormat:d,attrs:A,issuerId:p,expiresAt:u}=pe(t),{idpId:h,redirectTo:w}=JSON.parse(m);if(!l){const n="SAML2 assertion is not successful";return r.error(`SAML2 login error: ${n}`),e.text(`Permission denied: ${n}`,401)}if(!u||Math.ceil(Date.now()/1e3)>=u){const n="SAML2 Token Expired";return r.error(`SAML2 login error: ${n}`),e.text(n,401)}const R=s.getConfig().ssoDirect?.[h];if(!R||!ae(R)){const n="Cannot find valid IdP";return r.error(`SAML2 login error: ${n}`),e.text(`Permission denied: ${n}`,401)}if(!(R.issuerId&&p&&ee(R.issuerId,p))){const n="IssuerID is misconfigured or untrusted assertions issuer received";return r.error(`SAML2 login error: ${n}`),e.text(`Permission denied: ${n}`,401)}if(!await fe(t,R.x509PublicCert)){const n="SAMLResponse signature invalid";return r.error(`SAML2 login error: ${n}`),e.text(n,401)}const f=ue(i,d,A,R.teamsAttributeName??x);if(!f.sub){const n="The provider did not return a valid user identity.";return r.error(`SAML2 login error: ${n}`),e.text(n,400)}if(!f.email){const n="The provider did not return a valid user email.";return r.error(`SAML2 login error: ${n}`),e.text(n,400)}const M=await k.sign({...f,idpId:h},v,E.HS256);return L(e,_.AUTHORIZATION,M,{path:C()||"/",httpOnly:!0,expires:new Date(u*1e3)}),U(e,_.IDP_REFRESH_TOKEN,{path:C()||"/"}),$(e),r.updateContext({email:f.email,subject:f.sub}),r.info("SAML2 login successful"),e.newResponse(null,302,{Location:w||"/"})}}function Xe(s){return async e=>{const r=e.get("logger"),a=new URL(e.req.query("redirectTo")||"/",e.req.url),o=O(K(a.pathname)),m=s.getConfig().ssoDirect,t=Object.entries(m||{}).find(([,w])=>b(w)&&_e(w));if(!(m&&t))return e.newResponse(null,302,{Location:o});const i=e.req.query("token"),d=i&&await Re(i);if(!d)return e.newResponse(null,302,{Location:o});if(!N(d[H]||[]).some(w=>w===re||w===oe))return e.newResponse(null,302,{Location:o});const u=await k.sign({...d,idpId:t?.at(0)},v,E.HS256),h=Date.now()+B*1e3;return L(e,_.AUTHORIZATION,u,{path:C()||"/",httpOnly:!0,expires:new Date(h),sameSite:"None",secure:!0}),U(e,_.IDP_REFRESH_TOKEN,{path:C()||"/"}),$(e),r.info("Token login successful"),e.newResponse(null,302,{Location:o})}}export{Ke as authorizeHandler,Ve as idpLoginHandler,Ze as inviteHandler,Ge as logoutHandler,ze as oidcCallbackHandler,Je as postLogoutHandler,je as redoclyLoginCallbackHandler,Xe as redoclyTokenLoginHandler,We as samlCallbackHandler};
@@ -1 +1 @@
1
- import{telemetryTraceStep as o}from"../../../telemetry/helpers/trace-step.js";import{CATALOG_ENTITY_KEY as d}from"../../../../constants/api.js";import{ALLOWED_CATALOG_QUERY_PARAMS as y}from"../../../constants/plugins/catalog-entities.js";import{allowlistObject as f}from"../../../../utils/object/allowlist-object.js";import{CatalogEntitiesService as g}from"../../../plugins/catalog-entities/database/catalog-entities-service.js";import{createPaginationParamsValidator as E}from"../../../providers/database/pagination/schemas.js";import{ENTITY_RELATION_TO_DATABASE as _}from"../../../plugins/catalog-entities/database/mappers/field-transformations.js";import{getRbacRestrictionsDataForCatalog as A}from"../helpers/get-rbac-restrictions-data-for-catalog.js";const b=["id","key","title","type","summary","source","source_file","created_at","updated_at","relation_type","version","revision"],p=async({catalogEntitiesService:i,store:a,ctx:e})=>o("catalog_entities.bff.related_entities.get_related_entities",async t=>{try{const r=e.req.param(d);if(!r)return t?.error(new Error("Entity key is required")),e.json({message:"Entity key is required"},400);t?.setAttribute("pathParams",JSON.stringify({entityKey:r}));const s=e.req.query();t?.setAttribute("queryParams",JSON.stringify(f(s,y)));const m=E(b,_).parse(s),{currentRbacTeamsForRead:l,excludedTypes:c,excludedEntities:u}=A({store:a,ctx:e}),n=await i.getRelatedEntities({entityKey:r,paginationParams:m,rbacTeams:l,excludedTypes:c,excludedEntities:u});return t?.setAttribute("relatedEntitiesCount",n.items.length),e.json(n)}catch(r){return console.error(r),t?.error(r),e.json({message:r.message},500)}});function v(i){return async a=>o("catalog_entities.bff.related_entities",async e=>{e?.setAttribute("method",a.req.method);const t=await g.getInstance({baseDbDir:i.serverOutDir});return p({catalogEntitiesService:t,ctx:a,store:i})})}export{v as bffCatalogRelatedEntitiesHandler};
1
+ import{telemetryTraceStep as n}from"../../../telemetry/helpers/trace-step.js";import{CATALOG_ENTITY_KEY as d}from"../../../../constants/api.js";import{ALLOWED_CATALOG_QUERY_PARAMS as y}from"../../../constants/plugins/catalog-entities.js";import{allowlistObject as E}from"../../../../utils/object/allowlist-object.js";import{CatalogEntitiesService as g}from"../../../plugins/catalog-entities/database/catalog-entities-service.js";import{createPaginationParamsValidator as b}from"../../../providers/database/pagination/schemas.js";import{ENTITY_RELATION_TO_DATABASE as A}from"../../../plugins/catalog-entities/database/mappers/field-transformations.js";import{getRbacRestrictionsDataForCatalog as f}from"../helpers/get-rbac-restrictions-data-for-catalog.js";const T=["id","key","title","type","summary","source","source_file","created_at","updated_at","relation_type","version","revision"],_=async({catalogEntitiesService:i,store:a,ctx:t})=>n("com.redocly.catalogEntities.bff.relatedEntities.getRelatedEntities",async e=>{e?.setAttribute("object","catalogEntity");try{const r=t.req.param(d);if(!r)return e?.error(new Error("Entity key is required")),t.json({message:"Entity key is required"},400);e?.setAttribute("id",r),e?.setAttribute("uri",`urn:redocly:realm:api:catalogEntity:${r}`),e?.setAttribute("pathParams",JSON.stringify({entityKey:r}));const o=t.req.query();e?.setAttribute("queryParams",JSON.stringify(E(o,y)));const l=b(T,A).parse(o),{currentRbacTeamsForRead:m,excludedTypes:u,excludedEntities:c}=f({store:a,ctx:t}),s=await i.getRelatedEntities({entityKey:r,paginationParams:l,rbacTeams:m,excludedTypes:u,excludedEntities:c});return e?.setAttribute("relatedEntitiesCount",s.items.length),t.json(s)}catch(r){return console.error(r),e?.error(r),t.json({message:r.message},500)}});function I(i){return async a=>n("com.redocly.catalogEntities.bff.relatedEntities",async t=>{t?.setAttribute("id","catalogEntityId"),t?.setAttribute("object","catalogEntity"),t?.setAttribute("uri","urn:redocly:realm:api:catalogEntity:catalogEntityId"),t?.setAttribute("method",a.req.method);const e=await g.getInstance({baseDbDir:i.serverOutDir});return _({catalogEntitiesService:e,ctx:a,store:i})})}export{I as bffCatalogRelatedEntitiesHandler};
@@ -1 +1 @@
1
- import{telemetryTraceStep as y}from"../../../telemetry/helpers/trace-step.js";import{parseFilterQuery as u}from"../../../providers/database/pagination/filter.js";import{extractEqualFilterClauseValue as f}from"../../../providers/database/pagination/utils/extract-equal-filter-clause-value.js";import{CatalogEntitiesService as c}from"../../../plugins/catalog-entities/database/catalog-entities-service.js";function p(o){return async e=>y("catalog_entities.bff.revisions.get_entity_revisions",async t=>{const l=await c.getInstance({baseDbDir:o.serverOutDir}),r=e.req.query("filter");let i;try{i=u(typeof r=="string"?r:"",["catalogEntityKey"])}catch{return t?.error(new Error("Invalid filter")),e.json({message:"Invalid filter"},400)}const n=f(i,"catalogEntityKey");if(!n)return t?.error(new Error("Missing catalogEntityKey in filter")),e.json({message:"The filter query must include a non-empty catalogEntityKey clause, for example filter=catalogEntityKey:my-entity."},400);const s=e.req.query("version")??null;t?.setAttribute("queryParams",JSON.stringify({version:s,filter:r}));const a=await l.listEntityRevisions(n,s);return t?.setAttribute("totalRevisions",a.length),e.json({items:a})})}export{p as bffCatalogRevisionsHandler};
1
+ import{telemetryTraceStep as y}from"../../../telemetry/helpers/trace-step.js";import{parseFilterQuery as u}from"../../../providers/database/pagination/filter.js";import{extractEqualFilterClauseValue as c}from"../../../providers/database/pagination/utils/extract-equal-filter-clause-value.js";import{CatalogEntitiesService as f}from"../../../plugins/catalog-entities/database/catalog-entities-service.js";function b(a){return async e=>y("com.redocly.catalogEntities.bff.revisions.getEntityRevisions",async t=>{t?.setAttribute("object","catalogEntity");const l=await f.getInstance({baseDbDir:a.serverOutDir}),i=e.req.query("filter");let n;try{n=u(typeof i=="string"?i:"",["catalogEntityKey"])}catch{return t?.error(new Error("Invalid filter")),e.json({message:"Invalid filter"},400)}const r=c(n,"catalogEntityKey");if(!r)return t?.error(new Error("Missing catalogEntityKey in filter")),e.json({message:"The filter query must include a non-empty catalogEntityKey clause, for example filter=catalogEntityKey:my-entity."},400);t?.setAttribute("id",r),t?.setAttribute("uri",`urn:redocly:realm:api:catalogEntity:${r}`);const s=e.req.query("version")??null;t?.setAttribute("queryParams",JSON.stringify({version:s,filter:i}));const o=await l.listEntityRevisions(r,s);return t?.setAttribute("totalRevisions",o.length),e.json({items:o})})}export{b as bffCatalogRevisionsHandler};
@@ -1 +1 @@
1
- import{telemetryTraceStep as d}from"../../../telemetry/helpers/trace-step.js";import{CATALOG_ENTITY_KEY as g}from"../../../../constants/api.js";import{ALLOWED_CATALOG_QUERY_PARAMS as p}from"../../../constants/plugins/catalog-entities.js";import{allowlistObject as E}from"../../../../utils/object/allowlist-object.js";import{CatalogEntitiesService as b}from"../../../plugins/catalog-entities/database/catalog-entities-service.js";import{createPaginationParamsValidator as v}from"../../../providers/database/pagination/schemas.js";import{isValidIsoDate as q}from"../../../utils/is-valid-iso-date.js";import{isValidSanitizedString as A}from"../../../utils/validate-and-sanitize-string.js";import{getRbacRestrictionsDataForCatalog as l}from"../helpers/get-rbac-restrictions-data-for-catalog.js";const _=["type","key","title","summary","tags","metadata","metadata.*","git","contact","links","id","source","source_file","version","revision","created_at","updated_at","domains","owners"],h=async({catalogEntitiesService:r,ctx:e,store:n})=>d("catalog_entities.bff.get_entities",async t=>{const i=e.req.query();t?.setAttribute("queryParams",JSON.stringify(E(i,p)));const a=v(_).parse(i),{currentRbacTeamsForRead:s,excludedTypes:o,excludedEntities:u}=l({store:n,ctx:e}),m=await r.getEntitiesWithRelations({paginationParams:a,rbacTeams:s,excludedTypes:o,excludedEntities:u});return t?.setAttribute("entitiesCount",m.items.length),e.json(m)}),w=async({catalogEntitiesService:r,ctx:e,store:n})=>d("catalog_entities.bff.get_entity",async t=>{const i=e.req.param(g);if(!i)return t?.error(new Error("Entity key is required")),e.json({message:"Entity key is required"},400);const a=e.req.query("revision");let s=null;if(a){if(!q(a))return t?.error(new Error("Invalid revision parameter")),e.json({message:"Invalid revision parameter: must be a valid ISO 8601 date-time string"},400);s=a}const o=e.req.query("version");if(!A(o,{pattern:/^[a-zA-Z0-9._-]+$/,maxLength:100,allowEmpty:!0}))return t?.error(new Error("Invalid version parameter")),e.json({message:"Invalid version parameter: version must contain only alphanumeric characters, dots, hyphens, and underscores, and must not exceed 100 characters"},400);const u=e.req.query();t?.setAttribute("queryParams",JSON.stringify(u)),t?.setAttribute("pathParams",JSON.stringify({entityKey:i}));const{currentRbacTeamsForRead:m,excludedTypes:c,excludedEntities:f}=l({store:n,ctx:e}),y=await r.getEntityWithRelationsByKey({entityKey:i,filter:{revision:s,version:o},rbacTeams:m,excludedTypes:c,excludedEntities:f});return y?(t?.setAttribute("entity",JSON.stringify(y)),e.json(y)):(t?.error(new Error("Entity not found")),e.json({message:"Entity not found"},404))});function L(r){return async e=>d("catalog_entities.bff",async n=>{n?.setAttribute("method",e.req.method);const t=await b.getInstance({baseDbDir:r.serverOutDir});return e.req.param("entityKey")?w({catalogEntitiesService:t,ctx:e,store:r}):h({catalogEntitiesService:t,ctx:e,store:r})})}export{L as bffCatalogHandler};
1
+ import{telemetryTraceStep as l}from"../../../telemetry/helpers/trace-step.js";import{CATALOG_ENTITY_KEY as E}from"../../../../constants/api.js";import{ALLOWED_CATALOG_QUERY_PARAMS as b}from"../../../constants/plugins/catalog-entities.js";import{allowlistObject as f}from"../../../../utils/object/allowlist-object.js";import{CatalogEntitiesService as A}from"../../../plugins/catalog-entities/database/catalog-entities-service.js";import{createPaginationParamsValidator as v}from"../../../providers/database/pagination/schemas.js";import{isValidIsoDate as p}from"../../../utils/is-valid-iso-date.js";import{isValidSanitizedString as q}from"../../../utils/validate-and-sanitize-string.js";import{getRbacRestrictionsDataForCatalog as d}from"../helpers/get-rbac-restrictions-data-for-catalog.js";const h=["type","key","title","summary","tags","metadata","metadata.*","git","contact","links","id","source","source_file","version","revision","created_at","updated_at","domains","owners"],w=async({catalogEntitiesService:n,ctx:t,store:i})=>l("com.redocly.catalogEntities.bff.getEntities",async e=>{e?.setAttribute("id","catalogEntityId"),e?.setAttribute("object","catalogEntity"),e?.setAttribute("uri","urn:redocly:realm:api:catalogEntity:catalogEntityId");const r=t.req.query();e?.setAttribute("queryParams",JSON.stringify(f(r,b)));const a=v(h).parse(r),{currentRbacTeamsForRead:s,excludedTypes:o,excludedEntities:y}=d({store:i,ctx:t}),u=await n.getEntitiesWithRelations({paginationParams:a,rbacTeams:s,excludedTypes:o,excludedEntities:y});return e?.setAttribute("entitiesCount",u.items.length),t.json(u)}),I=async({catalogEntitiesService:n,ctx:t,store:i})=>l("com.redocly.catalogEntities.bff.getEntity",async e=>{e?.setAttribute("object","catalogEntity");const r=t.req.param(E);if(!r)return e?.error(new Error("Entity key is required")),t.json({message:"Entity key is required"},400);e?.setAttribute("id",r),e?.setAttribute("uri",`urn:redocly:realm:api:catalogEntity:${r}`);const a=t.req.query("revision");let s=null;if(a){if(!p(a))return e?.error(new Error("Invalid revision parameter")),t.json({message:"Invalid revision parameter: must be a valid ISO 8601 date-time string"},400);s=a}const o=t.req.query("version");if(!q(o,{pattern:/^[a-zA-Z0-9._-]+$/,maxLength:100,allowEmpty:!0}))return e?.error(new Error("Invalid version parameter")),t.json({message:"Invalid version parameter: version must contain only alphanumeric characters, dots, hyphens, and underscores, and must not exceed 100 characters"},400);const y=t.req.query();e?.setAttribute("queryParams",JSON.stringify(y)),e?.setAttribute("pathParams",JSON.stringify({entityKey:r}));const{currentRbacTeamsForRead:u,excludedTypes:c,excludedEntities:g}=d({store:i,ctx:t}),m=await n.getEntityWithRelationsByKey({entityKey:r,filter:{revision:s,version:o},rbacTeams:u,excludedTypes:c,excludedEntities:g});return m?(e?.setAttribute("entity",JSON.stringify(m)),t.json(m)):(e?.error(new Error("Entity not found")),t.json({message:"Entity not found"},404))});function L(n){return async t=>l("com.redocly.catalogEntities.bff",async i=>{i?.setAttribute("id","catalogEntityId"),i?.setAttribute("object","catalogEntity"),i?.setAttribute("uri","urn:redocly:realm:api:catalogEntity:catalogEntityId"),i?.setAttribute("method",t.req.method);const e=await A.getInstance({baseDbDir:n.serverOutDir});return t.req.param("entityKey")?I({catalogEntitiesService:e,ctx:t,store:n}):w({catalogEntitiesService:e,ctx:t,store:n})})}export{L as bffCatalogHandler};
@@ -1 +1 @@
1
- import{telemetryTraceStep as l}from"../../../telemetry/helpers/trace-step.js";import{CATALOG_ENTITY_RELATION_ID as y}from"../../../../constants/api.js";import{CATALOG_FILTERS_CACHE_NAMESPACE as m,ALLOWED_CATALOG_QUERY_PARAMS as c}from"../../../constants/plugins/catalog-entities.js";import{allowlistObject as E}from"../../../../utils/object/allowlist-object.js";import{CatalogEntitiesService as f}from"../../../plugins/catalog-entities/database/catalog-entities-service.js";import{createPaginationParamsValidator as R}from"../../../providers/database/pagination/schemas.js";import{ENTITY_RELATION_TO_DATABASE as w}from"../../../plugins/catalog-entities/database/mappers/field-transformations.js";import{CacheService as A}from"../../../persistence/cache/services/cache-service.js";import{parseEntityRelation as _}from"./parsers/relations/parse-entity-relation.js";import{parseEntitiesRelations as b}from"./parsers/relations/parse-entities-relations.js";import{parseEntityRelationUpdateData as j}from"./parsers/relations/parse-entity-relation-update-data.js";const h=["id","organizationId","projectId","sourceKey","targetKey","type","createdAt","updatedAt"],g=async a=>{await(await A.getInstance({baseDbDir:a,databaseType:"local"})).deleteByNamespace(m)},p=async({catalogEntitiesService:a,ctx:e})=>l("catalog_entities.relations.get_entity_relation",async n=>{const t=e.req.param(y);if(!t)return n?.error(new Error("Entity relation id is required")),e.json({message:"Entity relation id is required"},400);n?.setAttribute("pathParams",JSON.stringify({entityRelationId:t}));const i=await a.getEntityRelationById(t);return i?(n?.setAttribute("entityRelation",JSON.stringify(i)),e.json(i)):(n?.error(new Error("Entity relation not found")),e.json({message:"Entity relation not found"},404))}),O=async({catalogEntitiesService:a,ctx:e})=>l("catalog_entities.relations.get_entities_relations",async n=>{try{const t=e.req.query();n?.setAttribute("queryParams",JSON.stringify(E(t,c)));const i=R(h,w).parse(t),r=await a.getEntitiesRelations(i);return n?.setAttribute("entitiesRelationsCount",r.items.length),e.json(r)}catch(t){return console.error(t),n?.error(new Error("Failed to get entities relations")),e.json({message:"Failed to get entities relations"},500)}}),q=async({catalogEntitiesService:a,ctx:e,serverOutDir:n})=>l("catalog_entities.relations.create_entity_relation",async t=>{const i=e.get("logger");try{const r=await e.req.json();t?.setAttribute("requestBody",JSON.stringify(r));const o=_(r),s=await a.createEntityRelation(o);return s?(g(n),t?.setAttribute("entityRelation",JSON.stringify(s)),e.json(s)):(t?.error(new Error("Failed to create entity relation")),e.json({message:"Failed to create entity relation"},500))}catch(r){return i.error(r),r instanceof Error&&r.message.includes("validation failed")?(t?.error(new Error(r.message)),e.json({message:r.message},400)):(t?.error(r),e.json({message:"Failed to create entity relation"},500))}}),T=async({catalogEntitiesService:a,ctx:e,serverOutDir:n})=>l("catalog_entities.relations.bulk_upsert_entities_relations",async t=>{const i=e.get("logger");try{const r=await e.req.json();t?.setAttribute("requestBody",JSON.stringify(r));const o=b(r),s=await a.createEntitiesRelations(o);if(!s.length)return t?.error(new Error("Failed to create entity relations")),e.json({message:"Failed to create entity relations"},500);g(n);const u=s.filter(d=>d.status==="ok");return t?.setAttribute("totalSuccess",u.length),t?.setAttribute("totalFailed",s.length-u.length),e.json(s,207)}catch(r){return i.error(r),r instanceof Error&&r.message.includes("validation failed")?(t?.error(new Error(r.message)),e.json({message:r.message},400)):(t?.error(r),e.json({message:"Failed to create entity relations"},500))}}),N=async({catalogEntitiesService:a,ctx:e,serverOutDir:n})=>l("catalog_entities.relations.update_entity_relation",async t=>{const i=e.get("logger"),r=e.req.param(y);if(!r)return t?.error(new Error("Entity relation id is required")),e.json({message:"Entity relation id is required"},400);t?.setAttribute("pathParams",JSON.stringify({entityRelationId:r}));try{const o=await e.req.json();t?.setAttribute("requestBody",JSON.stringify(o));const s=await a.getEntityRelationById(r);if(!s)return t?.error(new Error(`Entity relation with id: ${r} not found`)),e.json({message:`Entity relation with id: ${r} not found`},404);const u=j(o),d=await a.updateEntityRelation(u,s);return d?(g(n),t?.setAttribute("entityRelation",JSON.stringify(d)),e.json(d)):(t?.error(new Error("Failed to update entity relation")),e.json({message:"Failed to update entity relation"},500))}catch(o){return i.error(o),o instanceof Error&&o.message.includes("validation failed")?(t?.error(new Error(o.message)),e.json({message:o.message},400)):(t?.error(o),e.json({message:o.message},500))}}),I=async({catalogEntitiesService:a,ctx:e,serverOutDir:n})=>l("catalog_entities.relations.delete_entity_relation",async t=>{const i=e.req.param(y);return i?(t?.setAttribute("pathParams",JSON.stringify({entityRelationId:i})),await a.deleteEntityRelation(i),g(n),new Response(null,{status:204})):(t?.error(new Error("Entity relation id is required")),e.json({message:"Entity relation id is required"},400))}),D={GET:O,POST:q,PUT:T},F={GET:p,DELETE:I,PATCH:N};function Y(a){return async e=>l("catalog_entities.relations",async n=>{n?.setAttribute("method",e.req.method);const t=await f.getInstance({baseDbDir:a.serverOutDir}),i=e.req.method,r=e.req.param(y)?F:D;return r[i]?await r[i]({catalogEntitiesService:t,ctx:e,serverOutDir:a.serverOutDir}):(n?.error(new Error("Method not allowed")),e.json({message:"Method not allowed"},405))})}export{Y as catalogRelationsHandler};
1
+ import{telemetryTraceStep as l}from"../../../telemetry/helpers/trace-step.js";import{CATALOG_ENTITY_RELATION_ID as g}from"../../../../constants/api.js";import{CATALOG_FILTERS_CACHE_NAMESPACE as E,ALLOWED_CATALOG_QUERY_PARAMS as c}from"../../../constants/plugins/catalog-entities.js";import{allowlistObject as m}from"../../../../utils/object/allowlist-object.js";import{CatalogEntitiesService as R}from"../../../plugins/catalog-entities/database/catalog-entities-service.js";import{createPaginationParamsValidator as A}from"../../../providers/database/pagination/schemas.js";import{ENTITY_RELATION_TO_DATABASE as b}from"../../../plugins/catalog-entities/database/mappers/field-transformations.js";import{CacheService as f}from"../../../persistence/cache/services/cache-service.js";import{parseEntityRelation as w}from"./parsers/relations/parse-entity-relation.js";import{parseEntitiesRelations as j}from"./parsers/relations/parse-entities-relations.js";import{parseEntityRelationUpdateData as h}from"./parsers/relations/parse-entity-relation-update-data.js";const O=["id","organizationId","projectId","sourceKey","targetKey","type","createdAt","updatedAt"],y=async o=>{await(await f.getInstance({baseDbDir:o,databaseType:"local"})).deleteByNamespace(E)},q=async({catalogEntitiesService:o,ctx:e})=>l("com.redocly.catalogEntities.relations.getEntityRelation",async r=>{r?.setAttribute("object","catalogEntitiesRelation");const t=e.req.param(g);if(!t)return r?.error(new Error("Entity relation id is required")),e.json({message:"Entity relation id is required"},400);r?.setAttribute("id",t),r?.setAttribute("uri",`urn:redocly:realm:api:catalogEntitiesRelation:${t}`),r?.setAttribute("pathParams",JSON.stringify({entityRelationId:t}));const n=await o.getEntityRelationById(t);return n?(r?.setAttribute("entityRelation",JSON.stringify(n)),e.json(n)):(r?.error(new Error("Entity relation not found")),e.json({message:"Entity relation not found"},404))}),I=async({catalogEntitiesService:o,ctx:e})=>l("com.redocly.catalogEntities.relations.getEntitiesRelations",async r=>{r?.setAttribute("id","catalogEntitiesRelationId"),r?.setAttribute("object","catalogEntitiesRelation"),r?.setAttribute("uri","urn:redocly:realm:api:catalogEntitiesRelation:catalogEntitiesRelationId");try{const t=e.req.query();r?.setAttribute("queryParams",JSON.stringify(m(t,c)));const n=A(O,b).parse(t),i=await o.getEntitiesRelations(n);return r?.setAttribute("entitiesRelationsCount",i.items.length),e.json(i)}catch(t){return console.error(t),r?.error(new Error("Failed to get entities relations")),e.json({message:"Failed to get entities relations"},500)}}),T=async({catalogEntitiesService:o,ctx:e,serverOutDir:r})=>l("com.redocly.catalogEntities.relations.createEntityRelation",async t=>{t?.setAttribute("object","catalogEntitiesRelation");const n=e.get("logger");try{const i=await e.req.json();t?.setAttribute("requestBody",JSON.stringify(i));const a=w(i),s=await o.createEntityRelation(a);return s?(y(r),t?.setAttribute("id",s.id),t?.setAttribute("uri",`urn:redocly:realm:api:catalogEntitiesRelation:${s.id}`),t?.setAttribute("entityRelation",JSON.stringify(s)),e.json(s)):(t?.error(new Error("Failed to create entity relation")),e.json({message:"Failed to create entity relation"},500))}catch(i){return n.error(i),i instanceof Error&&i.message.includes("validation failed")?(t?.error(new Error(i.message)),e.json({message:i.message},400)):(t?.error(i),e.json({message:"Failed to create entity relation"},500))}}),N=async({catalogEntitiesService:o,ctx:e,serverOutDir:r})=>l("com.redocly.catalogEntities.relations.bulkUpsertEntitiesRelations",async t=>{t?.setAttribute("id","catalogEntitiesRelationId"),t?.setAttribute("object","catalogEntitiesRelation"),t?.setAttribute("uri","urn:redocly:realm:api:catalogEntitiesRelation:catalogEntitiesRelationId");const n=e.get("logger");try{const i=await e.req.json();t?.setAttribute("requestBody",JSON.stringify(i));const a=j(i),s=await o.createEntitiesRelations(a);if(!s.length)return t?.error(new Error("Failed to create entity relations")),e.json({message:"Failed to create entity relations"},500);y(r);const d=s.filter(u=>u.status==="ok");return t?.setAttribute("totalSuccess",d.length),t?.setAttribute("totalFailed",s.length-d.length),e.json(s,207)}catch(i){return n.error(i),i instanceof Error&&i.message.includes("validation failed")?(t?.error(new Error(i.message)),e.json({message:i.message},400)):(t?.error(i),e.json({message:"Failed to create entity relations"},500))}}),D=async({catalogEntitiesService:o,ctx:e,serverOutDir:r})=>l("com.redocly.catalogEntities.relations.updateEntityRelation",async t=>{t?.setAttribute("object","catalogEntitiesRelation");const n=e.get("logger"),i=e.req.param(g);if(!i)return t?.error(new Error("Entity relation id is required")),e.json({message:"Entity relation id is required"},400);t?.setAttribute("id",i),t?.setAttribute("uri",`urn:redocly:realm:api:catalogEntitiesRelation:${i}`),t?.setAttribute("pathParams",JSON.stringify({entityRelationId:i}));try{const a=await e.req.json();t?.setAttribute("requestBody",JSON.stringify(a));const s=await o.getEntityRelationById(i);if(!s)return t?.error(new Error(`Entity relation with id: ${i} not found`)),e.json({message:`Entity relation with id: ${i} not found`},404);const d=h(a),u=await o.updateEntityRelation(d,s);return u?(y(r),t?.setAttribute("entityRelation",JSON.stringify(u)),e.json(u)):(t?.error(new Error("Failed to update entity relation")),e.json({message:"Failed to update entity relation"},500))}catch(a){return n.error(a),a instanceof Error&&a.message.includes("validation failed")?(t?.error(new Error(a.message)),e.json({message:a.message},400)):(t?.error(a),e.json({message:a.message},500))}}),F=async({catalogEntitiesService:o,ctx:e,serverOutDir:r})=>l("com.redocly.catalogEntities.relations.deleteEntityRelation",async t=>{t?.setAttribute("object","catalogEntitiesRelation");const n=e.req.param(g);return n?(t?.setAttribute("id",n),t?.setAttribute("uri",`urn:redocly:realm:api:catalogEntitiesRelation:${n}`),t?.setAttribute("pathParams",JSON.stringify({entityRelationId:n})),await o.deleteEntityRelation(n),y(r),new Response(null,{status:204})):(t?.error(new Error("Entity relation id is required")),e.json({message:"Entity relation id is required"},400))}),P={GET:I,POST:T,PUT:N},C={GET:q,DELETE:F,PATCH:D};function k(o){return async e=>l("com.redocly.catalogEntities.relations",async r=>{r?.setAttribute("id","catalogEntitiesRelationId"),r?.setAttribute("object","catalogEntitiesRelation"),r?.setAttribute("uri","urn:redocly:realm:api:catalogEntitiesRelation:catalogEntitiesRelationId"),r?.setAttribute("method",e.req.method);const t=await R.getInstance({baseDbDir:o.serverOutDir}),n=e.req.method,i=e.req.param(g)?C:P;return i[n]?await i[n]({catalogEntitiesService:t,ctx:e,serverOutDir:o.serverOutDir}):(r?.error(new Error("Method not allowed")),e.json({message:"Method not allowed"},405))})}export{k as catalogRelationsHandler};
@@ -1 +1 @@
1
- import{getCompleteCatalogConfig as j}from"../../../plugins/catalog-entities/get-complete-catalog-config.js";import{telemetryTraceStep as m}from"../../../telemetry/helpers/trace-step.js";import{CATALOG_FILTERS_CACHE_NAMESPACE as T,ALLOWED_CATALOG_QUERY_PARAMS as F}from"../../../constants/plugins/catalog-entities.js";import{CATALOG_ENTITY_ID as f}from"../../../../constants/api.js";import{allowlistObject as _}from"../../../../utils/object/allowlist-object.js";import{CatalogEntitiesService as R}from"../../../plugins/catalog-entities/database/catalog-entities-service.js";import{createPaginationParamsValidator as q}from"../../../providers/database/pagination/schemas.js";import{createEntityRelationDtoFromFileSchema as O}from"../../../plugins/catalog-entities/database/mappers/create-entity-relation-dto-from-file-schema.js";import{CacheService as C}from"../../../persistence/cache/services/cache-service.js";import{hasAccessToEntity as w}from"./helpers/has-access-to-entity.js";import{getRbacRestrictionsDataForCatalog as b}from"../helpers/get-rbac-restrictions-data-for-catalog.js";import{mapEntityReadModelSchemaToEntityReadDto as g}from"./mappers/map-entity-read-model-schema-to-entity-read-dto.js";import{parseEntity as I}from"./parsers/entities/parse-entity.js";import{parseEntityUpdateData as D}from"./parsers/entities/parse-entity-update-data.js";import{parseEntities as P}from"./parsers/entities/parse-entities.js";import{upsertPagesStats as h}from"./helpers/upsert-pages-stats.js";const k=["type","key","title","summary","tags","metadata","metadata.*","git","contact","links","id","source","sourceFile","createdAt","updatedAt"],A=async n=>{await(await C.getInstance({baseDbDir:n,databaseType:"local"})).deleteByNamespace(T)},N=async({catalogEntitiesService:n,ctx:e,store:u})=>m("catalog_entities.get_entities",async o=>{const i=e.get("logger");try{const r=e.req.query();o?.setAttribute("queryParams",JSON.stringify(_(r,F)));const{currentRbacTeamsForRead:d,excludedTypes:t,excludedEntities:s}=b({store:u,ctx:e}),l=q(k).parse(r),y=await n.getEntities({paginationParams:l,rbacTeams:d,excludedTypes:t,excludedEntities:s});return o?.setAttribute("entitiesCount",y.items.length),e.json({...y,items:y.items.map(g)})}catch(r){return i.error(r),o?.error(r),e.json({message:"Failed to get entities"},500)}}),W=async({catalogEntitiesService:n,ctx:e,store:u})=>m("catalog_entities.get_entity",async o=>{const i=e.req.param(f);if(!i)return o?.error(new Error("Entity id is required")),e.json({message:"Entity id is required"},400);o?.setAttribute("pathParams",JSON.stringify({entityId:i}));const{currentRbacTeamsForRead:r,excludedTypes:d,excludedEntities:t}=b({store:u,ctx:e}),s=await n.getEntityById(i,{rbacTeams:r,excludedTypes:d,excludedEntities:t});return s?(o?.setAttribute("entity",JSON.stringify(s)),e.json(g(s))):(o?.error(new Error("Entity not found")),e.json({message:"Entity not found"},404))}),L=async({catalogEntitiesService:n,ctx:e,catalogConfig:u,serverOutDir:o,store:i})=>m("catalog_entities.create_entity",async r=>{const d=e.get("logger");try{const t=await e.req.json();r?.setAttribute("requestBody",JSON.stringify(t));const s=I(t,u);if(!w({ctx:e,store:i,accessLevel:"WRITE",entityType:s.type,entityKey:s.key}))return r?.error(new Error("Access denied")),e.json({message:"Access denied"},403);const y=await n.transaction(async()=>{const a=await n.createEntity({entity:s,source:"remote",errorOnSkip:!0}),c=s.relations?.map(E=>O(s.key,E));return await n.createEntitiesRelations(c??[]),await h({ctx:e,catalogEntitiesService:n,addedEntities:a?[a]:void 0}),a});return y?(A(o),r?.setAttribute("entity",JSON.stringify(y)),e.json(g(y))):(r?.error(new Error("Failed to create entity")),e.json({message:"Failed to create entity"},500))}catch(t){return d.error(t),t instanceof Error&&t.message.includes("validation failed")?(r?.error(new Error(t.message)),e.json({message:t.message},400)):(r?.error(t),e.json({message:"Failed to create entity"},500))}}),J=async({catalogEntitiesService:n,ctx:e,catalogConfig:u,serverOutDir:o,store:i})=>m("catalog_entities.bulk_upsert_entities",async r=>{const d=e.get("logger");try{const t=await e.req.json();r?.setAttribute("requestBody",JSON.stringify(t));const s=P(t,u);for(const a of s)if(!w({ctx:e,store:i,accessLevel:"WRITE",entityType:a.type,entityKey:a.key}))return r?.error(new Error("Access denied")),e.json({message:"Access denied"},403);const l=await n.transaction(async()=>{const a=await n.createEntities(s,"remote"),c=a.reduce((E,p)=>(p.status==="ok"&&p.resource!=null&&E.push(p.resource),E),[]);return await h({ctx:e,catalogEntitiesService:n,addedEntities:c}),a});if(!l.length)return r?.error(new Error("Failed to create entities")),e.json({message:"Failed to create entities"},500);A(o);const y=l.filter(a=>a.status==="ok");return r?.setAttribute("totalSuccess",y.length),r?.setAttribute("totalFailed",l.length-y.length),e.json(y.map(a=>({...a,resource:g(a.resource)})),207)}catch(t){return d.error(t),t instanceof Error&&t.message.includes("validation failed")?(r?.error(new Error(t.message)),e.json({message:t.message},400)):(r?.error(t),e.json({message:"Failed to create entities"},500))}}),v=async({catalogEntitiesService:n,ctx:e,catalogConfig:u,serverOutDir:o,store:i})=>m("catalog_entities.update_entity",async r=>{const d=e.get("logger"),t=e.req.param(f);if(!t)return r?.error(new Error("Entity id is required")),e.json({message:"Entity id is required"},400);r?.setAttribute("pathParams",JSON.stringify({entityId:t}));try{const s=await e.req.json();r?.setAttribute("requestBody",JSON.stringify(s));const l=await n.getEntityById(t);if(!l)return r?.error(new Error(`Entity with id: ${t} not found`)),e.json({message:`Entity with id: ${t} not found`},404);if(l.source==="file")return r?.error(new Error("File entities cannot be updated")),e.json({message:"File entities cannot be updated"},400);if(!w({ctx:e,store:i,accessLevel:"WRITE",entityType:s.type??l.type,entityKey:s.key??l.key}))return r?.error(new Error("Access denied")),e.json({message:"Access denied"},403);const a=D(s,u,s?.type??l.type),c=await n.updateEntity(a,l);return c?(A(o),r?.setAttribute("entity",JSON.stringify(c)),e.json(g(c))):(r?.error(new Error("Failed to update entity")),e.json({message:"Failed to update entity"},500))}catch(s){return d.error(s),s instanceof Error&&s.message.includes("validation failed")?(r?.error(new Error(s.message)),e.json({message:s.message},400)):(r?.error(s),e.json({message:s.message},500))}}),B=async({catalogEntitiesService:n,ctx:e,serverOutDir:u,store:o})=>m("catalog_entities.delete_entity",async i=>{const r=e.get("logger"),d=e.req.param(f);if(!d)return i?.error(new Error("Entity id is required")),e.json({message:"Entity id is required"},400);i?.setAttribute("pathParams",JSON.stringify({entityId:d}));try{const t=await n.getEntityById(d);return t?t.source==="file"?(i?.error(new Error("File entities cannot be deleted")),e.json({message:"File entities cannot be deleted"},400)):w({ctx:e,store:o,accessLevel:"WRITE",entityType:t.type,entityKey:t.key})?await n.transaction(async()=>{const y=await n.deleteEntity(t);return y?(await h({ctx:e,catalogEntitiesService:n,removedEntities:t?[t]:void 0}),y):null})?(A(u),new Response(null,{status:204})):(i?.error(new Error("Failed to delete entity")),e.json({message:"Failed to delete entity"},500)):(i?.error(new Error("Access denied")),e.json({message:"Access denied"},403)):new Response(null,{status:204})}catch(t){return r.error(t),i?.error(t),e.json({message:"Failed to delete entity"},500)}}),U={GET:N,POST:L,PUT:J},G={GET:W,DELETE:B,PATCH:v};function ne(n){return async e=>m("catalog_entities",async u=>{const o=await R.getInstance({baseDbDir:n.serverOutDir}),i=e.req.method;u?.setAttribute("method",i);const r=e.req.param(f)?G:U,d=j(n.config.entitiesCatalog),t=r[i];return t?await t({catalogEntitiesService:o,ctx:e,catalogConfig:d,serverOutDir:n.serverOutDir,store:n}):(u?.error(new Error("Method not allowed")),e.json({message:"Method not allowed"},405))})}export{ne as catalogHandler};
1
+ import{getCompleteCatalogConfig as T}from"../../../plugins/catalog-entities/get-complete-catalog-config.js";import{telemetryTraceStep as g}from"../../../telemetry/helpers/trace-step.js";import{CATALOG_FILTERS_CACHE_NAMESPACE as p,ALLOWED_CATALOG_QUERY_PARAMS as F}from"../../../constants/plugins/catalog-entities.js";import{CATALOG_ENTITY_ID as f}from"../../../../constants/api.js";import{allowlistObject as I}from"../../../../utils/object/allowlist-object.js";import{CatalogEntitiesService as R}from"../../../plugins/catalog-entities/database/catalog-entities-service.js";import{createPaginationParamsValidator as q}from"../../../providers/database/pagination/schemas.js";import{createEntityRelationDtoFromFileSchema as O}from"../../../plugins/catalog-entities/database/mappers/create-entity-relation-dto-from-file-schema.js";import{CacheService as C}from"../../../persistence/cache/services/cache-service.js";import{hasAccessToEntity as A}from"./helpers/has-access-to-entity.js";import{getRbacRestrictionsDataForCatalog as h}from"../helpers/get-rbac-restrictions-data-for-catalog.js";import{mapEntityReadModelSchemaToEntityReadDto as m}from"./mappers/map-entity-read-model-schema-to-entity-read-dto.js";import{parseEntity as D}from"./parsers/entities/parse-entity.js";import{parseEntityUpdateData as P}from"./parsers/entities/parse-entity-update-data.js";import{parseEntities as k}from"./parsers/entities/parse-entities.js";import{upsertPagesStats as j}from"./helpers/upsert-pages-stats.js";const N=["type","key","title","summary","tags","metadata","metadata.*","git","contact","links","id","source","sourceFile","createdAt","updatedAt"],b=async s=>{await(await C.getInstance({baseDbDir:s,databaseType:"local"})).deleteByNamespace(p)},W=async({catalogEntitiesService:s,ctx:t,store:a})=>g("com.redocly.catalogEntities.getEntities",async o=>{o?.setAttribute("id","catalogEntityId"),o?.setAttribute("object","catalogEntity"),o?.setAttribute("uri","urn:redocly:realm:api:catalogEntity:catalogEntityId");const n=t.get("logger");try{const e=t.req.query();o?.setAttribute("queryParams",JSON.stringify(I(e,F)));const{currentRbacTeamsForRead:d,excludedTypes:r,excludedEntities:i}=h({store:a,ctx:t}),l=q(N).parse(e),y=await s.getEntities({paginationParams:l,rbacTeams:d,excludedTypes:r,excludedEntities:i});return o?.setAttribute("entitiesCount",y.items.length),t.json({...y,items:y.items.map(m)})}catch(e){return n.error(e),o?.error(e),t.json({message:"Failed to get entities"},500)}}),L=async({catalogEntitiesService:s,ctx:t,store:a})=>g("com.redocly.catalogEntities.getEntity",async o=>{o?.setAttribute("object","catalogEntity");const n=t.req.param(f);if(!n)return o?.error(new Error("Entity id is required")),t.json({message:"Entity id is required"},400);o?.setAttribute("id",n),o?.setAttribute("uri",`urn:redocly:realm:api:catalogEntity:${n}`),o?.setAttribute("pathParams",JSON.stringify({entityId:n}));const{currentRbacTeamsForRead:e,excludedTypes:d,excludedEntities:r}=h({store:a,ctx:t}),i=await s.getEntityById(n,{rbacTeams:e,excludedTypes:d,excludedEntities:r});return i?(o?.setAttribute("entity",JSON.stringify(i)),t.json(m(i))):(o?.error(new Error("Entity not found")),t.json({message:"Entity not found"},404))}),J=async({catalogEntitiesService:s,ctx:t,catalogConfig:a,serverOutDir:o,store:n})=>g("com.redocly.catalogEntities.createEntity",async e=>{e?.setAttribute("object","catalogEntity");const d=t.get("logger");try{const r=await t.req.json();e?.setAttribute("requestBody",JSON.stringify(r));const i=D(r,a);if(!A({ctx:t,store:n,accessLevel:"WRITE",entityType:i.type,entityKey:i.key}))return e?.error(new Error("Access denied")),t.json({message:"Access denied"},403);const y=await s.transaction(async()=>{const u=await s.createEntity({entity:i,source:"remote",errorOnSkip:!0}),c=i.relations?.map(E=>O(i.key,E));return await s.createEntitiesRelations(c??[]),await j({ctx:t,catalogEntitiesService:s,addedEntities:u?[u]:void 0}),u});return y?(b(o),e?.setAttribute("id",y.id),e?.setAttribute("uri",`urn:redocly:realm:api:catalogEntity:${y.id}`),e?.setAttribute("entity",JSON.stringify(y)),t.json(m(y))):(e?.error(new Error("Failed to create entity")),t.json({message:"Failed to create entity"},500))}catch(r){return d.error(r),r instanceof Error&&r.message.includes("validation failed")?(e?.error(new Error(r.message)),t.json({message:r.message},400)):(e?.error(r),t.json({message:"Failed to create entity"},500))}}),v=async({catalogEntitiesService:s,ctx:t,catalogConfig:a,serverOutDir:o,store:n})=>g("com.redocly.catalogEntities.bulkUpsertEntities",async e=>{e?.setAttribute("id","catalogEntityId"),e?.setAttribute("object","catalogEntity"),e?.setAttribute("uri","urn:redocly:realm:api:catalogEntity:catalogEntityId");const d=t.get("logger");try{const r=await t.req.json();e?.setAttribute("requestBody",JSON.stringify(r));const i=k(r,a);for(const u of i)if(!A({ctx:t,store:n,accessLevel:"WRITE",entityType:u.type,entityKey:u.key}))return e?.error(new Error("Access denied")),t.json({message:"Access denied"},403);const l=await s.transaction(async()=>{const u=await s.createEntities(i,"remote"),c=u.reduce((E,w)=>(w.status==="ok"&&w.resource!=null&&E.push(w.resource),E),[]);return await j({ctx:t,catalogEntitiesService:s,addedEntities:c}),u});if(!l.length)return e?.error(new Error("Failed to create entities")),t.json({message:"Failed to create entities"},500);b(o);const y=l.filter(u=>u.status==="ok");return e?.setAttribute("totalSuccess",y.length),e?.setAttribute("totalFailed",l.length-y.length),t.json(y.map(u=>({...u,resource:m(u.resource)})),207)}catch(r){return d.error(r),r instanceof Error&&r.message.includes("validation failed")?(e?.error(new Error(r.message)),t.json({message:r.message},400)):(e?.error(r),t.json({message:"Failed to create entities"},500))}}),B=async({catalogEntitiesService:s,ctx:t,catalogConfig:a,serverOutDir:o,store:n})=>g("com.redocly.catalogEntities.updateEntity",async e=>{e?.setAttribute("object","catalogEntity");const d=t.get("logger"),r=t.req.param(f);if(!r)return e?.error(new Error("Entity id is required")),t.json({message:"Entity id is required"},400);e?.setAttribute("id",r),e?.setAttribute("uri",`urn:redocly:realm:api:catalogEntity:${r}`),e?.setAttribute("pathParams",JSON.stringify({entityId:r}));try{const i=await t.req.json();e?.setAttribute("requestBody",JSON.stringify(i));const l=await s.getEntityById(r);if(!l)return e?.error(new Error(`Entity with id: ${r} not found`)),t.json({message:`Entity with id: ${r} not found`},404);if(l.source==="file")return e?.error(new Error("File entities cannot be updated")),t.json({message:"File entities cannot be updated"},400);if(!A({ctx:t,store:n,accessLevel:"WRITE",entityType:i.type??l.type,entityKey:i.key??l.key}))return e?.error(new Error("Access denied")),t.json({message:"Access denied"},403);const u=P(i,a,i?.type??l.type),c=await s.updateEntity(u,l);return c?(b(o),e?.setAttribute("entity",JSON.stringify(c)),t.json(m(c))):(e?.error(new Error("Failed to update entity")),t.json({message:"Failed to update entity"},500))}catch(i){return d.error(i),i instanceof Error&&i.message.includes("validation failed")?(e?.error(new Error(i.message)),t.json({message:i.message},400)):(e?.error(i),t.json({message:i.message},500))}}),U=async({catalogEntitiesService:s,ctx:t,serverOutDir:a,store:o})=>g("com.redocly.catalogEntities.deleteEntity",async n=>{n?.setAttribute("object","catalogEntity");const e=t.get("logger"),d=t.req.param(f);if(!d)return n?.error(new Error("Entity id is required")),t.json({message:"Entity id is required"},400);n?.setAttribute("id",d),n?.setAttribute("uri",`urn:redocly:realm:api:catalogEntity:${d}`),n?.setAttribute("pathParams",JSON.stringify({entityId:d}));try{const r=await s.getEntityById(d);return r?r.source==="file"?(n?.error(new Error("File entities cannot be deleted")),t.json({message:"File entities cannot be deleted"},400)):A({ctx:t,store:o,accessLevel:"WRITE",entityType:r.type,entityKey:r.key})?await s.transaction(async()=>{const y=await s.deleteEntity(r);return y?(await j({ctx:t,catalogEntitiesService:s,removedEntities:r?[r]:void 0}),y):null})?(b(a),new Response(null,{status:204})):(n?.error(new Error("Failed to delete entity")),t.json({message:"Failed to delete entity"},500)):(n?.error(new Error("Access denied")),t.json({message:"Access denied"},403)):new Response(null,{status:204})}catch(r){return e.error(r),n?.error(r),t.json({message:"Failed to delete entity"},500)}}),_={GET:W,POST:J,PUT:v},$={GET:L,DELETE:U,PATCH:B};function st(s){return async t=>g("com.redocly.catalogEntities.accessed",async a=>{a?.setAttribute("id","catalogEntityId"),a?.setAttribute("object","catalogEntity"),a?.setAttribute("uri","urn:redocly:realm:api:catalogEntity:catalogEntityId");const o=await R.getInstance({baseDbDir:s.serverOutDir}),n=t.req.method;a?.setAttribute("method",n);const e=t.req.param(f)?$:_,d=T(s.config.entitiesCatalog),r=e[n];return r?await r({catalogEntitiesService:o,ctx:t,catalogConfig:d,serverOutDir:s.serverOutDir,store:s}):(a?.error(new Error("Method not allowed")),t.json({message:"Method not allowed"},405))})}export{st as catalogHandler};
@@ -1,6 +1,6 @@
1
1
  import type { Context } from 'hono';
2
2
  import type { Store } from '../../../../store';
3
- export declare function hasAccessToEntity({ ctx, store, accessLevel, entityType, entityKey }: {
3
+ export declare function hasAccessToEntity({ ctx, store, accessLevel, entityType, entityKey, }: {
4
4
  ctx: Context;
5
5
  store: Store;
6
6
  accessLevel: 'READ' | 'WRITE';
@@ -7,6 +7,6 @@ type UpsertPagesStatsParams = {
7
7
  addedEntities?: EntityReadModelSchema[];
8
8
  removedEntities?: EntityReadModelSchema[];
9
9
  };
10
- export declare function upsertPagesStats({ ctx, catalogEntitiesService, addedEntities, removedEntities }: UpsertPagesStatsParams): Promise<void>;
10
+ export declare function upsertPagesStats({ ctx, catalogEntitiesService, addedEntities, removedEntities, }: UpsertPagesStatsParams): Promise<void>;
11
11
  export {};
12
12
  //# sourceMappingURL=upsert-pages-stats.d.ts.map
@@ -1 +1 @@
1
- import{envConfig as t}from"../../../../config/env-config.js";async function u({ctx:r,catalogEntitiesService:s,addedEntities:n,removedEntities:i}){if(!t.isProductionEnv){r.get("logger").info("Skipping pages stats upsert in non-production environment");return}if(!t.BH_API_URL||!t.ORGANIZATION_ID||!t.PROJECT_ID)throw new Error("Pages stats service not configured");const o=r.req.header("apiKey");if(!o)throw new Error("API key is required to upsert pages stats");const{total:a}=await s.getEntitiesCount("remote",n,i?.length),p={remoteEntityPages:a,isReported:!1},g=new URL(`/api/orgs/${t.ORGANIZATION_ID}/projects/${t.PROJECT_ID}/project-pages-stats`,t.BH_API_URL).toString();try{const e=await fetch(g,{method:"PUT",headers:{"Content-Type":"application/json",Authorization:`Bearer ${o}`},body:JSON.stringify(p)});if(!e.ok)throw new Error(e.statusText)}catch(e){throw new Error(`Failed to upsert project pages stats: ${e?.message}`)}}export{u as upsertPagesStats};
1
+ import{envConfig as t}from"../../../../config/env-config.js";import{fetchWithClient as c}from"../../../../utils/fetch-with-client.js";async function h({ctx:r,catalogEntitiesService:s,addedEntities:n,removedEntities:i}){if(!t.isProductionEnv){r.get("logger").info("Skipping pages stats upsert in non-production environment");return}if(!t.BH_API_URL||!t.ORGANIZATION_ID||!t.PROJECT_ID)throw new Error("Pages stats service not configured");const o=r.req.header("apiKey");if(!o)throw new Error("API key is required to upsert pages stats");const{total:a}=await s.getEntitiesCount("remote",n,i?.length),p={remoteEntityPages:a,isReported:!1},g=new URL(`/api/orgs/${t.ORGANIZATION_ID}/projects/${t.PROJECT_ID}/project-pages-stats`,t.BH_API_URL).toString();try{const e=await c(g,{method:"PUT",headers:{"Content-Type":"application/json",Authorization:`Bearer ${o}`},body:JSON.stringify(p)});if(!e.ok)throw new Error(e.statusText)}catch(e){throw new Error(`Failed to upsert project pages stats: ${e?.message}`)}}export{h as upsertPagesStats};
@@ -1 +1 @@
1
- import m from"path";import{REDOCLY_ROUTE_RBAC as U,REDOCLY_TEAMS_RBAC as b}from"@redocly/config";import{withoutPathPrefix as j,withPathPrefix as V}from"@redocly/theme/core/utils";import{CACHE_CONTROL_NO_STORE_HEADER_VALUE as M,CACHE_CONTROL_PUBLIC_HTML as W,DEFAULT_IMMUTABLE_CACHE_MAX_AGE as Z,X_REDOCLY_CACHE_CONTROL_HEADER as J,X_REDOCLY_CACHE_CONTROL_PUBLIC_HTML as K}from"../../constants/common.js";import{removeTrailingSlash as Q}from"../../../utils/url/remove-trailing-slash.js";import{findInIterable as x}from"../../../utils/collection/find-in-iterable.js";import{sanitizeRedirectPathname as ee}from"../../../utils/url/sanitize-redirect-pathname.js";import{envConfig as te}from"../../config/env-config.js";import{sanitizePath as ne}from"../../../utils/path/sanitize-path.js";import{normalizeRouteSlug as oe}from"../../../utils/path/normalize-route-slug.js";import{isPathInFolder as re}from"../../../utils/path/is-path-in-folder.js";import{getLlmsTxtMdPathBySlug as ae}from"../../utils/llmstxt/get-llms-txt-md-path-by-slug.js";import{removeLeadingSlash as D}from"../../../utils/url/remove-leading-slash.js";import{processRedirects as ie}from"./helpers/process-redirects.js";import{renderPage as se,getServerProps as ce}from"../../ssr/index.js";import{canAccessAsset as le,canAccessResource as H}from"../../utils/rbac.js";import{handleErrorPageRender as q,handleUnauthorized as v,handleUnauthorizedAsset as B}from"../utils.js";import{DEFAULT_MAX_AGE_FOR_MIME_TYPE as me,MIME_TYPES as ue}from"../mime-types.js";import{fileExistsAsync as F}from"../../utils/index.js";import{isAiAgentRequest as de}from"../../utils/ai-agent-detection.js";import{getRedirectRoute as ge}from"../utils/legacy-openapi-redirects.js";import{getContentTypeHeaderValue as fe}from"../utils/content-type.js";import{telemetry as pe}from"../../../cli/telemetry/index.js";import{telemetry as he}from"../../telemetry/index.js";function Xe(e,z,Y){return async n=>{const R=n.get("logger"),a=n.req,i=new URL(a.url),r=j(ne(decodeURIComponent(i.pathname))),A=m.parse(r).ext===".md",E=de({accept:a.header("accept"),signatureAgent:a.header("signature-agent"),signature:a.header("signature"),signatureInput:a.header("signature-input"),userAgent:a.header("user-agent")}),l=oe(r),o=(a.method==="GET"||a.method==="HEAD")&&!A?e.getRouteBySlug(l,{followRedirect:!1})||x(e.routesBySlug?.values(),t=>t.hasClientRoutes&&(r===t.slug||r.startsWith(t.slug+"/"))):void 0,L=e.getRedirect(l);if(L){const t=ie({redirect:L,reqUrlSearch:i.search});return he.sendRedirectMessage([{object:"redirect",from:l,templateId:t.type.toString()}]),n.newResponse(null,t.type,{Location:t.location})}const f=te.isProductionEnv?301:302;if(o?.metadata?.type==="openapi"){const t=ge(i.pathname);if(t)return R.info("Legacy OpenAPI docs redirect from "+i.pathname),n.newResponse(null,f,{Location:encodeURI(t)});if(i.pathname.match(/[A-Z]/))return R.warn("Redirect to lowercase route to avoid 404 error"),n.newResponse(null,f,{Location:encodeURI(i.pathname.toLowerCase())})}if(r.endsWith("/")&&r!=="/"){const t=ee(new URL(l||"/",n.req.url).pathname);return n.newResponse(null,f,{Location:encodeURI(V((t==="/"?"/":Q(t))+i.search))})}const u=o&&E?ae(o.slug):void 0,_=u?await F(m.resolve(e.outdir,D(u))):!1,{isAuthenticated:d,teams:p,claims:{email:h}}=n.get("auth");if(o&&!H(o,{isAuthenticated:d,email:h,teams:p},e.config.access?.rbac,e.config.access?.requiresLogin))return d?q(n,e,{slug:o.slug,[b]:o[b],[U]:o[U]},403):v(n,e,o.slug);if(o&&(!E||!_)){const t=await z(o),c=await ce(o,n,t,e),{html:X,statusCode:y,error:k}=await se(o,c,n,e,pe),O=e.config.access?.rbac,I=!e.config.access?.requiresLogin&&(!O||!Object.keys(O).length),S=y>=400||!!k||!!e.compilationErrors?.length,$=I&&!S;let g;return S?g=M:I?g=W:g="private",n.html(X,y,{"Cache-Control":g,...$&&{[J]:K}})}const w=u&&_?u:r,G=D(w),s=m.resolve(e.outdir,G);if(!re(s,e.outdir))return B(n);if(A){const t=r==="index.html.md"?"/":r.replace(/\.md$/,""),c=e.getRouteBySlug(t,{followRedirect:!1});if(c&&!H(c,{isAuthenticated:d,email:h,teams:p},e.config.access?.rbac,e.config.access?.requiresLogin))return v(n,e,r)}const P=e.getGlobalConfig("access");if(!le(w,P?.rbac||{},P?.requiresLogin||!1,e.getGlobalConfig("directoryPaths"),{isAuthenticated:d,email:h,teams:p}))return B(n);const T=ue[m.extname(s)]||"text/plain",C=s.match(/assets\/.*\.[a-f0-9]{8,}\..+/)||s.match(/runtime\/chunks\/.*/)?Z:me[T],N=C?{"Cache-Control":`public, max-age=${C}, immutable`,Expires:new Date(Date.now()+C*1e3).toUTCString()}:{"Cache-Control":M};if(await F(s)){const t=a.query("download")!=null,c=await Y(s);return n.newResponse(c,200,{"Content-Type":fe(T),"Access-Control-Allow-Origin":"*",...N,...t&&{"Content-Disposition":`attachment; filename="${m.basename(s)}"`}})}else return q(n,e,{slug:l},404)}}export{Xe as dynamicRouteHandler};
1
+ import m from"path";import{REDOCLY_ROUTE_RBAC as M,REDOCLY_TEAMS_RBAC as S}from"@redocly/config";import{combineUrls as V,withoutPathPrefix as W,withPathPrefix as Z}from"@redocly/theme/core/utils";import{CACHE_CONTROL_NO_STORE_HEADER_VALUE as D,CACHE_CONTROL_PUBLIC_HTML as J,DEFAULT_IMMUTABLE_CACHE_MAX_AGE as K,X_REDOCLY_CACHE_CONTROL_HEADER as Q,X_REDOCLY_CACHE_CONTROL_PUBLIC_HTML as x}from"../../constants/common.js";import{removeTrailingSlash as ee}from"../../../utils/url/remove-trailing-slash.js";import{findInIterable as te}from"../../../utils/collection/find-in-iterable.js";import{sanitizeRedirectPathname as ne}from"../../../utils/url/sanitize-redirect-pathname.js";import{envConfig as re}from"../../config/env-config.js";import{sanitizePath as oe}from"../../../utils/path/sanitize-path.js";import{normalizeRouteSlug as ie}from"../../../utils/path/normalize-route-slug.js";import{isPathInFolder as ae}from"../../../utils/path/is-path-in-folder.js";import{getLlmsTxtMdPathBySlug as se}from"../../utils/llmstxt/get-llms-txt-md-path-by-slug.js";import{removeLeadingSlash as H}from"../../../utils/url/remove-leading-slash.js";import{processRedirects as ce}from"./helpers/process-redirects.js";import{renderPage as le,getServerProps as me}from"../../ssr/index.js";import{canAccessAsset as ue,canAccessResource as q}from"../../utils/rbac.js";import{handleErrorPageRender as v,handleUnauthorized as B,handleUnauthorizedAsset as F}from"../utils.js";import{DEFAULT_MAX_AGE_FOR_MIME_TYPE as de,MIME_TYPES as ge}from"../mime-types.js";import{fileExistsAsync as z}from"../../utils/index.js";import{isAiAgentRequest as fe}from"../../utils/ai-agent-detection.js";import{getRedirectRoute as pe}from"../utils/legacy-openapi-redirects.js";import{getContentTypeHeaderValue as he}from"../utils/content-type.js";import{telemetry as Re}from"../../../cli/telemetry/index.js";import{telemetry as Ce}from"../../telemetry/index.js";function ke(e,Y,G){return async n=>{const A=n.get("logger"),i=n.req,a=new URL(i.url),o=W(oe(decodeURIComponent(a.pathname))),E=m.parse(o).ext===".md",L=fe({accept:i.header("accept"),signatureAgent:i.header("signature-agent"),signature:i.header("signature"),signatureInput:i.header("signature-input"),userAgent:i.header("user-agent")}),s=ie(o),r=(i.method==="GET"||i.method==="HEAD")&&!E?e.getRouteBySlug(s,{followRedirect:!1})||te(e.routesBySlug?.values(),t=>t.hasClientRoutes&&(o===t.slug||o.startsWith(t.slug+"/"))):void 0,_=e.getRedirect(s);if(_){const t=ce({redirect:_,reqUrlSearch:a.search});return Ce.sendRedirectMessage([{id:s,object:"redirect",uri:`urn:redocly:realm:api:redirect:${s}`,from:s,templateId:t.type.toString()}]),n.newResponse(null,t.type,{Location:t.location})}const f=re.isProductionEnv?301:302;if(r?.metadata?.type==="openapi"){const t=pe(a.pathname);if(t)return A.info("Legacy OpenAPI docs redirect from "+a.pathname),n.newResponse(null,f,{Location:encodeURI(t)});if(a.pathname.match(/[A-Z]/))return A.warn("Redirect to lowercase route to avoid 404 error"),n.newResponse(null,f,{Location:encodeURI(a.pathname.toLowerCase())})}if(o.endsWith("/")&&o!=="/"){const t=ne(new URL(s||"/",n.req.url).pathname);return n.newResponse(null,f,{Location:encodeURI(Z((t==="/"?"/":ee(t))+a.search))})}const u=r&&L?se(r.slug):void 0,w=u?await z(m.resolve(e.outdir,H(u))):!1,{isAuthenticated:d,teams:p,claims:{email:h}}=n.get("auth");if(r&&!q(r,{isAuthenticated:d,email:h,teams:p},e.config.access?.rbac,e.config.access?.requiresLogin))return d?v(n,e,{slug:r.slug,[S]:r[S],[M]:r[M]},403):B(n,e,r.slug);if(r&&(!L||!w)){const t=await Y(r),C=await me(r,n,t,e),{html:$,statusCode:U,error:k}=await le(r,C,n,e,Re),b=e.config.access?.rbac,O=!e.config.access?.requiresLogin&&(!b||!Object.keys(b).length),I=U>=400||!!k||!!e.compilationErrors?.length,j=O&&!I;let g;return I?g=D:O?g=J:g="private",n.html($,U,{"Cache-Control":g,...j&&{[Q]:x}})}const P=u&&w?u:o,N=H(P),c=m.resolve(e.outdir,N);if(!ae(c,e.outdir))return F(n);let l;if(E){const t=o==="/index.html.md"?"/":o.replace(/\.md$/,"");if(l=e.getRouteBySlug(t,{followRedirect:!1}),l&&!q(l,{isAuthenticated:d,email:h,teams:p},e.config.access?.rbac,e.config.access?.requiresLogin))return B(n,e,o)}const T=e.getGlobalConfig("access");if(!ue(P,T?.rbac||{},T?.requiresLogin||!1,e.getGlobalConfig("directoryPaths"),{isAuthenticated:d,email:h,teams:p}))return F(n);const y=ge[m.extname(c)]||"text/plain",R=c.match(/assets\/.*\.[a-f0-9]{8,}\..+/)||c.match(/runtime\/chunks\/.*/)?K:de[y],X=R?{"Cache-Control":`public, max-age=${R}, immutable`,Expires:new Date(Date.now()+R*1e3).toUTCString()}:{"Cache-Control":D};if(await z(c)){const t=i.query("download")!=null,C=await G(c);return n.newResponse(C,200,{"Content-Type":he(y),"Access-Control-Allow-Origin":"*",...X,...l&&{"X-Robots-Tag":"noindex, follow",...e.config.seo?.siteUrl&&{Link:`<${V(e.config.seo.siteUrl,l.slug)}>; rel="canonical"`}},...t&&{"Content-Disposition":`attachment; filename="${m.basename(c)}"`}})}else return v(n,e,{slug:s},404)}}export{ke as dynamicRouteHandler};
@@ -16,7 +16,7 @@ type FeedbackData = {
16
16
  email?: string;
17
17
  };
18
18
  export declare function normalizeFeedbackMetadata(metadata?: FeedbackData['metadata']): Record<string, any> | undefined;
19
- export declare function normalizeFeedbackData({ component, path, location, lang, agent, targetFeature, score, max, reasons, comment, metadata, email }: FeedbackData): {
19
+ export declare function normalizeFeedbackData({ component, path, location, lang, agent, targetFeature, score, max, reasons, comment, metadata, email, }: FeedbackData): {
20
20
  feedbackComponent: string;
21
21
  path: string | undefined;
22
22
  location: string | undefined;
@@ -1 +1 @@
1
- import{FEEDBACK_API_URL as E}from"../../constants/common.js";import{MAX_AGENT_LENGTH as T,MAX_CONTEXT_LENGTH as A,MAX_EMAIL_LENGTH as k,MAX_LANG_LENGTH as y,MAX_PATH_LENGTH as N,MAX_REASONS_COUNT as F,MAX_TARGET_FEATURE_LENGTH as j}from"../../constants/feedback.js";import{mapObject as L}from"../../../utils/object/map-object.js";import{getFeedbackClientIp as C}from"../utils/feedback-ip.js";import{canAccessResource as R}from"../../utils/rbac.js";function r(n,e){if(n!=null)return String(n).replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g,"").trim().slice(0,e)||void 0}function S(n){if(!n)return n;const e=["userAgent","firstName","lastName","auth_time","platform","id","email","ipAddress"];return L(n,(t,a)=>e.includes(a)?t:"*****")}function G({component:n,path:e,location:t,lang:a,agent:p,targetFeature:m,score:s,max:o,reasons:i,comment:f,metadata:l,email:h}){const u=Array.isArray(i)?i.map(c=>r(String(c),A)).filter(c=>!!c).slice(0,F):void 0;return{feedbackComponent:n.toUpperCase(),path:r(e,N),location:r(t,A),lang:r(a,y),score:typeof s=="number"?s:void 0,maxScore:typeof o=="number"?o:void 0,reasons:u?.length?u:void 0,comment:r(f,A),email:r(h,k),agent:r(p,T),targetFeature:r(m,j),metadata:S(l)}}async function M(n,e){return(await fetch(E,{method:"POST",body:JSON.stringify(G(n)),headers:e})).json()}function P(n){return async e=>{const t=await e.req.json(),a=e.req.header("user-agent"),p=C(e.req.raw),m=e.req.header("Sec-Ch-Ua-Platform"),s={...t.metadata,userAgent:a,ipAddress:p,platform:m?m.replace(/"/g,""):"unknown"},o=[];(!t.path||t.path==="")&&o.push("`path` is required");const i=["sentiment","rating","comment","problem","mood","scale"];if(i.includes(t.component)||o.push(`\`component\` field should be one of ${i.join(", ")}.`),o.length)return e.json({errors:o},400);const{claims:f,isAuthenticated:l,teams:h}=e.get("auth"),u={isAuthenticated:l,email:f?.email,teams:h};if(Object.keys(n.config.access?.rbac||{}).length>0){const d=t.path,_=new URL(d).pathname,b=n.getRouteBySlug(_);if(!b)return e.json({errors:["Resource not found"]},404);if(!R(b,u,n.config.access?.rbac,n.config.access?.requiresLogin))return e.json({errors:["Forbidden: no permission to send feedback for resource"]},403)}const c={"Content-Type":"application/json"},g=f?.email||t?.email||s?.email;try{const d=await M({...t,email:g,metadata:{email:g,...s}},c);return e.json({message:"Thanks for your feedback",...d},200,{})}catch(d){return e.json({errors:["Failed to send feedback",d.message]},500)}}}export{P as feedbackHandler,G as normalizeFeedbackData,S as normalizeFeedbackMetadata};
1
+ import{FEEDBACK_API_URL as E}from"../../constants/common.js";import{fetchWithClient as T}from"../../utils/fetch-with-client.js";import{MAX_AGENT_LENGTH as k,MAX_CONTEXT_LENGTH as A,MAX_EMAIL_LENGTH as y,MAX_LANG_LENGTH as N,MAX_PATH_LENGTH as F,MAX_REASONS_COUNT as j,MAX_TARGET_FEATURE_LENGTH as C}from"../../constants/feedback.js";import{mapObject as L}from"../../../utils/object/map-object.js";import{getFeedbackClientIp as R}from"../utils/feedback-ip.js";import{canAccessResource as S}from"../../utils/rbac.js";function r(n,e){if(n!=null)return String(n).replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g,"").trim().slice(0,e)||void 0}function G(n){if(!n)return n;const e=["userAgent","firstName","lastName","auth_time","platform","id","email","ipAddress"];return L(n,(t,a)=>e.includes(a)?t:"*****")}function M({component:n,path:e,location:t,lang:a,agent:p,targetFeature:m,score:s,max:o,reasons:i,comment:f,metadata:l,email:h}){const u=Array.isArray(i)?i.map(c=>r(String(c),A)).filter(c=>!!c).slice(0,j):void 0;return{feedbackComponent:n.toUpperCase(),path:r(e,F),location:r(t,A),lang:r(a,N),score:typeof s=="number"?s:void 0,maxScore:typeof o=="number"?o:void 0,reasons:u?.length?u:void 0,comment:r(f,A),email:r(h,y),agent:r(p,k),targetFeature:r(m,C),metadata:G(l)}}async function w(n,e){return(await T(E,{method:"POST",body:JSON.stringify(M(n)),headers:e})).json()}function B(n){return async e=>{const t=await e.req.json(),a=e.req.header("user-agent"),p=R(e.req.raw),m=e.req.header("Sec-Ch-Ua-Platform"),s={...t.metadata,userAgent:a,ipAddress:p,platform:m?m.replace(/"/g,""):"unknown"},o=[];(!t.path||t.path==="")&&o.push("`path` is required");const i=["sentiment","rating","comment","problem","mood","scale"];if(i.includes(t.component)||o.push(`\`component\` field should be one of ${i.join(", ")}.`),o.length)return e.json({errors:o},400);const{claims:f,isAuthenticated:l,teams:h}=e.get("auth"),u={isAuthenticated:l,email:f?.email,teams:h};if(Object.keys(n.config.access?.rbac||{}).length>0){const d=t.path,_=new URL(d).pathname,b=n.getRouteBySlug(_);if(!b)return e.json({errors:["Resource not found"]},404);if(!S(b,u,n.config.access?.rbac,n.config.access?.requiresLogin))return e.json({errors:["Forbidden: no permission to send feedback for resource"]},403)}const c={"Content-Type":"application/json"},g=f?.email||t?.email||s?.email;try{const d=await w({...t,email:g,metadata:{email:g,...s}},c);return e.json({message:"Thanks for your feedback",...d},200,{})}catch(d){return e.json({errors:["Failed to send feedback",d.message]},500)}}}export{B as feedbackHandler,M as normalizeFeedbackData,G as normalizeFeedbackMetadata};
@@ -22,7 +22,7 @@ import type { StatusCode } from 'hono/utils/http-status';
22
22
  * processRedirects({ redirect: { to: 'https://example.com', type: 302 } });
23
23
  * // Returns: { location: 'https://example.com', type: 302 }
24
24
  */
25
- export declare function processRedirects({ redirect, reqUrlSearch }: {
25
+ export declare function processRedirects({ redirect, reqUrlSearch, }: {
26
26
  redirect: WithRequired<RedirectConfig, 'to'>;
27
27
  reqUrlSearch?: string;
28
28
  }): {
@@ -1 +1 @@
1
- import{withPathPrefix as t}from"@redocly/theme/core/utils";import{MCP_SERVER_CARD_SLUG as n}from"../../../../constants/common.js";import{telemetryTraceStep as a}from"../../../telemetry/helpers/trace-step.js";import{SKILLS_INDEX_SLUG as l}from"../skills/constants.js";function p(i){return async s=>await a("a2a",async o=>{const r=i.config.skills?.hide!==!0,e=[`<${t(n)}>; rel="mcp-server-card"`];return r&&e.push(`<${t(l)}>; rel="agent-skills"`),o?.setAttribute("skillsAdvertised",r),s.json({error:{code:"405",message:"Method not allowed"}},405,{Link:e.join(", ")})})}export{p as a2aHandler};
1
+ import{withPathPrefix as i}from"@redocly/theme/core/utils";import{MCP_SERVER_CARD_SLUG as a}from"../../../../constants/common.js";import{telemetryTraceStep as l}from"../../../telemetry/helpers/trace-step.js";import{SKILLS_INDEX_SLUG as n}from"../skills/constants.js";function f(s){return async o=>await l("com.redocly.a2a.requested",async e=>{const r=s.config.skills?.hide!==!0,t=[`<${i(a)}>; rel="mcp-server-card"`];return r&&t.push(`<${i(n)}>; rel="agent-skills"`),e?.setAttribute("skillsAdvertised",r),e?.setAttribute("object","a2a"),e?.setAttribute("id","a2aId"),e?.setAttribute("uri","urn:redocly:realm:api:a2a:a2aId"),o.json({error:{code:"405",message:"Method not allowed"}},405,{Link:t.join(", ")})})}export{f as a2aHandler};
@@ -1 +1 @@
1
- import{CACHE_CONTROL_NO_STORE_HEADER_VALUE as u}from"../../../constants/common.js";import{telemetryTraceStep as m}from"../../../telemetry/helpers/trace-step.js";import{getAccessibleSkills as g}from"../../../utils/skills/get-accessible-skills.js";import{resolvePublicBaseUrl as f}from"../../../web-server/utils/resolve-public-base-url.js";import{shouldHandleMcpAuth as A}from"../../../plugins/mcp/auth/auth-handlers.js";import{buildAgentCard as d}from"./utils/build-agent-card.js";function _(e){return async i=>await m("agent_card",async t=>{if(e.config.skills?.hide===!0)return i.newResponse(null,404);const{isAuthenticated:o,teams:c,claims:{email:a}}=i.get("auth"),r=e.config.access?.rbac||{},s=!!e.config.access?.requiresLogin,n=g(e.getSkills(),{isAuthenticated:o,teams:c,email:a},r,s),l=A(s,r);return t?.setAttribute("skillsCount",n.length),t?.setAttribute("mcpAuthRequired",l),i.json(d({seo:e.getGlobalConfig("seo"),baseUrl:f(e,i),skills:n,mcpAuthRequired:l}),200,{"Cache-Control":u,"Access-Control-Allow-Origin":"*"})})}export{_ as agentCardHandler};
1
+ import{CACHE_CONTROL_NO_STORE_HEADER_VALUE as c}from"../../../constants/common.js";import{telemetryTraceStep as d}from"../../../telemetry/helpers/trace-step.js";import{getAccessibleSkills as g}from"../../../utils/skills/get-accessible-skills.js";import{resolvePublicBaseUrl as m}from"../../../web-server/utils/resolve-public-base-url.js";import{shouldHandleMcpAuth as A}from"../../../plugins/mcp/auth/auth-handlers.js";import{buildAgentCard as C}from"./utils/build-agent-card.js";function y(e){return async r=>await d("com.redocly.agentCard.served",async t=>{if(t?.setAttribute("id","agentCardId"),t?.setAttribute("object","agentCard"),t?.setAttribute("uri","urn:redocly:realm:api:agentCard:agentCardId"),e.config.skills?.hide===!0)return r.newResponse(null,404);const{isAuthenticated:l,teams:a,claims:{email:u}}=r.get("auth"),i=e.config.access?.rbac||{},n=!!e.config.access?.requiresLogin,s=g(e.getSkills(),{isAuthenticated:l,teams:a,email:u},i,n),o=A(n,i);return t?.setAttribute("skillsCount",s.length),t?.setAttribute("mcpAuthRequired",o),r.json(C({seo:e.getGlobalConfig("seo"),baseUrl:m(e,r),skills:s,mcpAuthRequired:o}),200,{"Cache-Control":c,"Access-Control-Allow-Origin":"*"})})}export{y as agentCardHandler};
@@ -1,4 +1,6 @@
1
1
  import type { Handler } from 'hono';
2
+ import type { SsoConfig } from '@redocly/config';
3
+ import type { Store } from '../../../store.js';
2
4
  export type McpContextPayload = {
3
5
  isMcpFlow: boolean;
4
6
  originalRedirectUri: string | null;
@@ -9,17 +11,19 @@ export type McpContextPayload = {
9
11
  mcpCodeChallengeMethod?: string | null;
10
12
  timestamp: number;
11
13
  };
14
+ export declare const SUPPORTED_MCP_GRANT_TYPES: readonly ['authorization_code', 'refresh_token'];
12
15
  export declare function verifyPkce(codeChallenge: string, codeChallengeMethod: string | undefined, codeVerifier: string): boolean;
13
16
  export declare function createMcpContextToken(context: McpContextPayload): Promise<string>;
14
17
  export declare function verifyAndParseMcpContextToken(token: string): Promise<McpContextPayload>;
15
- export declare function mcpOAuthProtectedResourceHandler(): Handler;
16
- export declare function mcpOAuthAuthorizationServerHandler(): Handler;
18
+ export declare function mcpOAuthProtectedResourceHandler(store: Store): Handler;
19
+ export declare function mcpOAuthAuthorizationServerHandler(store: Store): Handler;
17
20
  /**
18
21
  * This code is not used in the MCP server, but it is required to satisfy the OAuth 2.0 Dynamic Client Registration Protocol.
19
22
  * Also it is simulating the client registration process.
20
23
  */
21
- export declare function mcpDynamicClientRegistrationHandler(): Handler;
22
- export declare function mcpAuthorizationHandler(): Handler;
23
- export declare function mcpTokenPortalHandler(): Handler;
24
- export declare function mcpCallbackHandler(): Handler;
24
+ export declare function mcpDynamicClientRegistrationHandler(store: Store): Handler;
25
+ export declare function resolveMcpIdpId(ssoDirect: SsoConfig | undefined): string | undefined;
26
+ export declare function mcpAuthorizationHandler(store: Store): Handler;
27
+ export declare function mcpTokenPortalHandler(store: Store): Handler;
28
+ export declare function mcpCallbackHandler(store: Store): Handler;
25
29
  //# sourceMappingURL=mcp-oauth.d.ts.map