@redocly/redoc 0.140.0-next.1 → 0.140.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 (242) hide show
  1. package/CHANGELOG.md +409 -201
  2. package/dist/api-schemas/mcp-fetch-count.d.ts +2 -18
  3. package/dist/api-schemas/otel-traces.d.ts +7 -1345
  4. package/dist/api-schemas/otel-traces.js +1 -1
  5. package/dist/api-schemas/search-facets.d.ts +3 -31
  6. package/dist/api-schemas/search.d.ts +6 -52
  7. package/dist/cli/build/index.js +1 -1
  8. package/dist/cli/eject/resolveEjectParams.js +1 -1
  9. package/dist/cli/generate/get-schema-template.js +1 -1
  10. package/dist/client/app/hooks/markdown/useMarkdocRenderer.js +1 -1
  11. package/dist/client/app/hooks/markdown/useMarkdownText.js +1 -1
  12. package/dist/client/app/markdoc/custom-components/openapi/openapi-code-sample.d.ts +2 -0
  13. package/dist/client/app/markdoc/custom-components/openapi/openapi-code-sample.js +1 -1
  14. package/dist/client/app/markdoc/custom-components/openapi/use-markdown-adapter.d.ts +1 -33
  15. package/dist/client/app/useGlobalData.d.ts +1 -1
  16. package/dist/client/providers/post-message/use-post-message.d.ts +1 -1
  17. package/dist/compiled/@redocly/pii/index.mjs +1 -0
  18. package/dist/compiled/@redocly/pii/package.json +1 -0
  19. package/dist/compiled/svgo/svgo-node.js +1 -1
  20. package/dist/constants/l10n/langs/ar.js +1 -1
  21. package/dist/constants/l10n/langs/de.js +1 -1
  22. package/dist/constants/l10n/langs/en.js +1 -1
  23. package/dist/constants/l10n/langs/es.js +1 -1
  24. package/dist/constants/l10n/langs/fr.js +1 -1
  25. package/dist/constants/l10n/langs/hi.js +1 -1
  26. package/dist/constants/l10n/langs/it.js +1 -1
  27. package/dist/constants/l10n/langs/ja.js +1 -1
  28. package/dist/constants/l10n/langs/ko.js +1 -1
  29. package/dist/constants/l10n/langs/pl.js +1 -1
  30. package/dist/constants/l10n/langs/pt-BR.js +1 -1
  31. package/dist/constants/l10n/langs/pt.js +1 -1
  32. package/dist/constants/l10n/langs/ru.js +1 -1
  33. package/dist/constants/l10n/langs/uk.js +1 -1
  34. package/dist/constants/l10n/langs/zh.js +1 -1
  35. package/dist/markdoc/attributes/definition-path.d.ts +1 -1
  36. package/dist/markdoc/attributes/json-example-ref.d.ts +1 -1
  37. package/dist/markdoc/attributes/json-schema-ref.d.ts +1 -1
  38. package/dist/markdoc/attributes/parsed-yaml.d.ts +1 -1
  39. package/dist/markdoc/attributes/raw-content.d.ts +1 -1
  40. package/dist/markdoc/attributes/sample-from-json-schema.d.ts +1 -1
  41. package/dist/markdoc/helpers/extract-rbac-from-condition-node.d.ts +1 -1
  42. package/dist/markdoc/helpers/get-inner-text.d.ts +1 -1
  43. package/dist/markdoc/helpers/get-node-attribute.d.ts +1 -1
  44. package/dist/markdoc/helpers/get-variable.d.ts +1 -1
  45. package/dist/markdoc/helpers/guards/is-conditional-node.d.ts +1 -1
  46. package/dist/markdoc/helpers/guards/is-function.d.ts +1 -1
  47. package/dist/markdoc/helpers/guards/is-node.d.ts +1 -1
  48. package/dist/markdoc/helpers/guards/is-prompt-node.d.ts +1 -1
  49. package/dist/markdoc/helpers/guards/is-tag.d.ts +1 -1
  50. package/dist/markdoc/helpers/guards/is-variable.d.ts +1 -1
  51. package/dist/markdoc/helpers/parse-partials.d.ts +1 -1
  52. package/dist/markdoc/helpers/parse-partials.js +1 -1
  53. package/dist/markdoc/helpers/remove-markdoc-tags.js +1 -1
  54. package/dist/markdoc/helpers/set-node-attribute-value.d.ts +1 -1
  55. package/dist/markdoc/nodes/fence/index.d.ts +1 -1
  56. package/dist/markdoc/nodes/fence/index.js +1 -1
  57. package/dist/markdoc/nodes/gfm-list-item.d.ts +1 -1
  58. package/dist/markdoc/nodes/gfm-list-item.js +1 -1
  59. package/dist/markdoc/nodes/heading.d.ts +1 -1
  60. package/dist/markdoc/nodes/heading.js +1 -1
  61. package/dist/markdoc/nodes/index.d.ts +6 -165
  62. package/dist/markdoc/nodes/index.js +1 -1
  63. package/dist/markdoc/nodes/table.d.ts +1 -1
  64. package/dist/markdoc/nodes/table.js +1 -1
  65. package/dist/markdoc/nodes/text.d.ts +1 -1
  66. package/dist/markdoc/tags/json-example.js +1 -1
  67. package/dist/markdoc/tags/openapi-code-sample.js +1 -1
  68. package/dist/server/api-routes/execute-api-route.js +1 -1
  69. package/dist/server/api-routes/run-api-routes-worker.js +1 -1
  70. package/dist/server/config/env-config.d.ts +26 -24
  71. package/dist/server/config/env-schema.d.ts +87 -326
  72. package/dist/server/config/env-schemas/api-urls.d.ts +2 -14
  73. package/dist/server/config/env-schemas/auth.d.ts +10 -32
  74. package/dist/server/config/env-schemas/catalog.d.ts +6 -9
  75. package/dist/server/config/env-schemas/database.d.ts +2 -8
  76. package/dist/server/config/env-schemas/environment-detection.d.ts +20 -18
  77. package/dist/server/config/env-schemas/feature-flags.d.ts +29 -33
  78. package/dist/server/config/env-schemas/feature-flags.js +1 -1
  79. package/dist/server/config/env-schemas/organization-project.d.ts +3 -21
  80. package/dist/server/config/env-schemas/scorecards.d.ts +2 -6
  81. package/dist/server/config/env-schemas/search.d.ts +9 -15
  82. package/dist/server/config/env-schemas/server-config.d.ts +6 -31
  83. package/dist/server/config/env-schemas/site.d.ts +1 -5
  84. package/dist/server/config/env-schemas/ssr.d.ts +7 -12
  85. package/dist/server/config/env-schemas/telemetry.d.ts +1 -7
  86. package/dist/server/constants/common.d.ts +3 -0
  87. package/dist/server/constants/common.js +1 -1
  88. package/dist/server/esbuild/plugins/dependency-resolver.js +1 -1
  89. package/dist/server/esbuild/plugins/themes-resolver.js +3 -3
  90. package/dist/server/external-plugins/resolve-external-plugins.js +1 -1
  91. package/dist/server/node-bundle-entry.js +1 -1
  92. package/dist/server/plugins/api-docs/definition-access.d.ts +22 -0
  93. package/dist/server/plugins/api-docs/definition-access.js +1 -0
  94. package/dist/server/plugins/api-docs/index.js +1 -1
  95. package/dist/server/plugins/api-docs/loader.d.ts +1 -1
  96. package/dist/server/plugins/api-docs/options.js +1 -1
  97. package/dist/server/plugins/api-docs/spec-download.api.js +1 -1
  98. package/dist/server/plugins/config-parser/index.js +1 -1
  99. package/dist/server/plugins/config-parser/loaders/utils/read-and-validate-config.js +1 -1
  100. package/dist/server/plugins/markdown/attribute-resolvers/code-walkthrough/filesets-resolver.d.ts +1 -1
  101. package/dist/server/plugins/markdown/attribute-resolvers/helpers/load-openapi-bundle.d.ts +1 -1
  102. package/dist/server/plugins/markdown/attribute-resolvers/index.d.ts +1 -1
  103. package/dist/server/plugins/markdown/attribute-resolvers/resolve-code-snippet-from-file.d.ts +1 -1
  104. package/dist/server/plugins/markdown/attribute-resolvers/resolve-diagram-from-file.d.ts +1 -1
  105. package/dist/server/plugins/markdown/attribute-resolvers/resolve-html-href.d.ts +1 -1
  106. package/dist/server/plugins/markdown/attribute-resolvers/resolve-html-source-attribute.d.ts +1 -1
  107. package/dist/server/plugins/markdown/attribute-resolvers/resolve-image-gallery.d.ts +1 -1
  108. package/dist/server/plugins/markdown/attribute-resolvers/resolve-image-src-set.d.ts +1 -1
  109. package/dist/server/plugins/markdown/attribute-resolvers/resolve-image-src.d.ts +1 -1
  110. package/dist/server/plugins/markdown/attribute-resolvers/resolve-json-example-ref.d.ts +1 -1
  111. package/dist/server/plugins/markdown/attribute-resolvers/resolve-json-schema-ref.d.ts +1 -1
  112. package/dist/server/plugins/markdown/attribute-resolvers/resolve-link.d.ts +1 -1
  113. package/dist/server/plugins/markdown/attribute-resolvers/resolve-native-md-link.d.ts +1 -1
  114. package/dist/server/plugins/markdown/attribute-resolvers/resolve-nav-links.d.ts +1 -1
  115. package/dist/server/plugins/markdown/attribute-resolvers/resolve-open-api-ref.d.ts +1 -1
  116. package/dist/server/plugins/markdown/attribute-resolvers/resolve-openapi-code-samples.d.ts +1 -1
  117. package/dist/server/plugins/markdown/attribute-resolvers/resolve-openapi-code-samples.js +1 -1
  118. package/dist/server/plugins/markdown/attribute-resolvers/resolve-openapi-response-samples.d.ts +1 -1
  119. package/dist/server/plugins/markdown/attribute-resolvers/resolve-parsed-yaml.d.ts +1 -1
  120. package/dist/server/plugins/markdown/attribute-resolvers/resolve-raw-content.d.ts +1 -1
  121. package/dist/server/plugins/markdown/attribute-resolvers/resolve-relative-or-cdn-icon.d.ts +1 -1
  122. package/dist/server/plugins/markdown/attribute-resolvers/resolve-relative-path.d.ts +1 -1
  123. package/dist/server/plugins/markdown/attribute-resolvers/resolve-sample-from-json-schema.d.ts +1 -1
  124. package/dist/server/plugins/markdown/attribute-resolvers/resolve-svg-content.d.ts +1 -1
  125. package/dist/server/plugins/markdown/attribute-resolvers/resolve-tag-raw-content.d.ts +1 -1
  126. package/dist/server/plugins/markdown/attribute-resolvers/resolve-tag-raw-content.js +2 -2
  127. package/dist/server/plugins/markdown/attribute-resolvers/utils.d.ts +1 -1
  128. package/dist/server/plugins/markdown/compiler.d.ts +1 -1
  129. package/dist/server/plugins/markdown/compiler.js +1 -1
  130. package/dist/server/plugins/markdown/errors.d.ts +1 -1
  131. package/dist/server/plugins/markdown/get-server-props.js +1 -1
  132. package/dist/server/plugins/markdown/html/normalize-html-headings.d.ts +1 -1
  133. package/dist/server/plugins/markdown/html/normalize-html-headings.js +1 -1
  134. package/dist/server/plugins/markdown/markdoc/functions/concat.d.ts +1 -1
  135. package/dist/server/plugins/markdown/markdoc/markdoc-options.d.ts +5 -165
  136. package/dist/server/plugins/markdown/markdoc/markdoc-options.js +1 -1
  137. package/dist/server/plugins/markdown/markdoc/partials.d.ts +1 -1
  138. package/dist/server/plugins/markdown/markdoc/plugins/headings.d.ts +1 -1
  139. package/dist/server/plugins/markdown/markdoc/plugins/utils.d.ts +1 -1
  140. package/dist/server/plugins/markdown/markdoc/reparse-example-fences.d.ts +1 -1
  141. package/dist/server/plugins/markdown/markdoc/reparse-example-fences.js +1 -1
  142. package/dist/server/plugins/markdown/runtime-transform.d.ts +2 -2
  143. package/dist/server/plugins/markdown/runtime-transform.js +1 -1
  144. package/dist/server/plugins/markdown/search/get-ai-search-documents.js +1 -1
  145. package/dist/server/plugins/markdown/search/nodes/section-node.d.ts +1 -1
  146. package/dist/server/plugins/markdown/search/search-resolver.js +1 -1
  147. package/dist/server/plugins/markdown/search/to-markdown.d.ts +1 -1
  148. package/dist/server/plugins/markdown/search/walk-sections.d.ts +1 -1
  149. package/dist/server/plugins/markdown/search/walk-sections.js +1 -1
  150. package/dist/server/plugins/markdown/utils/stringify-tag-children-objects.d.ts +1 -1
  151. package/dist/server/plugins/mcp/codemode/tools/describe-tools.d.ts +1 -1
  152. package/dist/server/plugins/mcp/codemode/tools/describe-tools.js +1 -3
  153. package/dist/server/plugins/mcp/docs-mcp/tools/graphql/get-graphql-type-list.js +1 -1
  154. package/dist/server/plugins/mcp/docs-mcp/tools/graphql/list-graphql-apis.js +1 -1
  155. package/dist/server/plugins/mcp/docs-mcp/tools/graphql/types.d.ts +4 -4
  156. package/dist/server/plugins/mcp/docs-mcp/tools/openapi/list-apis.js +1 -1
  157. package/dist/server/plugins/mcp/docs-mcp/tools/openapi/types.d.ts +2 -2
  158. package/dist/server/plugins/mcp/handlers/docs-mcp-handler.js +1 -1
  159. package/dist/server/plugins/mcp/handlers/errors.d.ts +0 -5
  160. package/dist/server/plugins/mcp/handlers/errors.js +1 -1
  161. package/dist/server/plugins/mcp/handlers/handle-mcp-request.js +1 -1
  162. package/dist/server/plugins/mcp/handlers/mcp-credentials-handler.js +1 -1
  163. package/dist/server/plugins/mcp/servers/docs-server.js +1 -1
  164. package/dist/server/plugins/mcp/servers/mcp-server.js +2 -2
  165. package/dist/server/plugins/mcp/types.d.ts +10 -0
  166. package/dist/server/plugins/mcp/utils/available-tools.d.ts +5 -0
  167. package/dist/server/plugins/mcp/utils/available-tools.js +1 -0
  168. package/dist/server/plugins/mcp/workers/worker-context.d.ts +4 -0
  169. package/dist/server/plugins/mcp/workers/worker-context.js +1 -0
  170. package/dist/server/plugins/scorecard-classic/compute-scorecard.d.ts +2 -2
  171. package/dist/server/plugins/scorecard-classic/compute-scorecard.js +1 -1
  172. package/dist/server/plugins/scorecard-classic/index.js +1 -1
  173. package/dist/server/plugins/scorecard-classic/shared-utils.js +1 -1
  174. package/dist/server/plugins/scorecard-classic/template/Grid/GridHeader.js +3 -3
  175. package/dist/server/plugins/scorecard-classic/template/views.js +1 -1
  176. package/dist/server/plugins/search/engines/typesense/index.js +1 -1
  177. package/dist/server/store-config.d.ts +33 -0
  178. package/dist/server/store-config.js +1 -0
  179. package/dist/server/store.d.ts +11 -16
  180. package/dist/server/store.js +1 -1
  181. package/dist/server/tools/notifiers/formatter.js +3 -3
  182. package/dist/server/tools/notifiers/helpers/colors.d.ts +1 -1
  183. package/dist/server/types/plugins/api-routes.d.ts +4 -1
  184. package/dist/server/types/plugins/common.d.ts +1 -1
  185. package/dist/server/utils/codeframes/codeframes.d.ts +1 -1
  186. package/dist/server/utils/codeframes/yaml-ast.d.ts +1 -1
  187. package/dist/server/utils/decode-request-path.d.ts +2 -0
  188. package/dist/server/utils/decode-request-path.js +1 -0
  189. package/dist/server/utils/envs/env-boolean-string.d.ts +9 -3
  190. package/dist/server/utils/envs/get-api-route-allowed-env-variables.d.ts +2 -0
  191. package/dist/server/utils/envs/get-api-route-allowed-env-variables.js +1 -1
  192. package/dist/server/utils/envs/interpolate-env-variables.d.ts +5 -1
  193. package/dist/server/utils/envs/interpolate-env-variables.js +1 -1
  194. package/dist/server/utils/envs/load-env-variables.js +1 -1
  195. package/dist/server/utils/envs/replace-env-variables-deep.d.ts +17 -9
  196. package/dist/server/utils/envs/replace-env-variables-deep.js +1 -1
  197. package/dist/server/utils/errors.d.ts +3 -0
  198. package/dist/server/utils/errors.js +1 -1
  199. package/dist/server/utils/llmstxt/resolve-llms-txt-md.js +1 -1
  200. package/dist/server/utils/rbac-expand.js +1 -1
  201. package/dist/server/utils/rbac.d.ts +5 -1
  202. package/dist/server/utils/rbac.js +1 -1
  203. package/dist/server/utils/report-all-errors.js +1 -1
  204. package/dist/server/web-server/auth.d.ts +2 -0
  205. package/dist/server/web-server/auth.js +2 -2
  206. package/dist/server/web-server/middleware/jsonValidatorMiddleware.d.ts +5 -325
  207. package/dist/server/web-server/routes/auth.js +1 -1
  208. package/dist/server/web-server/routes/dynamic-route.js +1 -1
  209. package/dist/server/web-server/routes/error.js +1 -1
  210. package/dist/server/web-server/routes/helpers/process-redirects.js +1 -1
  211. package/dist/server/web-server/routes/mcp-routes/mcp-consent-page.d.ts +2 -2
  212. package/dist/server/web-server/routes/mcp-routes/mcp-consent-page.js +18 -18
  213. package/dist/server/web-server/routes/mcp-routes/mcp-oauth.js +1 -1
  214. package/dist/server/web-server/utils/ssrf-safe-lookup.d.ts +2 -1
  215. package/dist/server/web-server/utils/ssrf-safe-lookup.js +1 -1
  216. package/dist/server/workers/mcp-tool-worker-methods.d.ts +7 -0
  217. package/dist/server/workers/mcp-tool-worker-methods.js +1 -0
  218. package/dist/server/workers/mcp-tool-worker-pool.d.ts +0 -1
  219. package/dist/server/workers/mcp-tool-worker-pool.js +1 -1
  220. package/dist/server/workers/mcp-tool-worker.js +1 -1
  221. package/dist/server/workers/types.d.ts +4 -8
  222. package/dist/server/workers/worker-config.d.ts +33 -0
  223. package/dist/server/workers/worker-config.js +1 -0
  224. package/dist/types/errors.d.ts +1 -1
  225. package/dist/types/markdoc.d.ts +1 -1
  226. package/package.json +11 -11
  227. package/dist/server/plugins/markdown/html/html-jsx-attribute-mapping.d.ts +0 -6
  228. package/dist/server/plugins/markdown/html/html-jsx-attribute-mapping.js +0 -1
  229. package/dist/server/plugins/markdown/html/process-html-tokens.d.ts +0 -2
  230. package/dist/server/plugins/markdown/html/process-html-tokens.js +0 -1
  231. package/dist/server/plugins/markdown/source.d.ts +0 -4
  232. package/dist/server/plugins/markdown/source.js +0 -1
  233. package/dist/server/plugins/mcp/utils/available-sandbox-tools.d.ts +0 -4
  234. package/dist/server/plugins/mcp/utils/available-sandbox-tools.js +0 -1
  235. package/dist/server/tools/notifiers/helpers/privacy/mask-email.d.ts +0 -25
  236. package/dist/server/tools/notifiers/helpers/privacy/mask-email.js +0 -1
  237. package/dist/server/tools/notifiers/helpers/privacy/mask-subject.d.ts +0 -13
  238. package/dist/server/tools/notifiers/helpers/privacy/mask-subject.js +0 -1
  239. package/dist/server/tools/notifiers/helpers/privacy/remove-pii-from-url.d.ts +0 -25
  240. package/dist/server/tools/notifiers/helpers/privacy/remove-pii-from-url.js +0 -1
  241. package/dist/server/tools/notifiers/helpers/privacy/remove-pii.d.ts +0 -36
  242. package/dist/server/tools/notifiers/helpers/privacy/remove-pii.js +0 -1
@@ -1,15 +1,19 @@
1
+ import { readEnvVariable } from './read-env-variable.js';
2
+ /** False when `value` has no env variable template. Cheaper than `interpolateEnvVariables`. */
3
+ export declare function mayHaveEnvVariables(value: string): boolean;
1
4
  /**
2
5
  * Interpolates environment variables in a string using the format {{ process.env.VARIABLE_NAME }}.
3
6
  * Supports optional quoted default values applied when the variable is not set,
4
7
  * e.g. {{ process.env.VARIABLE_NAME || "default" }} (both `|` and `||` separators are accepted).
5
8
  *
6
9
  * @param value - The string containing environment variable templates to interpolate
10
+ * @param readEnv - Returns the value of an environment variable; reads `process.env` by default
7
11
  * @returns An object containing:
8
12
  * - interpolatedValue: The string with all environment variables replaced with their values
9
13
  * - unsetVars: Array of environment variable names that were not found and had no default
10
14
  * - interpolatedVars: Array of environment variable names that were successfully resolved
11
15
  */
12
- export declare function interpolateEnvVariables(value: string): {
16
+ export declare function interpolateEnvVariables(value: string, readEnv?: typeof readEnvVariable): {
13
17
  interpolatedValue: string;
14
18
  unsetVars: string[];
15
19
  interpolatedVars: string[];
@@ -1 +1 @@
1
- import{readEnvVariable as d}from"./read-env-variable.js";const i=/{{\s*process\.env\.([A-Z0-9_]+)\s*(?:\|\|?\s*(?:"([^"]*)"|'([^']*)')\s*)?}}/gi;function V(s){let e=s;const t=new Set,r=new Set,c=[...s.matchAll(i)];for(const n of c){const a=n[1].toUpperCase(),o=n[2]??n[3],l=d(a);l!==void 0?(e=e.replace(n[0],l),r.add(a)):o!==void 0?(e=e.replace(n[0],o),r.add(a)):t.add(a)}return{interpolatedValue:e,unsetVars:Array.from(t),interpolatedVars:Array.from(r)}}export{V as interpolateEnvVariables};
1
+ import{readEnvVariable as d}from"./read-env-variable.js";const f=/{{\s*process\.env\.([A-Z0-9_]+)\s*(?:\|\|?\s*(?:"([^"]*)"|'([^']*)')\s*)?}}/gi;function p(a){return a.includes("{{")}function u(a,c=d){let e=a;const s=new Set,t=new Set,i=[...a.matchAll(f)];for(const n of i){const r=n[1].toUpperCase(),o=n[2]??n[3],l=c(r);l!==void 0?(e=e.replace(n[0],l),t.add(r)):o!==void 0?(e=e.replace(n[0],o),t.add(r)):s.add(r)}return{interpolatedValue:e,unsetVars:Array.from(s),interpolatedVars:Array.from(t)}}export{u as interpolateEnvVariables,p as mayHaveEnvVariables};
@@ -1 +1 @@
1
- import*as o from"dotenv";import*as n from"path";import{simpleGit as p}from"simple-git";import{envConfig as s,reloadEnvConfig as c,setEnv as m}from"../../config/env-config.js";import{readEnvVariable as f}from"../../utils/envs/read-env-variable.js";import{sanitizeBranchName as E}from"../../utils/envs/sanitize-branch-name.js";async function l(e){try{return(await p(e??process.cwd()).revparse(["--abbrev-ref","HEAD"])).trim()}catch{return""}}const h=["REDOCLY_EXP_REPLAY_GRAPHQL_ENABLED"];async function N(e){const a=Object.fromEntries(h.map(t=>[t,f(t)]));o.config({path:n.resolve(e??"",".env")}),c();const i=s.PUBLIC_REDOCLY_BRANCH_NAME||await l(e);if(i){const t=E(i);o.config({path:n.resolve(e??"",`.env.branch.${t}`),override:!0}),c()}const v=s.REDOCLY_ENV;let r;switch(v){case"production":r=".env.production";break;case"preview":r=".env.preview";break;default:r=".env.development";break}o.config({path:n.resolve(e??"",r),override:!0}),m(a)}export{N as loadEnvVariables};
1
+ import*as o from"dotenv";import*as n from"path";import{simpleGit as E}from"simple-git";import{envConfig as s,reloadEnvConfig as c,setEnv as p}from"../../config/env-config.js";import{readEnvVariable as m}from"../../utils/envs/read-env-variable.js";import{sanitizeBranchName as f}from"../../utils/envs/sanitize-branch-name.js";async function l(e){try{return(await E(e??process.cwd()).revparse(["--abbrev-ref","HEAD"])).trim()}catch{return""}}const _=["REDOCLY_EXP_REPLAY_GRAPHQL_ENABLED","REDOCLY_EXP_REPLAY_ASYNCAPI_ENABLED"];async function d(e){const a=Object.fromEntries(_.map(t=>[t,m(t)]));o.config({path:n.resolve(e??"",".env")}),c();const i=s.PUBLIC_REDOCLY_BRANCH_NAME||await l(e);if(i){const t=f(i);o.config({path:n.resolve(e??"",`.env.branch.${t}`),override:!0}),c()}const v=s.REDOCLY_ENV;let r;switch(v){case"production":r=".env.production";break;case"preview":r=".env.preview";break;default:r=".env.development";break}o.config({path:n.resolve(e??"",r),override:!0}),p(a)}export{d as loadEnvVariables};
@@ -1,12 +1,20 @@
1
+ import { readEnvVariable } from './read-env-variable.js';
2
+ type EnvReplacement = {
3
+ unsetEnvVars: string[];
4
+ interpolatedEnvVars: string[];
5
+ replacedValues: Record<string, {
6
+ original: string;
7
+ replaced: string;
8
+ }>;
9
+ };
1
10
  /**
2
11
  * Recursively traverses an object or array and interpolates environment variables in all string values.
3
12
  * Keeps track of the path to each modified value and maintains a record of original and replaced values.
4
13
  *
5
14
  * @param obj - The object or array to process
6
- * @param currentPath - Array of keys representing current position in object tree
7
15
  *
8
16
  * @returns An object containing:
9
- * - resolvedObj: The processed object with all environment variables replaced
17
+ * - resolvedObj: A copy of the plain objects and arrays, with all environment variables replaced
10
18
  * - unsetEnvVars: Array of environment variable names that were not found
11
19
  * - interpolatedEnvVars: Array of environment variable names that were successfully resolved
12
20
  * - replacedValues: Record of paths where values were replaced, with original and new values
@@ -14,13 +22,13 @@
14
22
  * For usage examples and test cases, see:
15
23
  * [unit tests](./__tests__/env.test.ts)
16
24
  */
17
- export declare function replaceEnvVariablesDeep<T extends Record<string, unknown> | Array<unknown>>(obj: T, currentPath?: string[]): {
25
+ export declare function replaceEnvVariablesDeep<T extends Record<string, unknown> | Array<unknown>>(obj: T): EnvReplacement & {
18
26
  resolvedObj: T;
19
- unsetEnvVars: string[];
20
- interpolatedEnvVars: string[];
21
- replacedValues: Record<string, {
22
- original: string;
23
- replaced: string;
24
- }>;
25
27
  };
28
+ /**
29
+ * `replaceEnvVariablesDeep` without the copy: changes the strings of `container` in place.
30
+ * `readEnv` returns the value of an environment variable; it reads `process.env` by default.
31
+ */
32
+ export declare function replaceEnvVariablesInPlace(container: object, readEnv?: typeof readEnvVariable): EnvReplacement;
33
+ export {};
26
34
  //# sourceMappingURL=replace-env-variables-deep.d.ts.map
@@ -1 +1 @@
1
- import{isObject as V}from"../../../utils/guards/is-object.js";import{interpolateEnvVariables as E}from"./interpolate-env-variables.js";function u(t,c=[]){const s=new Set,a=new Set,o={};return!V(t)&&!Array.isArray(t)?{resolvedObj:t,unsetEnvVars:Array.from(s),interpolatedEnvVars:Array.from(a),replacedValues:o}:{resolvedObj:Object.entries(t).reduce((i,[d,r])=>{const f=c.concat(d);if(typeof r=="string"){const{interpolatedValue:e,unsetVars:n,interpolatedVars:p}=E(r);i[d]=e;for(const l of n)s.add(l);for(const l of p)a.add(l);p.length>0&&(o[f.join(":")]={original:r,replaced:e})}else if(V(r)||Array.isArray(r)){const e=u(r,f);i[d]=e.resolvedObj;for(const n of e.unsetEnvVars)s.add(n);for(const n of e.interpolatedEnvVars)a.add(n);Object.assign(o,e.replacedValues)}else i[d]=r;return i},Array.isArray(t)?[]:{}),unsetEnvVars:Array.from(s),interpolatedEnvVars:Array.from(a),replacedValues:o}}export{u as replaceEnvVariablesDeep};
1
+ import{isObject as c}from"../../../utils/guards/is-object.js";import{interpolateEnvVariables as E,mayHaveEnvVariables as b}from"./interpolate-env-variables.js";import{readEnvVariable as v}from"./read-env-variable.js";function g(r){const n=p(r);return{resolvedObj:n,...A(n)}}function A(r,n=v){const t=new Set,f=new Set,l={},i=[],V=u=>{const o=u;for(const a in o){const e=o[a];if(typeof e=="string"){if(!b(e))continue;const{interpolatedValue:d,unsetVars:y,interpolatedVars:m}=E(e,n);y.forEach(s=>t.add(s)),m.forEach(s=>f.add(s)),m.length>0&&(o[a]=d,l[[...i,a].join(":")]={original:e,replaced:d})}else(c(e)||Array.isArray(e))&&(i.push(a),V(e),i.pop())}};return(c(r)||Array.isArray(r))&&V(r),{unsetEnvVars:Array.from(t),interpolatedEnvVars:Array.from(f),replacedValues:l}}function p(r){return Array.isArray(r)?r.map(p):c(r)?Object.fromEntries(Object.entries(r).map(([n,t])=>[n,p(t)])):r}export{g as replaceEnvVariablesDeep,A as replaceEnvVariablesInPlace};
@@ -2,4 +2,7 @@ export declare class HttpError extends Error {
2
2
  status: number;
3
3
  constructor(status: number, message: string);
4
4
  }
5
+ export declare class OidcDiscoveryError extends Error {
6
+ constructor(url: string, status: number, contentType: string | null);
7
+ }
5
8
  //# sourceMappingURL=errors.d.ts.map
@@ -1 +1 @@
1
- class t extends Error{status;constructor(s,r){super(r),this.status=s,Object.setPrototypeOf(this,t.prototype)}}export{t as HttpError};
1
+ class r extends Error{status;constructor(t,e){super(e),this.status=t,Object.setPrototypeOf(this,r.prototype)}}class s extends Error{constructor(t,e,o){super(`OIDC discovery failed: ${new URL(t).host} answered HTTP ${e} (${o??"no content type"})`),this.name="OidcDiscoveryError",Object.setPrototypeOf(this,s.prototype)}}export{r as HttpError,s as OidcDiscoveryError};
@@ -1 +1 @@
1
- import i from"path";import{removeLeadingSlash as s}from"../../../utils/url/remove-leading-slash.js";import{fileExistsAsync as l}from"../index.js";async function f(e,o,r){if(r){const t=await r.getPageMarkdown(e);return{exists:t!==void 0,content:t?.content,route:t?.route}}const n=e==="/index.html.md"?"/":e.replace(/\.md$/,"");return{exists:await l(i.resolve(o.outdir,s(e))),content:void 0,route:o.getRouteBySlug(n,{followRedirect:!1})}}export{f as resolveLlmsTxtMd};
1
+ import n from"path";import{removeLeadingSlash as s}from"../../../utils/url/remove-leading-slash.js";import{fileExistsAsync as l}from"../index.js";async function f(e,o,r){if(r){const t=await r.getPageMarkdown(e);return{exists:t!==void 0,content:t?.content,route:t?.route}}const i=e==="/index.html.md"?"/":e.replace(/\.md$/i,"");return{exists:await l(n.resolve(o.outdir,s(e))),content:void 0,route:o.getRouteBySlug(i,{followRedirect:!1})}}export{f as resolveLlmsTxtMd};
@@ -1 +1 @@
1
- import{getHigherRole as c}from"./rbac.js";function R(e,r){if(!e)return;if(!p(e))return e;const o={reunite:{},content:f(e)},n=i(e,r);for(const t of n)o.reunite[t.teamName]=t.projectRole,o.content={...o.content,...Object.fromEntries((e.teamFolders||[]).flatMap(a=>{const l={...e.teamFoldersBaseRoles||{authenticated:"READ"},[t.teamName]:t.projectRole,"redocly.owners":"ADMIN"},m=a.replaceAll("{teamPathSegment}",t.teamPathSegment),s=m+"/**";return[[m,l],[s,l]]}))};return{...e,reunite:{...e.reunite,...o.reunite},content:{...d(e.content||{},o.content)}}}function p(e){return!!(e.teamNamePatterns&&e.teamFolders)}function u(e,r){for(const o of e.teamNamePatterns||[]){if(!o.includes("{teamPathSegment}")&&!o.includes("{projectRole}"))continue;const n="^"+o.replace("{teamPathSegment}","(?<teamPathSegment>[a-zA-Z0-9_.-]+)").replace("{projectRole}","(?<projectRole>admin|maintain|triage|write|read|none)")+"$",a=new RegExp(n,"i").exec(r)?.groups;if(a?.projectRole||a?.teamPathSegment)return{teamName:r,projectRole:a.projectRole?.toUpperCase(),teamPathSegment:a.teamPathSegment?.toLowerCase()}}return null}function g(e,r){for(const o of e?.teamFolders||[]){if(!o.includes("{teamPathSegment}"))continue;const n=`^${o.replace("{teamPathSegment}","(?<teamPathSegment>[a-zA-Z0-9_.-]+)")}($|/)`,t=new RegExp(n,"i");for(const a of r){const l=t.exec(a)?.groups;if(l?.teamPathSegment)return{teamPathSegment:l.teamPathSegment.toLowerCase()}}}return null}function i(e,r){const o=r.map(t=>u(e,t));let n=null;for(const t of o)t?.projectRole&&!t.teamPathSegment&&(n=n?c(n,t.projectRole):t.projectRole);return o.map(t=>!t?.teamPathSegment||!t.projectRole&&!n?null:(t.projectRole=t.projectRole??n??void 0,t)).filter(Boolean)}function f(e){const r={};if(e.teamFoldersBaseRoles)for(const o of e.teamFolders){const n=o.replaceAll("{teamPathSegment}","**");r[n]=e.teamFoldersBaseRoles}return r}function d(e,r){const o={...e};for(const[n,t]of Object.entries(r))o[n]?o[n]={...o[n],...t}:o[n]=t;return o}export{p as canExpandConfig,R as expandRbacConfig,f as getTeamFolderDefaults,g as parseTeamFoldersTemplate,u as parseTeamNameTemplate,i as parseTeams};
1
+ import{getHigherRole as c}from"./rbac.js";function R(e,r){if(!e)return;if(!p(e))return e;const o={platform:{},content:i(e)},n=f(e,r);for(const t of n)o.platform[t.teamName]=t.projectRole,o.content={...o.content,...Object.fromEntries((e.teamFolders||[]).flatMap(a=>{const l={...e.teamFoldersBaseRoles||{authenticated:"READ"},[t.teamName]:t.projectRole,"redocly.owners":"ADMIN"},m=a.replaceAll("{teamPathSegment}",t.teamPathSegment),s=m+"/**";return[[m,l],[s,l]]}))};return{...e,platform:{...e.platform,...o.platform},content:{...d(e.content||{},o.content)}}}function p(e){return!!(e.teamNamePatterns&&e.teamFolders)}function u(e,r){for(const o of e.teamNamePatterns||[]){if(!o.includes("{teamPathSegment}")&&!o.includes("{projectRole}"))continue;const n="^"+o.replace("{teamPathSegment}","(?<teamPathSegment>[a-zA-Z0-9_.-]+)").replace("{projectRole}","(?<projectRole>admin|maintain|triage|write|read|none)")+"$",a=new RegExp(n,"i").exec(r)?.groups;if(a?.projectRole||a?.teamPathSegment)return{teamName:r,projectRole:a.projectRole?.toUpperCase(),teamPathSegment:a.teamPathSegment?.toLowerCase()}}return null}function g(e,r){for(const o of e?.teamFolders||[]){if(!o.includes("{teamPathSegment}"))continue;const n=`^${o.replace("{teamPathSegment}","(?<teamPathSegment>[a-zA-Z0-9_.-]+)")}($|/)`,t=new RegExp(n,"i");for(const a of r){const l=t.exec(a)?.groups;if(l?.teamPathSegment)return{teamPathSegment:l.teamPathSegment.toLowerCase()}}}return null}function f(e,r){const o=r.map(t=>u(e,t));let n=null;for(const t of o)t?.projectRole&&!t.teamPathSegment&&(n=n?c(n,t.projectRole):t.projectRole);return o.map(t=>!t?.teamPathSegment||!t.projectRole&&!n?null:(t.projectRole=t.projectRole??n??void 0,t)).filter(Boolean)}function i(e){const r={};if(e.teamFoldersBaseRoles)for(const o of e.teamFolders){const n=o.replaceAll("{teamPathSegment}","**");r[n]=e.teamFoldersBaseRoles}return r}function d(e,r){const o={...e};for(const[n,t]of Object.entries(r))o[n]?o[n]={...o[n],...t}:o[n]=t;return o}export{p as canExpandConfig,R as expandRbacConfig,i as getTeamFolderDefaults,g as parseTeamFoldersTemplate,u as parseTeamNameTemplate,f as parseTeams};
@@ -2,6 +2,7 @@ import '../node-crypto-polyfill.js';
2
2
  import { REDOCLY_TEAMS_RBAC, REDOCLY_ROUTE_RBAC } from '@redocly/config';
3
3
  import type { RbacConfig, RbacScopeItems, RedoclyConfig, SsoConfig } from '@redocly/config';
4
4
  import type { AuthDetails } from '../types';
5
+ import type { ApiDefinitionAccess } from '../plugins/api-docs/definition-access.js';
5
6
  import type { ContentFs } from '../fs/content-fs.js';
6
7
  import type { RbacFeatures } from '../../constants/common.js';
7
8
  export type ProjectRole = 'NONE' | 'READ' | 'TRIAGE' | 'WRITE' | 'MAINTAIN' | 'ADMIN';
@@ -33,7 +34,7 @@ export declare function canDownloadApiDefinition(pathname: string, rbacConfig: R
33
34
  isAuthenticated?: boolean;
34
35
  email?: string;
35
36
  teams?: string[];
36
- }): boolean;
37
+ }, definitionAccess?: ApiDefinitionAccess): boolean;
37
38
  export declare function canAccessAsset(pathname: string, rbacConfig: RbacConfig, requiresLogin: boolean, directoryPaths: Record<string, string>, user?: {
38
39
  isAuthenticated?: boolean;
39
40
  email?: string;
@@ -145,6 +146,9 @@ export declare const normalizeRbacConfig: (rbacConfig: RbacConfig) => {
145
146
  [x: string]: string;
146
147
  } | undefined;
147
148
  } | undefined;
149
+ platform?: {
150
+ [x: string]: string;
151
+ } | undefined;
148
152
  reunite?: {
149
153
  [x: string]: string;
150
154
  } | undefined;
@@ -1 +1 @@
1
- import R from"path";import P from"picomatch";import"../node-crypto-polyfill.js";import{REDOCLY_TEAMS_RBAC as x,REDOCLY_ROUTE_RBAC as E}from"@redocly/config";import{MCP_ROUTE as U,PUBLIC_MCP_ROUTE as k}from"@redocly/theme/core/constants/mcp";import{ServerRoutes as w}from"../../constants/api.js";import{DEFAULT_ANONYMOUS_VISITOR_TEAM as D,PUBLIC_RBAC_SCOPE_ITEM as y,RBAC_ALL_OTHER_TEAMS as l,DEFAULT_RBAC_SCOPE as L,GRAPHQL_SPEC_SLUG as M}from"../../constants/common.js";import{DEPRECATED_PUBLIC_API_DEFINITIONS_FOLDER as g,PUBLIC_API_DEFINITIONS_FOLDER as C,PUBLIC_ASSETS_FOLDER as B}from"../constants/common.js";import{MCP_CREDENTIALS_ROUTE as b}from"../constants/mcp.js";import{ANONYMOUS_AUTH_DETAILS as W}from"../constants/rbac.js";import{removeTrailingSlash as T}from"../../utils/url/remove-trailing-slash.js";import{removeLeadingSlash as $}from"../../utils/url/remove-leading-slash.js";import{parsePathVersions as v}from"../../utils/path/parse-path-versions.js";import{reporter as Y}from"../tools/notifiers/reporter.js";import{bold as G}from"../tools/notifiers/helpers/colors.js";import{shaDirPathShort as H}from"../utils/crypto/sha-dir-path-short.js";import{isTruthy as z}from"../../utils/guards/is-truthy.js";import{canExpandConfig as K,expandRbacConfig as V,getTeamFolderDefaults as J,parseTeamFoldersTemplate as Q,parseTeamNameTemplate as X}from"./rbac-expand.js";import{getUserParamsFromCookies as Z}from"../web-server/auth.js";import{getDeeperGlobPattern as q}from"./globs.js";import{EntitlementsProvider as tt}from"../entitlements/entitlements-provider.js";const j=["NONE","READ","TRIAGE","WRITE","MAINTAIN","ADMIN"],et=new Set(["x-parsed-md-description","x-parsed-md-summary"]),rt=new Set(Object.values(w).map(t=>T(t.split(":")[0])));function It(t,e){const r=j.indexOf(t.toUpperCase()),n=j.indexOf(e.toUpperCase());return r>n?t:e}const A={};function I(t,e){if(!t?.content)return y;const r=t.content,{slug:n,fsPath:o}=e;if(!n&&!o)return y;const s=a=>{const d=`slug:${a}`,p=A[d]??P(a);A[d]=p;const _=`fsPath:${a}`,S=A[_]??P($(a));return A[_]=S,!!(n&&p(n))||!!(o&&S(o))};if(st(n||o||"")&&Object.keys(r).filter(p=>s(p)).length===0)return r[L]||y;const f=Object.keys(r).filter(a=>s(a));if(f.length==0)return y;const u=f.map(a=>P.scan(a,{tokens:!0,parts:!0}));let h=u[0];for(let a=1;a<u.length;a++)h=q(h,u[a]);return r[h.input]}function F(t,e,r){const n=r?[...e,r]:e,o=[];for(const s of n)t[s]?o.push(t[s]):t[l]&&s!==r&&o.push(t[l]);return o.some(s=>s.toLowerCase()!=="none")}function Ft(t,e,r={},n=!1){if(n&&Object.keys(r).length===0)return e.isAuthenticated;const o=r.features?.[t];return o?F(o,e.teams):!0}function Nt(t,e){return O(t,W,e.access?.rbac||{},e.access?.requiresLogin||!1)}function O(t,e={},r={},n=!1){if(t.slug&&typeof t.slug=="string"&&rt.has(T(t.slug))||(t.slug===U||t.slug===k||t.slug===b)&&tt.instance().canAccessFeature("mcp"))return!0;if(n&&Object.keys(r).length===0)return!!e.isAuthenticated;const o=V(r,e.teams||[]),s=t[x]||I(o,t[E]||{});return Object.keys(s||{}).length===0?!1:Object.keys(s).length===1&&s[l]&&s[l].toLowerCase()!=="none"?!0:F(s,e?.teams||[],e?.email)}function Ut(t,e,r,n){if(!t.startsWith(C)&&!t.startsWith(g))return!0;const o=t.replace(new RegExp(`^${C}/`),"").replace(new RegExp(`^${g}/`),"").replace(new RegExp(`^${M}/`),""),c=o==="."?"":o,i={[E]:{slug:t,fsPath:c},slug:t};return O(i,n,e,r)}function kt(t,e,r,n,o){if(!t.startsWith(B))return!0;const s=t.match(/\..{64}\.([A-Fa-f0-9]{8})\.[^.]+$/)?.[1];if(!s)return!0;const c=n[s];if(!c)return!0;const{base:i,ext:f}=R.parse(t),u=i.split(".")[0],h=f.split(".").join(""),d=c==="."?"":c,p={[E]:{slug:t,fsPath:R.posix.join(d,`${u}.${h}`)},slug:t};return O(p,o,e,r)}async function wt(t,e){const{isAuthenticated:r=!1,idpAccessToken:n,federatedAccessToken:o,federatedIdToken:s,...c}=await Z(t,e),{teams:i=[]}=c;let f;return r?f=i.filter(u=>u!==D):f=[D],{isAuthenticated:r,idpAccessToken:n,teams:f,claims:c}}function N(t,e,r={},n=!1){if(!t)return t;if(Array.isArray(t)){const o=[];for(const s of t){const c=N(s,e,r,n);c!==void 0&&o.push(c)}return o}if(typeof t=="object"){if(!O(t,e,r,n))return;let o=!1;const s={};for(const c in t){if(c===x||c===E)continue;if(et.has(c)){s[c]=t[c];continue}const i=N(t[c],e,r,n);if(!t.link&&(c==="items"||c==="menu"&&t.type==="tab")&&Array.isArray(i)&&i.length===0&&t[c].length!==0){o=!0;continue}i!==void 0&&(s[c]=i),c==="paths"&&nt(i)&&ot(i)}return o?void 0:s}return t}function Mt(t){return typeof t=="string"?t.split(" ").filter(Boolean):Array.isArray(t)?t.map(e=>e.toString()):[]}function Bt(t,e){if(!e)return;const r=e.content;if(!r)return e;const n=Object.entries(r).flatMap(([s,c])=>s===L?[[s,c]]:[[s,c]].concat(t.localeFolders.map(i=>[s.startsWith("/")?`/${i.toLocaleLowerCase()}${s}`:R.posix.join(t.localizationFolder,i,s),c]))),o=Object.fromEntries(n);return{...e,content:o}}async function bt(t,e){if(!e)return{};const r={},n=new Set(t.scan().flatMap(({relativePath:o})=>{const{versionFolderPath:s}=v(o)||{},c=R.dirname(o);return s?[s,c]:c}));for(const o of n)r[H(o)]=o;return r}const m=t=>typeof t=="object"&&t!==null&&!Array.isArray(t);function nt(t){return m(t)&&Object.keys(t).length>0}function ot(t){for(const e of Object.keys(t)){const r=t[e];m(r)&&Object.keys(r).length===0&&delete t[e]}}function st(t){return t?t.split("/").filter(Boolean).some(r=>r.startsWith(".")):!1}const ct=t=>{if(t&&m(t)&&("content"in t&&m(t.content)||"reunite"in t&&m(t.reunite)||"features"in t&&m(t.features)||t.teamFolders&&t.teamNamePatterns)){const e=Object.values(t.content||{});if(e.length===0)return!0;if(e.every(m))return e.every(r=>Object.values(r).every(n=>typeof n=="string"))}return!1},Wt=async t=>{if(t){if(Object.keys(t).length===0)return{};if(ct(t))return it(t);await Y.panicOnContentError(`You are using an incorrect format of ${G("rbac:")} configuration. See: https://redocly.com/docs/realm/access`)}},it=t=>{const e={...t};if(e.content){const r={};for(const n in e.content)if(e.content[n]!==void 0){const o=T(n);r[o]=e.content[n]}e.content=r}return e};function $t(t,e){const r=t.fsPath,n=t.slug,o=[],s=K(e)&&(r||n)?Q(e,[r,n].filter(z)):null;if(s){const i=e?.teamNamePatterns?.map(f=>f.replace("{teamPathSegment}",s.teamPathSegment).replace("{projectRole}","read"))??[];o.push(...i)}const c=I(s?{content:{...J(e),...e.content}}:e,t);return o.push(...at(c)),ft(e,o)}function at(t){if(!t)return[];const e=[],r=l in t?{authenticated:t[l],anonymous:t[l]}:{};for(const[n,o]of Object.entries({...r,...t}))o.toLowerCase()!=="none"&&n!==l&&e.push(n);return e}function ft(t,e){return e.map(n=>X(t,n)??{teamName:n}).map(n=>n.projectRole&&n.projectRole!=="READ"?n.teamName?.toLowerCase().replace(n.projectRole?.toLowerCase?.()??"","read")??"":n.teamName?.toLowerCase()??"")}export{j as PROJECT_ROLES_ORDERED_BY_ACCESS_LEVEL,Bt as applyL10nToRbacConfig,kt as canAccessAsset,Ft as canAccessFeature,O as canAccessResource,Ut as canDownloadApiDefinition,ft as expandTeamsForRead,at as extractTeamsFromScopeItems,N as filterDataByAccessDeep,wt as getAuthDetailsFromCookies,It as getHigherRole,$t as getRbacTeamsListForResource,I as getScopeItemsForResource,F as hasScopeAccess,ct as isRbacConfigValid,Nt as isResourcePubliclyAccessible,it as normalizeRbacConfig,Wt as parseRbacConfig,Mt as parseTeamClaimToArray,bt as resolveDirectoryHashes};
1
+ import y from"path";import O from"picomatch";import"../node-crypto-polyfill.js";import{REDOCLY_TEAMS_RBAC as T,REDOCLY_ROUTE_RBAC as R}from"@redocly/config";import{MCP_ROUTE as U,PUBLIC_MCP_ROUTE as k}from"@redocly/theme/core/constants/mcp";import{ServerRoutes as w}from"../../constants/api.js";import{DEFAULT_ANONYMOUS_VISITOR_TEAM as D,PUBLIC_RBAC_SCOPE_ITEM as _,RBAC_ALL_OTHER_TEAMS as l,DEFAULT_RBAC_SCOPE as x,GRAPHQL_SPEC_SLUG as B}from"../../constants/common.js";import{DEPRECATED_PUBLIC_API_DEFINITIONS_FOLDER as g,PUBLIC_API_DEFINITIONS_FOLDER as I,PUBLIC_ASSETS_FOLDER as b,RUNTIME_RESOURCES_DIR as $,SCORECARD_CLASSIC_FOLDER as W,SITEMAP_FILE_NAME as v,LLMS_TXT_FILE_NAME as Y}from"../constants/common.js";import{MCP_CREDENTIALS_ROUTE as G}from"../constants/mcp.js";import{ANONYMOUS_AUTH_DETAILS as H}from"../constants/rbac.js";import{removeTrailingSlash as S}from"../../utils/url/remove-trailing-slash.js";import{removeLeadingSlash as z}from"../../utils/url/remove-leading-slash.js";import{parsePathVersions as K}from"../../utils/path/parse-path-versions.js";import{reporter as V}from"../tools/notifiers/reporter.js";import{bold as J}from"../tools/notifiers/helpers/colors.js";import{shaDirPathShort as Q}from"../utils/crypto/sha-dir-path-short.js";import{isTruthy as X}from"../../utils/guards/is-truthy.js";import{isPathInFolder as C}from"../../utils/path/is-path-in-folder.js";import{canExpandConfig as Z,expandRbacConfig as q,getTeamFolderDefaults as tt,parseTeamFoldersTemplate as et,parseTeamNameTemplate as rt}from"./rbac-expand.js";import{getUserParamsFromCookies as nt}from"../web-server/auth.js";import{getDeeperGlobPattern as ot}from"./globs.js";import{EntitlementsProvider as st}from"../entitlements/entitlements-provider.js";const j=["NONE","READ","TRIAGE","WRITE","MAINTAIN","ADMIN"],ct=new Set(["x-parsed-md-description","x-parsed-md-summary"]),at=new Set(Object.values(w).map(t=>S(t.split(":")[0])));function wt(t,e){const r=j.indexOf(t.toUpperCase()),n=j.indexOf(e.toUpperCase());return r>n?t:e}const P={};function F(t,e){if(!t?.content)return _;const r=t.content,{slug:n,fsPath:o}=e;if(!n&&!o)return _;const s=f=>{const E=`slug:${f}`,p=P[E]??O(f);P[E]=p;const A=`fsPath:${f}`,L=P[A]??O(z(f));return P[A]=L,!!(n&&p(n))||!!(o&&L(o))};if(ut(n||o||"")&&Object.keys(r).filter(p=>s(p)).length===0)return r[x]||_;const i=Object.keys(r).filter(f=>s(f));if(i.length==0)return _;const u=i.map(f=>O.scan(f,{tokens:!0,parts:!0}));let h=u[0];for(let f=1;f<u.length;f++)h=ot(h,u[f]);return r[h.input]}function N(t,e,r){const n=r?[...e,r]:e,o=[];for(const s of n)t[s]?o.push(t[s]):t[l]&&s!==r&&o.push(t[l]);return o.some(s=>s.toLowerCase()!=="none")}function Bt(t,e,r={},n=!1){if(n&&Object.keys(r).length===0)return e.isAuthenticated;const o=r.features?.[t];return o?N(o,e.teams):!0}function bt(t,e){return d(t,H,e.access?.rbac||{},e.access?.requiresLogin||!1)}function d(t,e={},r={},n=!1){if(t.slug&&typeof t.slug=="string"&&at.has(S(t.slug))||(t.slug===U||t.slug===k||t.slug===G)&&st.instance().canAccessFeature("mcp"))return!0;if(n&&Object.keys(r).length===0)return!!e.isAuthenticated;const o=q(r,e.teams||[]),s=t[T]||F(o,t[R]||{});return Object.keys(s||{}).length===0?!1:Object.keys(s).length===1&&s[l]&&s[l].toLowerCase()!=="none"?!0:N(s,e?.teams||[],e?.email)}function $t(t,e,r,n,o){if(!t.startsWith(I)&&!t.startsWith(g))return!0;if(o){const u={[T]:o.rbac,[R]:{slug:o.slug,fsPath:o.sourcePath}};return d(u,n,e,r)}const s=t.replace(new RegExp(`^${I}/`),"").replace(new RegExp(`^${g}/`),"").replace(new RegExp(`^${B}/`),""),a=s==="."?"":s,i={[R]:{slug:t,fsPath:a},slug:t};return d(i,n,e,r)}function Wt(t,e,r,n,o){if(!C(t,b))return[`/${v}`,`/${Y}`].includes(t)||[$,W].some(A=>C(t,A));const s=t.match(/\..{64}\.([A-Fa-f0-9]{8})\.[^.]+$/)?.[1];if(!s)return!0;const c=n[s];if(!c)return!0;const{base:a,ext:i}=y.parse(t),u=a.split(".")[0],h=i.split(".").join(""),E=c==="."?"":c,p={[R]:{slug:t,fsPath:y.posix.join(E,`${u}.${h}`)},slug:t};return d(p,o,e,r)}async function vt(t,e){const{isAuthenticated:r=!1,idpAccessToken:n,federatedAccessToken:o,federatedIdToken:s,...c}=await nt(t,e),{teams:a=[]}=c;let i;return r?i=a.filter(u=>u!==D):i=[D],{isAuthenticated:r,idpAccessToken:n,teams:i,claims:c}}function M(t,e,r={},n=!1){if(!t)return t;if(Array.isArray(t)){const o=[];for(const s of t){const c=M(s,e,r,n);c!==void 0&&o.push(c)}return o}if(typeof t=="object"){if(!d(t,e,r,n))return;let o=!1;const s={};for(const c in t){if(c===T||c===R)continue;if(ct.has(c)){s[c]=t[c];continue}const a=M(t[c],e,r,n);if(!t.link&&(c==="items"||c==="menu"&&t.type==="tab")&&Array.isArray(a)&&a.length===0&&t[c].length!==0){o=!0;continue}a!==void 0&&(s[c]=a),c==="paths"&&it(a)&&ft(a)}return o?void 0:s}return t}function Yt(t){return typeof t=="string"?t.split(" ").filter(Boolean):Array.isArray(t)?t.map(e=>e.toString()):[]}function Gt(t,e){if(!e)return;const r=e.content;if(!r)return e;const n=Object.entries(r).flatMap(([s,c])=>s===x?[[s,c]]:[[s,c]].concat(t.localeFolders.map(a=>[s.startsWith("/")?`/${a.toLocaleLowerCase()}${s}`:y.posix.join(t.localizationFolder,a,s),c]))),o=Object.fromEntries(n);return{...e,content:o}}async function Ht(t,e){if(!e)return{};const r={},n=new Set(t.scan().flatMap(({relativePath:o})=>{const{versionFolderPath:s}=K(o)||{},c=y.dirname(o);return s?[s,c]:c}));for(const o of n)r[Q(o)]=o;return r}const m=t=>typeof t=="object"&&t!==null&&!Array.isArray(t);function it(t){return m(t)&&Object.keys(t).length>0}function ft(t){for(const e of Object.keys(t)){const r=t[e];m(r)&&Object.keys(r).length===0&&delete t[e]}}function ut(t){return t?t.split("/").filter(Boolean).some(r=>r.startsWith(".")):!1}const lt=t=>{if(t&&m(t)&&("content"in t&&m(t.content)||"platform"in t&&m(t.platform)||"features"in t&&m(t.features)||t.teamFolders&&t.teamNamePatterns)){const e=Object.values(t.content||{});if(e.length===0)return!0;if(e.every(m))return e.every(r=>Object.values(r).every(n=>typeof n=="string"))}return!1},zt=async t=>{if(t){if(Object.keys(t).length===0)return{};if(lt(t))return mt(t);await V.panicOnContentError(`You are using an incorrect format of ${J("rbac:")} configuration. See: https://redocly.com/docs/realm/access`)}},mt=t=>{const e={...t};if(e.content){const r={};for(const n in e.content)if(e.content[n]!==void 0){const o=S(n);r[o]=e.content[n]}e.content=r}return e};function Kt(t,e){const r=t.fsPath,n=t.slug,o=[],s=Z(e)&&(r||n)?et(e,[r,n].filter(X)):null;if(s){const a=e?.teamNamePatterns?.map(i=>i.replace("{teamPathSegment}",s.teamPathSegment).replace("{projectRole}","read"))??[];o.push(...a)}const c=F(s?{content:{...tt(e),...e.content}}:e,t);return o.push(...pt(c)),ht(e,o)}function pt(t){if(!t)return[];const e=[],r=l in t?{authenticated:t[l],anonymous:t[l]}:{};for(const[n,o]of Object.entries({...r,...t}))o.toLowerCase()!=="none"&&n!==l&&e.push(n);return e}function ht(t,e){return e.map(n=>rt(t,n)??{teamName:n}).map(n=>n.projectRole&&n.projectRole!=="READ"?n.teamName?.toLowerCase().replace(n.projectRole?.toLowerCase?.()??"","read")??"":n.teamName?.toLowerCase()??"")}export{j as PROJECT_ROLES_ORDERED_BY_ACCESS_LEVEL,Gt as applyL10nToRbacConfig,Wt as canAccessAsset,Bt as canAccessFeature,d as canAccessResource,$t as canDownloadApiDefinition,ht as expandTeamsForRead,pt as extractTeamsFromScopeItems,M as filterDataByAccessDeep,vt as getAuthDetailsFromCookies,wt as getHigherRole,Kt as getRbacTeamsListForResource,F as getScopeItemsForResource,N as hasScopeAccess,lt as isRbacConfigValid,bt as isResourcePubliclyAccessible,mt as normalizeRbacConfig,zt as parseRbacConfig,Yt as parseTeamClaimToArray,Ht as resolveDirectoryHashes};
@@ -1 +1 @@
1
- import{envConfig as p}from"../config/env-config.js";import{logger as l}from"../tools/notifiers/logger.js";import{reporter as r}from"../tools/notifiers/reporter.js";import{isMarkdocError as d}from"../plugins/markdown/errors.js";import{telemetryTraceStep as g}from"../../cli/telemetry/helpers/trace-step.js";import{writeProblemsReport as u}from"./write-problems-report.js";async function M(e){await g("com.redocly.build.validationErrors",async o=>{let t=0;for(const[c,f]of e.cache.errors.entries()){const m=c.split(":")[1];for(const i of f)d(i)?(r.reportMarkdocProblem(i),i.type!=="BROKEN_LINK"&&t++):await r.panicOnBuild(i.message,m)}const a=await e.getConfig();if(!p.isBuildMode)return;const n=r.getPageRenderProblems().length;o?.setAttribute("markdocErrors",t.toString()),o?.setAttribute("pageRenderErrors",n.toString()),t>0&&!a?.reunite?.ignoreMarkdocErrors?await s(`Need to fix ${t} Markdoc issue(s) or set the \`ignoreMarkdocErrors\` option to \`true\` in the \`reunite\` section of your \`redocly.yaml\``):n>0&&await s(`Need to fix ${n} runtime error(s) in React pages`)})}async function s(e){r.printErrors();try{u()}catch(o){l.warn("Failed to write the problems report: "+o.message)}await r.panic(e)}export{M as reportAllErrors};
1
+ import{envConfig as p}from"../config/env-config.js";import{logger as l}from"../tools/notifiers/logger.js";import{reporter as r}from"../tools/notifiers/reporter.js";import{isMarkdocError as d}from"../plugins/markdown/errors.js";import{telemetryTraceStep as g}from"../../cli/telemetry/helpers/trace-step.js";import{writeProblemsReport as u}from"./write-problems-report.js";async function M(o){await g("com.redocly.build.validationErrors",async e=>{let t=0;for(const[c,f]of o.cache.errors.entries()){const m=c.split(":")[1];for(const i of f)d(i)?(r.reportMarkdocProblem(i),i.type!=="BROKEN_LINK"&&t++):await r.panicOnBuild(i.message,m)}const n=await o.getConfig();if(!p.isBuildMode)return;const s=r.getPageRenderProblems().length;e?.setAttribute("markdocErrors",t.toString()),e?.setAttribute("pageRenderErrors",s.toString()),t>0&&!n?.platform?.ignoreMarkdocErrors?await a(`Need to fix ${t} Markdoc issue(s) or set the \`ignoreMarkdocErrors\` option to \`true\` in the \`platform\` section of your \`redocly.yaml\``):s>0&&await a(`Need to fix ${s} runtime error(s) in React pages`)})}async function a(o){r.printErrors();try{u()}catch(e){l.warn("Failed to write the problems report: "+e.message)}await r.panic(o)}export{M as reportAllErrors};
@@ -160,7 +160,9 @@ export declare const oidcJwksCache: {
160
160
  export declare const UNKNOWN_KID_RETRY_MS = 60000;
161
161
  export declare function getOidcMetadata(idpId: string, providerConfig: OidcProviderConfig): Promise<OidcIssuerMetadata>;
162
162
  export declare function discoverJwks(ssoConfig: SsoConfig): Promise<void>;
163
+ export declare const OIDC_DISCOVERY_RETRY_MS = 60000;
163
164
  export declare function getRedoclyTokenPayload(token: string): Promise<Record<string, unknown>>;
165
+ export declare function exchangeTokenLoginCode(code: string): Promise<string | undefined>;
164
166
  export declare function isRedoclySso(config: OidcProviderConfig): boolean;
165
167
  export declare function verifySAMLResponse(responseXml: string, cert: string): Promise<boolean>;
166
168
  export declare function orderTeamsRbacFirst(teams: string[], rbacConfig: RbacConfig | undefined, teamsMapping: Record<string, string> | undefined): string[];
@@ -1,4 +1,4 @@
1
- import"../node-crypto-polyfill.js";import{DOMParser as j}from"@xmldom/xmldom";import{SignedXml as Z}from"xml-crypto";import ee from"xpath";import{deflateSync as te,inflateSync as ne}from"fflate";import{createHash as re}from"crypto";import{ulid as oe}from"ulid";import{AuthProviderType as f,DEFAULT_TEAM_CLAIM_NAME as U}from"@redocly/config";import{ALTERNATIVE_AUD_CLAIM_NAME as se,AUTH_URL as ie,JWT_SECRET_KEY as y,MAX_AUTH_TOKEN_COOKIE_BYTES as ae}from"../constants/common.js";import{ensureArray as R}from"../../utils/array/ensure-array.js";import{envConfig as ce}from"../config/env-config.js";import{decryptClaimValue as ue}from"../utils/crypto/decrypt-claim-value.js";import{decryptAesGcm as de}from"../utils/crypto/decrypt-aes-gcm.js";import{encryptAesGcm as le}from"../utils/crypto/encrypt-aes-gcm.js";import{getPathPrefix as me,withPathPrefix as pe,withoutPathPrefix as fe}from"@redocly/theme/core/utils";import{ServerRoutes as K}from"../../constants/api.js";import{AuthCookieNames as I,DEFAULT_AUTHENTICATED_TEAM as he,REQUIRED_OIDC_SCOPES as V}from"../../constants/common.js";import{appendQueryParams as ye}from"../../utils/url/append-query-params.js";import{parsePreviewUrl as B}from"../../utils/url/parse-preview-url.js";import{logger as O}from"../tools/notifiers/logger.js";import{randomString as Ae}from"../utils/crypto/random-string.js";import{randomUUID as M}from"../utils/crypto/random-uuid.js";import{AlgorithmTypes as l,JwtTokenExpired as _e}from"./jwt/types.js";import*as p from"./jwt/jwt.js";import{InternalTokenTypes as x}from"./jwt/token-types.js";import{parseTeamClaimToArray as we}from"../utils/index.js";import{parseTeamNameTemplate as Se}from"../utils/rbac-expand.js";import{arrayBufferToBase64 as Te,decodeBase64 as $,encodeBase64URL as xe,urlSafeBase64 as F}from"./jwt/encode.js";import{formatSamlCertificate as ge}from"./utils/format-saml-certificate.js";const Ie=new Set(Object.values(x));function g(e){return e?.type===f.OIDC}function Ee(e){return e?.type===f.SAML2}async function Mt(e,t){if(g(t))return ke(e,t);if(Ee(t))return Re(e,t)}async function ke(e,t){const n=await G(e,t),r=new Set((t.scopes||[]).concat(V)),o=t.authorizationRequestCustomParams||{};return{type:f.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 Re(e,t){return{type:f.SAML2,idpId:e,name:"SAML2 provider",ssoUrl:t.ssoUrl,issuerId:t.issuerId,entityId:t.entityId||t.issuerId}}function H(e){return Array.from(new Set((e.scopes||[]).concat(V))).join(" ")}async function W(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 Lt(e,t,n,r,o={}){return await W(e,r,{scope:H(r),code:t,redirect_uri:J(n),grant_type:"authorization_code",...o})}async function Nt(e,t,n){return await W(e,n,{scope:H(n),grant_type:"refresh_token",refresh_token:t})}function Oe(e,{authorizationEndpoint:t,clientId:n,responseType:r,scope:o,extraParams:s,idpId:i,pkce:c},d,h,u){if(!t||!n||!r||!o)return{loginUrl:void 0};const a=new URL(t),_=u?.redirectUriOverride??`${e}${pe(K.OIDC_CALLBACK)}`,S={state:M(),idpId:i,redirectUri:_,redirectTo:d,branch:u?.branchOverride??De(e),inviteCode:h,source:u?.sourceOverride??"portal",uiLocales:u?.uiLocales},T={};if(c){const A=F(Ae(50)),E=F(re("sha256").update(A).digest("base64")),k="S256";a.searchParams.append("code_challenge",E),a.searchParams.append("code_challenge_method",k),T.code_verifier={value:A,options:{secure:!0,httpOnly:!0,expires:new Date(Date.now()+1e3*60*10),path:me()||"/"}}}a.searchParams.append("client_id",n),a.searchParams.append("scope",o),a.searchParams.append("response_type",r),a.searchParams.append("redirect_uri",J(_)),a.searchParams.append("state",xe(JSON.stringify(S))),u?.uiLocales&&a.searchParams.append("ui_locales",u.uiLocales);for(const A in s)s[A]!==void 0&&a.searchParams.append(A,s[A]);return{loginUrl:a.toString(),cookies:T}}function Dt(e,t,n,r){const o=new URL(e);return n&&(o.searchParams.append("post_logout_redirect_uri",t),r&&o.searchParams.append("state",r),o.searchParams.append("id_token_hint",n)),o.toString()}function Me(e,t){const n=R(t?.audience??[]);return!n.length||z(e,n)}function z(e,t){const n=[e.aud,e[se]].flat();return t.some(r=>r!==""&&n.includes(r))}function Le(e,t){return!t||!g(t)?!0:Me(e,t)&&Ne(e,t)}function Ne(e,t){return!g(t)||!Ye(t)||!t.clientId?!0:R(e.aud||[]).includes(t.clientId)}function Ct(e){if(!e)return!1;try{return p.decode(e).header.alg===l.RS256}catch{return!1}}async function bt(e){const t=Math.floor(Date.now()/1e3),n=t+(e.ttlSec??600);return p.sign({type:x.MCP_AUTHORIZATION_CODE,client_id:e.clientId,redirect_uri:e.redirectUri,id_token_enc:le(e.idToken,y),...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,l.HS256)}async function Pt(e){await p.verify(e,y,l.HS256);const{payload:t}=p.decode(e);if(t.type!==x.MCP_AUTHORIZATION_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");if(typeof t.id_token_enc!="string")throw new Error("Authorization code missing session");return{...t,id_token:de(t.id_token_enc,y)}}async function vt(e){const t=Math.floor(Date.now()/1e3);return p.sign({type:x.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,jti:M()},y,l.HS256)}async function jt(e){await p.verify(e,y,l.HS256);const{payload:t}=p.decode(e);if(t.type!==x.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 Ut(e){const t=e||oe(),n=t.startsWith("mcp_")?t:`mcp_${t}`;return{id:n,object:"mcpSession",uri:`urn:redocly:realm:mcp:session:${n}`}}function J(e){const t=B(e);if(!t)return e;const n=Ce(t.hostname);if(n)return t.hostname=`previewauth--${n.previewBranch}${n.after}`,Y(e,t);const r=q(t.hostname);return r?(t.hostname=`${r.projectSlug}.previewauth.${r.after}`,Y(e,t)):e}function De(e){const t=B(e);if(t)return q(t.hostname)?.previewBranch}function Y(e,t){const n=e.replace(/^https?:\/\/[^/?#]+/i,"");return`${t.protocol}//${t.host}${fe(n)}`}function q(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),i=n.slice(o+2);return!s||!i||i.includes(".")?null:{projectSlug:s,previewBranch:i,after:r}}function Ce(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 be(e){return e.type===f.OIDC}function Pe(e){return e.type===f.SAML2}function Kt(e,t,n,r,o){return be(e)?Oe(t,e,n,r,{uiLocales:o}):Pe(e)?ve(t,e,n,r,o):{}}function ve(e,t,n,r,o){const i=`<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
1
+ import"../node-crypto-polyfill.js";import{DOMParser as j}from"@xmldom/xmldom";import{SignedXml as ne}from"xml-crypto";import re from"xpath";import{deflateSync as oe,inflateSync as se}from"fflate";import{createHash as ie}from"crypto";import{ulid as ae}from"ulid";import{AuthProviderType as p,DEFAULT_TEAM_CLAIM_NAME as U}from"@redocly/config";import{ALTERNATIVE_AUD_CLAIM_NAME as ce,AUTH_URL as V,JWT_SECRET_KEY as y,MAX_AUTH_TOKEN_COOKIE_BYTES as ue}from"../constants/common.js";import{ensureArray as O}from"../../utils/array/ensure-array.js";import{envConfig as de}from"../config/env-config.js";import{decryptClaimValue as le}from"../utils/crypto/decrypt-claim-value.js";import{decryptAesGcm as fe}from"../utils/crypto/decrypt-aes-gcm.js";import{encryptAesGcm as me}from"../utils/crypto/encrypt-aes-gcm.js";import{getPathPrefix as pe,withPathPrefix as he,withoutPathPrefix as ye}from"@redocly/theme/core/utils";import{ServerRoutes as K}from"../../constants/api.js";import{AuthCookieNames as I,DEFAULT_AUTHENTICATED_TEAM as Ae,REQUIRED_OIDC_SCOPES as $}from"../../constants/common.js";import{appendQueryParams as we}from"../../utils/url/append-query-params.js";import{parsePreviewUrl as B}from"../../utils/url/parse-preview-url.js";import{logger as E}from"../tools/notifiers/logger.js";import{OidcDiscoveryError as F}from"../utils/errors.js";import{randomString as _e}from"../utils/crypto/random-string.js";import{randomUUID as M}from"../utils/crypto/random-uuid.js";import{AlgorithmTypes as l,JwtTokenExpired as Se}from"./jwt/types.js";import*as m from"./jwt/jwt.js";import{InternalTokenTypes as g}from"./jwt/token-types.js";import{parseTeamClaimToArray as Te}from"../utils/index.js";import{parseTeamNameTemplate as ge}from"../utils/rbac-expand.js";import{arrayBufferToBase64 as xe,decodeBase64 as H,encodeBase64URL as Ie,urlSafeBase64 as z}from"./jwt/encode.js";import{formatSamlCertificate as Ee}from"./utils/format-saml-certificate.js";const ke=new Set(Object.values(g));function x(e){return e?.type===p.OIDC}function Re(e){return e?.type===p.SAML2}async function Ct(e,t){if(x(t))return Oe(e,t);if(Re(t))return Me(e,t)}async function Oe(e,t){const n=await X(e,t),r=new Set((t.scopes||[]).concat($)),o=t.authorizationRequestCustomParams||{};return{type:p.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 Me(e,t){return{type:p.SAML2,idpId:e,name:"SAML2 provider",ssoUrl:t.ssoUrl,issuerId:t.issuerId,entityId:t.entityId||t.issuerId}}function W(e){return Array.from(new Set((e.scopes||[]).concat($))).join(" ")}async function J(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 bt(e,t,n,r,o={}){return await J(e,r,{scope:W(r),code:t,redirect_uri:q(n),grant_type:"authorization_code",...o})}async function vt(e,t,n){return await J(e,n,{scope:W(n),grant_type:"refresh_token",refresh_token:t})}function De(e,{authorizationEndpoint:t,clientId:n,responseType:r,scope:o,extraParams:s,idpId:i,pkce:c},d,h,u){if(!t||!n||!r||!o)return{loginUrl:void 0};const a=new URL(t),w=u?.redirectUriOverride??`${e}${he(K.OIDC_CALLBACK)}`,S={state:M(),idpId:i,redirectUri:w,redirectTo:d,branch:u?.branchOverride??be(e),inviteCode:h,source:u?.sourceOverride??"portal",uiLocales:u?.uiLocales},T={};if(c){const A=z(_e(50)),k=z(ie("sha256").update(A).digest("base64")),R="S256";a.searchParams.append("code_challenge",k),a.searchParams.append("code_challenge_method",R),T.code_verifier={value:A,options:{secure:!0,httpOnly:!0,expires:new Date(Date.now()+1e3*60*10),path:pe()||"/"}}}a.searchParams.append("client_id",n),a.searchParams.append("scope",o),a.searchParams.append("response_type",r),a.searchParams.append("redirect_uri",q(w)),a.searchParams.append("state",Ie(JSON.stringify(S))),u?.uiLocales&&a.searchParams.append("ui_locales",u.uiLocales);for(const A in s)s[A]!==void 0&&a.searchParams.append(A,s[A]);return{loginUrl:a.toString(),cookies:T}}function Pt(e,t,n,r){const o=new URL(e);return n&&(o.searchParams.append("post_logout_redirect_uri",t),r&&o.searchParams.append("state",r),o.searchParams.append("id_token_hint",n)),o.toString()}function Le(e,t){const n=O(t?.audience??[]);return!n.length||Y(e,n)}function Y(e,t){const n=[e.aud,e[ce]].flat();return t.some(r=>r!==""&&n.includes(r))}function Ne(e,t){return!t||!x(t)?!0:Le(e,t)&&Ce(e,t)}function Ce(e,t){return!x(t)||!Qe(t)||!t.clientId?!0:O(e.aud||[]).includes(t.clientId)}function jt(e){if(!e)return!1;try{return m.decode(e).header.alg===l.RS256}catch{return!1}}async function Ut(e){const t=Math.floor(Date.now()/1e3),n=t+(e.ttlSec??600);return m.sign({type:g.MCP_AUTHORIZATION_CODE,client_id:e.clientId,redirect_uri:e.redirectUri,id_token_enc:me(e.idToken,y),...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,l.HS256)}async function Vt(e){await m.verify(e,y,l.HS256);const{payload:t}=m.decode(e);if(t.type!==g.MCP_AUTHORIZATION_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");if(typeof t.id_token_enc!="string")throw new Error("Authorization code missing session");return{...t,id_token:fe(t.id_token_enc,y)}}async function Kt(e){const t=Math.floor(Date.now()/1e3);return m.sign({type:g.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,jti:M()},y,l.HS256)}async function $t(e){await m.verify(e,y,l.HS256);const{payload:t}=m.decode(e);if(t.type!==g.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 Bt(e){const t=e||ae(),n=t.startsWith("mcp_")?t:`mcp_${t}`;return{id:n,object:"mcpSession",uri:`urn:redocly:realm:mcp:session:${n}`}}function q(e){const t=B(e);if(!t)return e;const n=ve(t.hostname);if(n)return t.hostname=`previewauth--${n.previewBranch}${n.after}`,G(e,t);const r=Q(t.hostname);return r?(t.hostname=`${r.projectSlug}.previewauth.${r.after}`,G(e,t)):e}function be(e){const t=B(e);if(t)return Q(t.hostname)?.previewBranch}function G(e,t){const n=e.replace(/^https?:\/\/[^/?#]+/i,"");return`${t.protocol}//${t.host}${ye(n)}`}function Q(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),i=n.slice(o+2);return!s||!i||i.includes(".")?null:{projectSlug:s,previewBranch:i,after:r}}function ve(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 Pe(e){return e.type===p.OIDC}function je(e){return e.type===p.SAML2}function Ft(e,t,n,r,o){return Pe(e)?De(t,e,n,r,{uiLocales:o}):je(e)?Ue(t,e,n,r,o):{}}function Ue(e,t,n,r,o){const i=`<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="_${M()}"
@@ -9,4 +9,4 @@ import"../node-crypto-polyfill.js";import{DOMParser as j}from"@xmldom/xmldom";im
9
9
  <samlp:NameIDPolicy
10
10
  AllowCreate="true"
11
11
  Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"/>
12
- </samlp:AuthnRequest>`,c=je(i);return{loginUrl:ye(t.ssoUrl,{SAMLRequest:c,RelayState:JSON.stringify({idpId:t.idpId,redirectTo:n,inviteCode:r,source:"portal",uiLocales:o})})}}function je(e){return Te(te(new TextEncoder().encode(e)).buffer)}function Vt(e){const t=$(e);if(t.startsWith("<samlp:Response")||t.indexOf("<saml2p:Response")>-1)return t;const n=ne(new Uint8Array(atob(e).split("").map(r=>r.charCodeAt(0))));return new TextDecoder().decode(n)}function Bt(e){try{return JSON.parse($(e||""))}catch{throw new Error("Invalid OAuth2 state")}}function $t(e){const t=new j().parseFromString(e,"application/xml"),r=m(t,"//*[local-name(.)='StatusCode']/@Value")[0]?.nodeValue?.endsWith("Success")||!1,s=m(t,"//*[local-name(.)='Response']/@Destination")[0]?.nodeValue||"",i=m(t,"//*[local-name(.)='Assertion']//*[local-name(.)='Issuer']/text()")[0],c=i&&i.nodeValue||void 0,d=m(t,"//*[local-name(.)='Audience']/text()")[0],h=d&&d.nodeValue||void 0,a=m(t,"//*[local-name(.)='Assertion']//*[local-name(.)='X509Certificate']/text()")[0]?.nodeValue||"",_=m(t,"//*[local-name(.)='Subject']//*[local-name(.)='NameID']/text()")[0],S=_&&_.nodeValue||"",T=m(t,"//*[local-name(.)='Subject']//*[local-name(.)='NameID']/@Format")[0],A=T&&T.nodeValue||"",E=m(t,"//*[local-name(.)='Conditions']/@NotOnOrAfter")[0],k=Ue(E),D={},C=m(t,"//*[local-name(.)='AttributeStatement']//*[local-name(.)='Attribute']");if(C.length)for(const b of C){const P=m(b,"./@Name")[0];if(P.nodeValue){const v=m(b,"./*[local-name(.)='AttributeValue']/text()")[0];v?.nodeValue&&(D[P.nodeValue]=v.nodeValue)}}return{uid:S,success:r,expiresAt:k,issuerId:c,entityId:h,attrs:D,cert:a,nameFormat:A,destination:s}}function Ue(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 N={},w={jwks:{},missedAt:{}},Ke=6e4;function Ve(e){const t=w.jwks[e];return t===void 0?!0:t===null&&Date.now()-(w.missedAt[e]??0)>=Ke}async function G(e,t){if(!N[e]){const n=t.configurationUrl?await Q(t.configurationUrl):t.configuration;N[e]=Be()?Fe(n):n}return N[e]}function Be(){const e=ce.REDOCLY_ENFORCE_RESIDENCY;return!!e&&e.includes("host.docker.internal")}const $e=["authorization_endpoint","end_session_endpoint"];function Fe(e){if(typeof e!="object"||e===null)return e;const t={...e};for(const n of Object.keys(t)){if($e.includes(String(n)))continue;const r=t[n];typeof r=="string"&&r.includes("://localhost")&&(t[n]=r.replace("://localhost","://host.docker.internal"))}return t}const He=["kty","n","e","crv","x","y"];function We(e,t){return He.every(n=>e[n]===t[n])}async function ze(e){const t={};for(const n of Object.keys(e)){const r=e[n];if(!g(r))continue;const o=await G(n,r);if(o.jwks_uri){const s=await Q(o.jwks_uri);for(const i of s.keys){const c=t[i.kid],d=c&&We(c,i)?[...c.idpIds,n]:[n];t[i.kid]={...i,idpIds:d},w.jwks[i.kid]=t[i.kid]}}}}function Je(e,t,n){const r=w.jwks[e]?.idpIds??[];return r.find(o=>{const s=n[o];if(!g(s))return!1;const i=R(s.audience??[]);return z(t,i.length?i:[s.clientId])})??r.at(-1)}async function Q(e){return fetch(e,{headers:{Accept:"application/json"}}).then(t=>t.json())}async function Ft(e){return fetch(`${ie}/oidc/userinfo`,{headers:{Accept:"application/json",Authorization:`Bearer ${e}`}}).then(t=>t.status===200?t.json():void 0).catch(()=>{})}function Ye(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"].some(r=>qe(t.hostname,r))}function qe(e,t){return e===t||e.endsWith(`.${t}`)}async function Ht(e,t){const n=new j().parseFromString(e,"application/xml"),r=m(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=ge(t),s=new Z({publicCert:o});s.loadSignature(r);try{return s.checkSignature(e)}catch{return!1}}function Ge(e){const t=new Set,n=r=>{if(!(!r||typeof r!="object"||Array.isArray(r)))for(const[o,s]of Object.entries(r))typeof s=="string"?t.add(o):n(s)};return n(e),t}function Qe(e,t,n){if(!t)return e;const r=Ge(t),o=s=>{const i=n?.[s]||s;return r.has(i)||!!Se(t,i)};return[...e.filter(o),...e.filter(s=>!o(s))]}async function Wt(e,t,n,r){const o=n?e[n]:void 0,s=Array.isArray(o)?Qe(o.map(String),r?.rbacConfig,r?.teamsMapping):[];let i=s.length;const c=s.length+1;for(let d=0;d<c;d++){const h={...e,idpId:t};n&&s.length&&(h[n]=s.slice(0,i));const u=await p.sign(h,y,l.HS256),a=Buffer.byteLength(u)-ae;if(a<=0)return{token:u,teamsTotal:s.length,teamsKept:i,droppedTeams:s.slice(i)};if(i===0)return null;const _=Buffer.byteLength(JSON.stringify(s.slice(0,i))),S=Math.max(1,_/i*4/3);i=Math.max(0,i-Math.max(1,Math.ceil(a/S)))}return null}function zt(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(/^.+@.+/m)&&(o=e);const s=n["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"],i=s?.match(/^.+@.+/m);return o=o||n["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"]||(i?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?we(n[r]):[]}}function X(e,t={}){return e.map(n=>t[n]||n)}async function Jt(e,t){if(!t)return{};const n=t[I.AUTHORIZATION];if(!n)return{};try{const r=p.decode(n);if(typeof r.payload.type=="string"&&Ie.has(r.payload.type))return{};if(r.header.alg===l.RS256){const h=Ve(r.header.kid);h&&await ze(e);const u=w.jwks[r.header.kid];if(!u)return h&&(w.missedAt[r.header.kid]=Date.now()),w.jwks[r.header.kid]=null,{};await p.verify(n,u,l.RS256)}else await p.verify(n,y,l.HS256);const s=r.header.alg===l.RS256?Je(r.header.kid,r.payload,e):r.payload.idpId,i=e[s]||{};if(r.header.alg===l.RS256&&typeof r.payload.exp!="number")return O.warn("Rejected id_token: it has no exp claim"),{};if(r.header.alg===l.RS256&&!Le(r.payload,i))return O.warn("Rejected id_token: it was issued for another project"),{};const c=et(i),d=Ze(i);return{...r.payload,email:r.payload.email?.toLowerCase(),idpId:s,teams:Array.from(new Set([...X(r.payload.teams||[],d),..."defaultTeams"in i&&i.defaultTeams||[],...X("teamsClaimName"in i&&r.payload[c||""]||[],d),he])),name:Xe(r.payload),isAuthenticated:!0,idpAccessToken:ue(r.payload.idp_access_token,y)||t[I.IDP_ACCESS_TOKEN],federatedAccessToken:t[I.FEDERATED_ACCESS_TOKEN],federatedIdToken:t[I.FEDERATED_ID_TOKEN],authCookie:n}}catch(r){r instanceof _e||O.error("Malformed JWT token: %s",r.message)}return{}}function Xe(e){return(e.firstName&&e.lastName?`${e.firstName} ${e.lastName}`:e.name||e.given_name||e.firstName||e.lastName)||e.email}function Ze(e){switch(e.type){case f.SAML2:return e.teamsAttributeMap;case f.OIDC:return e.teamsClaimMap;default:return}}function et(e){switch(e.type){case f.SAML2:return e.teamsAttributeName??U;case f.OIDC:return e.teamsClaimName;default:return U}}function m(e,t){return ee.select(t,e)||[]}export{Ke as UNKNOWN_KID_RETRY_MS,Kt as buildLoginUrl,Oe as buildOidcLoginUrl,Dt as buildOidcLogoutUrl,ve as buildSAML2LoginUrl,bt as createMcpAuthorizationCode,vt as createMcpRefreshToken,Ut as createMcpSessionResource,Vt as decodeSamlResponse,ze as discoverJwks,je as encodeSAML2,zt as extractUserClaims,Mt as getAuthProviderLoginParams,ke as getOidcLoginParams,G as getOidcMetadata,Ft as getRedoclyTokenPayload,Re as getSaml2LoginParams,Jt as getUserParamsFromCookies,Xe as getUsernameFromPayload,Me as idTokenAudienceIsAllowed,Le as idTokenIsForThisProject,Ct as isIdpIssuedToken,g as isOidcProviderConfig,Ye as isRedoclySso,Ee as isSaml2ProviderConfig,Lt as oidcExchangeCodeForToken,w as oidcJwksCache,N as oidcMetadataCache,Nt as oidcRefreshTokenGrant,Qe as orderTeamsRbacFirst,Bt as parseOidcState,De as parsePreviewBranch,$t as parseSamlResponse,J as rewritePreviewAuthRedirectUri,Wt as signTokenWithinCookieSizeLimit,Pt as verifyMcpAuthorizationCode,jt as verifyMcpRefreshToken,Ht as verifySAMLResponse};
12
+ </samlp:AuthnRequest>`,c=Ve(i);return{loginUrl:we(t.ssoUrl,{SAMLRequest:c,RelayState:JSON.stringify({idpId:t.idpId,redirectTo:n,inviteCode:r,source:"portal",uiLocales:o})})}}function Ve(e){return xe(oe(new TextEncoder().encode(e)).buffer)}function Ht(e){const t=H(e);if(t.startsWith("<samlp:Response")||t.indexOf("<saml2p:Response")>-1)return t;const n=se(new Uint8Array(atob(e).split("").map(r=>r.charCodeAt(0))));return new TextDecoder().decode(n)}function zt(e){try{return JSON.parse(H(e||""))}catch{throw new Error("Invalid OAuth2 state")}}function Wt(e){const t=new j().parseFromString(e,"application/xml"),r=f(t,"//*[local-name(.)='StatusCode']/@Value")[0]?.nodeValue?.endsWith("Success")||!1,s=f(t,"//*[local-name(.)='Response']/@Destination")[0]?.nodeValue||"",i=f(t,"//*[local-name(.)='Assertion']//*[local-name(.)='Issuer']/text()")[0],c=i&&i.nodeValue||void 0,d=f(t,"//*[local-name(.)='Audience']/text()")[0],h=d&&d.nodeValue||void 0,a=f(t,"//*[local-name(.)='Assertion']//*[local-name(.)='X509Certificate']/text()")[0]?.nodeValue||"",w=f(t,"//*[local-name(.)='Subject']//*[local-name(.)='NameID']/text()")[0],S=w&&w.nodeValue||"",T=f(t,"//*[local-name(.)='Subject']//*[local-name(.)='NameID']/@Format")[0],A=T&&T.nodeValue||"",k=f(t,"//*[local-name(.)='Conditions']/@NotOnOrAfter")[0],R=Ke(k),N={},C=f(t,"//*[local-name(.)='AttributeStatement']//*[local-name(.)='Attribute']");if(C.length)for(const b of C){const v=f(b,"./@Name")[0];if(v.nodeValue){const P=f(b,"./*[local-name(.)='AttributeValue']/text()")[0];P?.nodeValue&&(N[v.nodeValue]=P.nodeValue)}}return{uid:S,success:r,expiresAt:R,issuerId:c,entityId:h,attrs:N,cert:a,nameFormat:A,destination:s}}function Ke(e){const t=typeof e?.nodeValue=="string"&&D(Date.parse(e.nodeValue)),n=D(Date.now()),r=D(Date.now()+720*60*1e3);return t?t>n&&t<r?r:t:n}function D(e){return Math.floor(e/1e3)}const L={},_={jwks:{},missedAt:{}},$e=6e4;function Be(e){const t=_.jwks[e];return t===void 0?!0:t===null&&Date.now()-(_.missedAt[e]??0)>=$e}async function X(e,t){if(!L[e]){const n=t.configurationUrl?await ee(t.configurationUrl):t.configuration;L[e]=Fe()?ze(n):n}return L[e]}function Fe(){const e=de.REDOCLY_ENFORCE_RESIDENCY;return!!e&&e.includes("host.docker.internal")}const He=["authorization_endpoint","end_session_endpoint"];function ze(e){if(typeof e!="object"||e===null)return e;const t={...e};for(const n of Object.keys(t)){if(He.includes(String(n)))continue;const r=t[n];typeof r=="string"&&r.includes("://localhost")&&(t[n]=r.replace("://localhost","://host.docker.internal"))}return t}const We=["kty","n","e","crv","x","y"];function Je(e,t){return We.every(n=>e[n]===t[n])}async function Ye(e){const t={};for(const n of Object.keys(e)){const r=e[n];if(!x(r))continue;const o=await X(n,r);if(o.jwks_uri){const s=await ee(o.jwks_uri);for(const i of s.keys){const c=t[i.kid],d=c&&Je(c,i)?[...c.idpIds,n]:[n];t[i.kid]={...i,idpIds:d},_.jwks[i.kid]=t[i.kid]}}}}function qe(e,t,n){const r=_.jwks[e]?.idpIds??[];return r.find(o=>{const s=n[o];if(!x(s))return!1;const i=O(s.audience??[]);return Y(t,i.length?i:[s.clientId])})??r.at(-1)}const Ge=6e4,Z={};async function ee(e){const t=Z[e];if(t&&Date.now()-t.failedAt<Ge)throw t.error;const n=await fetch(e,{headers:{Accept:"application/json"}}),r=n.ok?await n.json().catch(()=>{}):void 0;if(r===void 0){const o=new F(e,n.status,n.headers.get("content-type"));throw Z[e]={error:o,failedAt:Date.now()},o}return r}async function Jt(e){return fetch(`${V}/oidc/userinfo`,{headers:{Accept:"application/json",Authorization:`Bearer ${e}`}}).then(t=>t.status===200?t.json():void 0).catch(()=>{})}async function Yt(e){return fetch(`${V}/api/auth/organization-session/login-code/exchange`,{method:"POST",headers:{Accept:"application/json","Content-Type":"application/json"},body:JSON.stringify({code:e})}).then(t=>t.status===200?t.json():void 0).then(t=>typeof t?.token=="string"?t.token:void 0).catch(()=>{})}function Qe(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"].some(r=>Xe(t.hostname,r))}function Xe(e,t){return e===t||e.endsWith(`.${t}`)}async function qt(e,t){const n=new j().parseFromString(e,"application/xml"),r=f(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=Ee(t),s=new ne({publicCert:o});s.loadSignature(r);try{return s.checkSignature(e)}catch{return!1}}function Ze(e){const t=new Set,n=r=>{if(!(!r||typeof r!="object"||Array.isArray(r)))for(const[o,s]of Object.entries(r))typeof s=="string"?t.add(o):n(s)};return n(e),t}function et(e,t,n){if(!t)return e;const r=Ze(t),o=s=>{const i=n?.[s]||s;return r.has(i)||!!ge(t,i)};return[...e.filter(o),...e.filter(s=>!o(s))]}async function Gt(e,t,n,r){const o=n?e[n]:void 0,s=Array.isArray(o)?et(o.map(String),r?.rbacConfig,r?.teamsMapping):[];let i=s.length;const c=s.length+1;for(let d=0;d<c;d++){const h={...e,idpId:t};n&&s.length&&(h[n]=s.slice(0,i));const u=await m.sign(h,y,l.HS256),a=Buffer.byteLength(u)-ue;if(a<=0)return{token:u,teamsTotal:s.length,teamsKept:i,droppedTeams:s.slice(i)};if(i===0)return null;const w=Buffer.byteLength(JSON.stringify(s.slice(0,i))),S=Math.max(1,w/i*4/3);i=Math.max(0,i-Math.max(1,Math.ceil(a/S)))}return null}function Qt(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(/^.+@.+/m)&&(o=e);const s=n["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"],i=s?.match(/^.+@.+/m);return o=o||n["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"]||(i?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?Te(n[r]):[]}}function te(e,t={}){return e.map(n=>t[n]||n)}async function Xt(e,t){if(!t)return{};const n=t[I.AUTHORIZATION];if(!n)return{};try{const r=m.decode(n);if(typeof r.payload.type=="string"&&ke.has(r.payload.type))return{};if(r.header.alg===l.RS256){const h=Be(r.header.kid);h&&await Ye(e);const u=_.jwks[r.header.kid];if(!u)return h&&(_.missedAt[r.header.kid]=Date.now()),_.jwks[r.header.kid]=null,{};await m.verify(n,u,l.RS256)}else await m.verify(n,y,l.HS256);const s=r.header.alg===l.RS256?qe(r.header.kid,r.payload,e):r.payload.idpId,i=e[s]||{};if(r.header.alg===l.RS256&&typeof r.payload.exp!="number")return E.warn("Rejected id_token: it has no exp claim"),{};if(r.header.alg===l.RS256&&!Ne(r.payload,i))return E.warn("Rejected id_token: it was issued for another project"),{};const c=rt(i),d=nt(i);return{...r.payload,email:r.payload.email?.toLowerCase(),idpId:s,teams:Array.from(new Set([...te(r.payload.teams||[],d),..."defaultTeams"in i&&i.defaultTeams||[],...te("teamsClaimName"in i&&r.payload[c||""]||[],d),Ae])),name:tt(r.payload),isAuthenticated:!0,idpAccessToken:le(r.payload.idp_access_token,y)||t[I.IDP_ACCESS_TOKEN],federatedAccessToken:t[I.FEDERATED_ACCESS_TOKEN],federatedIdToken:t[I.FEDERATED_ID_TOKEN],authCookie:n}}catch(r){r instanceof Se||(r instanceof F?E.error(r.message):E.error("Malformed JWT token: %s",r.message))}return{}}function tt(e){return(e.firstName&&e.lastName?`${e.firstName} ${e.lastName}`:e.name||e.given_name||e.firstName||e.lastName)||e.email}function nt(e){switch(e.type){case p.SAML2:return e.teamsAttributeMap;case p.OIDC:return e.teamsClaimMap;default:return}}function rt(e){switch(e.type){case p.SAML2:return e.teamsAttributeName??U;case p.OIDC:return e.teamsClaimName;default:return U}}function f(e,t){return re.select(t,e)||[]}export{Ge as OIDC_DISCOVERY_RETRY_MS,$e as UNKNOWN_KID_RETRY_MS,Ft as buildLoginUrl,De as buildOidcLoginUrl,Pt as buildOidcLogoutUrl,Ue as buildSAML2LoginUrl,Ut as createMcpAuthorizationCode,Kt as createMcpRefreshToken,Bt as createMcpSessionResource,Ht as decodeSamlResponse,Ye as discoverJwks,Ve as encodeSAML2,Yt as exchangeTokenLoginCode,Qt as extractUserClaims,Ct as getAuthProviderLoginParams,Oe as getOidcLoginParams,X as getOidcMetadata,Jt as getRedoclyTokenPayload,Me as getSaml2LoginParams,Xt as getUserParamsFromCookies,tt as getUsernameFromPayload,Le as idTokenAudienceIsAllowed,Ne as idTokenIsForThisProject,jt as isIdpIssuedToken,x as isOidcProviderConfig,Qe as isRedoclySso,Re as isSaml2ProviderConfig,bt as oidcExchangeCodeForToken,_ as oidcJwksCache,L as oidcMetadataCache,vt as oidcRefreshTokenGrant,et as orderTeamsRbacFirst,zt as parseOidcState,be as parsePreviewBranch,Wt as parseSamlResponse,q as rewritePreviewAuthRedirectUri,Gt as signTokenWithinCookieSizeLimit,Vt as verifyMcpAuthorizationCode,$t as verifyMcpRefreshToken,qt as verifySAMLResponse};