@redocly/realm 0.135.0 → 0.136.0-next.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (205) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/dist/cli/build/analytics/collect-analytics.js +1 -1
  3. package/dist/cli/build/analytics/collectors/get-skills-usage.d.ts +3 -0
  4. package/dist/cli/build/analytics/collectors/get-skills-usage.js +1 -0
  5. package/dist/client/templates/openapi-docs/helpers.js +1 -1
  6. package/dist/constants/common.d.ts +8 -0
  7. package/dist/constants/common.js +1 -1
  8. package/dist/server/api-routes/execute-api-route.js +1 -1
  9. package/dist/server/api-routes/helpers/enhance-context.d.ts +3 -1
  10. package/dist/server/api-routes/helpers/enhance-context.js +1 -1
  11. package/dist/server/api-routes/helpers/is-mock-server.d.ts +2 -0
  12. package/dist/server/api-routes/helpers/is-mock-server.js +1 -0
  13. package/dist/server/api-routes/mock-server/kv-state-store.d.ts +3 -0
  14. package/dist/server/api-routes/mock-server/kv-state-store.js +1 -0
  15. package/dist/server/api-routes/mock-server/mock-js-executor.d.ts +3 -0
  16. package/dist/server/api-routes/mock-server/mock-js-executor.js +13 -0
  17. package/dist/server/config/env-config.d.ts +4 -0
  18. package/dist/server/config/env-schema.d.ts +10 -0
  19. package/dist/server/config/env-schemas/catalog.d.ts +3 -0
  20. package/dist/server/config/env-schemas/catalog.js +1 -1
  21. package/dist/server/config/env-schemas/feature-flags.d.ts +4 -0
  22. package/dist/server/config/env-schemas/feature-flags.js +1 -1
  23. package/dist/server/constants/plugins/search.d.ts +1 -2
  24. package/dist/server/constants/plugins/search.js +1 -1
  25. package/dist/server/esbuild/plugins/on-rebuild.js +1 -1
  26. package/dist/server/fs/fs.js +1 -1
  27. package/dist/server/plugins/catalog-entities/database/catalog-entities-diff-publisher.d.ts +27 -0
  28. package/dist/server/plugins/catalog-entities/database/catalog-entities-diff-publisher.js +12 -0
  29. package/dist/server/plugins/catalog-entities/database/catalog-entities-publisher.js +1 -12
  30. package/dist/server/plugins/catalog-entities/database/catalog-entities-revisions-pruner.d.ts +20 -0
  31. package/dist/server/plugins/catalog-entities/database/catalog-entities-revisions-pruner.js +42 -0
  32. package/dist/server/plugins/catalog-entities/database/consts.d.ts +5 -0
  33. package/dist/server/plugins/catalog-entities/database/consts.js +1 -1
  34. package/dist/server/plugins/catalog-entities/database/repositories/entities/entities-write-repository.js +1 -1
  35. package/dist/server/plugins/catalog-entities/extensions/extractors/api-description/arazzo-entities-extractor.js +1 -1
  36. package/dist/server/plugins/catalog-entities/extensions/extractors/api-description/asyncapi-entities-extractor.js +1 -1
  37. package/dist/server/plugins/catalog-entities/extensions/extractors/api-description/graphql-entities-extractor.js +2 -2
  38. package/dist/server/plugins/catalog-entities/extensions/extractors/api-description/openapi-entities-extractor.js +1 -1
  39. package/dist/server/plugins/catalog-entities/plugin.js +1 -1
  40. package/dist/server/plugins/config-parser/loaders/redocly-config-loader.js +1 -1
  41. package/dist/server/plugins/lifecycle.js +2 -2
  42. package/dist/server/plugins/mcp/{docs-mcp/codemode → codemode}/build-tool-type-declarations.d.ts +1 -1
  43. package/dist/server/plugins/mcp/codemode/capabilities/fetch/index.d.ts +4 -0
  44. package/dist/server/plugins/mcp/codemode/capabilities/fetch/index.js +4 -0
  45. package/dist/server/plugins/mcp/codemode/capabilities/index.d.ts +3 -0
  46. package/dist/server/plugins/mcp/codemode/capabilities/index.js +1 -0
  47. package/dist/server/plugins/mcp/codemode/capabilities/registry.d.ts +4 -0
  48. package/dist/server/plugins/mcp/codemode/capabilities/registry.js +1 -0
  49. package/dist/server/plugins/mcp/codemode/capabilities/types.d.ts +13 -0
  50. package/dist/server/plugins/mcp/codemode/capabilities/utils.d.ts +13 -0
  51. package/dist/server/plugins/mcp/codemode/capabilities/utils.js +7 -0
  52. package/dist/server/plugins/mcp/codemode/constants.d.ts +8 -0
  53. package/dist/server/plugins/mcp/codemode/constants.js +1 -0
  54. package/dist/server/plugins/mcp/codemode/invoke-tool.d.ts +4 -0
  55. package/dist/server/plugins/mcp/codemode/invoke-tool.js +1 -0
  56. package/dist/server/plugins/mcp/codemode/prompts.d.ts +6 -0
  57. package/dist/server/plugins/mcp/codemode/prompts.js +4 -0
  58. package/dist/server/plugins/mcp/codemode/sandbox/create-sandbox-setup.d.ts +10 -0
  59. package/dist/server/plugins/mcp/codemode/sandbox/create-sandbox-setup.js +11 -0
  60. package/dist/server/plugins/mcp/codemode/sandbox/polyfills.d.ts +2 -0
  61. package/dist/server/plugins/mcp/codemode/sandbox/polyfills.js +99 -0
  62. package/dist/server/plugins/mcp/codemode/tools/describe-tools.d.ts +7 -0
  63. package/dist/server/plugins/mcp/codemode/tools/describe-tools.js +1 -0
  64. package/dist/server/plugins/mcp/codemode/tools/execute-schema.d.ts +5 -0
  65. package/dist/server/plugins/mcp/codemode/tools/execute-schema.js +1 -0
  66. package/dist/server/plugins/mcp/codemode/tools/execute.js +1 -0
  67. package/dist/server/plugins/mcp/codemode/types.d.ts +16 -0
  68. package/dist/server/plugins/mcp/codemode/types.js +0 -0
  69. package/dist/server/plugins/mcp/constants.d.ts +2 -0
  70. package/dist/server/plugins/mcp/constants.js +1 -1
  71. package/dist/server/plugins/mcp/docs-mcp/tool-schemas.d.ts +0 -4
  72. package/dist/server/plugins/mcp/docs-mcp/tool-schemas.js +1 -1
  73. package/dist/server/plugins/mcp/docs-mcp/tools/openapi/list-apis.js +1 -1
  74. package/dist/server/plugins/mcp/docs-mcp/utils.js +1 -1
  75. package/dist/server/plugins/mcp/gateway-mcp/eligibility.d.ts +30 -0
  76. package/dist/server/plugins/mcp/gateway-mcp/eligibility.js +1 -0
  77. package/dist/server/plugins/mcp/gateway-mcp/fetch/allowed-hosts.d.ts +13 -0
  78. package/dist/server/plugins/mcp/gateway-mcp/fetch/allowed-hosts.js +1 -0
  79. package/dist/server/plugins/mcp/gateway-mcp/fetch/fetch-bridge.d.ts +12 -0
  80. package/dist/server/plugins/mcp/gateway-mcp/fetch/fetch-bridge.js +1 -0
  81. package/dist/server/plugins/mcp/gateway-mcp/fetch/ssrf-guard.d.ts +9 -0
  82. package/dist/server/plugins/mcp/gateway-mcp/fetch/ssrf-guard.js +1 -0
  83. package/dist/server/plugins/mcp/gateway-mcp/fetch-capability.d.ts +6 -0
  84. package/dist/server/plugins/mcp/gateway-mcp/fetch-capability.js +1 -0
  85. package/dist/server/plugins/mcp/handlers/docs-mcp-handler.js +1 -1
  86. package/dist/server/plugins/mcp/handlers/errors.d.ts +3 -21
  87. package/dist/server/plugins/mcp/handlers/errors.js +1 -1
  88. package/dist/server/plugins/mcp/handlers/handle-mcp-request.js +1 -1
  89. package/dist/server/plugins/mcp/index.js +1 -1
  90. package/dist/server/plugins/mcp/servers/docs-server.d.ts +5 -10
  91. package/dist/server/plugins/mcp/servers/docs-server.js +1 -3
  92. package/dist/server/plugins/mcp/servers/mcp-server.d.ts +18 -0
  93. package/dist/server/plugins/mcp/servers/mcp-server.js +1 -0
  94. package/dist/server/plugins/mcp/types.d.ts +23 -8
  95. package/dist/server/plugins/mcp/utils/mode.d.ts +7 -0
  96. package/dist/server/plugins/mcp/utils/mode.js +1 -0
  97. package/dist/server/plugins/mcp/utils/xmcp-utils.d.ts +12 -60
  98. package/dist/server/plugins/mcp/utils/xmcp-utils.js +1 -1
  99. package/dist/server/plugins/mcp/utils.d.ts +8 -0
  100. package/dist/server/plugins/mcp/utils.js +1 -1
  101. package/dist/server/plugins/mcp/workers/execute-mcp-tool.js +1 -1
  102. package/dist/server/plugins/mcp/workers/mcp-tool-telemetry.d.ts +15 -3
  103. package/dist/server/plugins/mcp/workers/mcp-tool-telemetry.js +1 -1
  104. package/dist/server/plugins/openapi-docs/index.js +1 -1
  105. package/dist/server/plugins/search/engines/search-engine.d.ts +2 -1
  106. package/dist/server/plugins/search/index.js +1 -1
  107. package/dist/server/plugins/skills/discover-skills.d.ts +17 -0
  108. package/dist/server/plugins/skills/discover-skills.js +1 -0
  109. package/dist/server/plugins/skills/index.d.ts +3 -0
  110. package/dist/server/plugins/skills/index.js +1 -0
  111. package/dist/server/plugins/skills/utils/parse-skill.d.ts +18 -0
  112. package/dist/server/plugins/skills/utils/parse-skill.js +1 -0
  113. package/dist/server/plugins/sso/index.js +1 -1
  114. package/dist/server/sandbox/constants/host-functions.d.ts +3 -0
  115. package/dist/server/sandbox/constants/host-functions.js +1 -0
  116. package/dist/server/sandbox/constants/sandbox.d.ts +6 -0
  117. package/dist/server/sandbox/constants/sandbox.js +1 -0
  118. package/dist/server/sandbox/sandbox.d.ts +8 -0
  119. package/dist/server/sandbox/sandbox.js +3 -0
  120. package/dist/server/sandbox/types.d.ts +24 -0
  121. package/dist/server/sandbox/types.js +0 -0
  122. package/dist/server/sandbox/utils/eval-guest-code.d.ts +15 -0
  123. package/dist/server/sandbox/utils/eval-guest-code.js +1 -0
  124. package/dist/server/sandbox/utils/execution-budget.d.ts +11 -0
  125. package/dist/server/sandbox/utils/execution-budget.js +1 -0
  126. package/dist/server/sandbox/utils/setup-host-functions.d.ts +18 -0
  127. package/dist/server/sandbox/utils/setup-host-functions.js +5 -0
  128. package/dist/server/store.d.ts +4 -0
  129. package/dist/server/store.js +1 -1
  130. package/dist/server/types/plugins/common.d.ts +3 -0
  131. package/dist/server/types/plugins/search.d.ts +0 -1
  132. package/dist/server/types/plugins/skills.d.ts +16 -0
  133. package/dist/server/types/plugins/skills.js +0 -0
  134. package/dist/server/utils/cookie.d.ts +3 -0
  135. package/dist/server/utils/cookie.js +1 -1
  136. package/dist/server/utils/fetch-with-client.d.ts +10 -0
  137. package/dist/server/utils/fetch-with-client.js +1 -0
  138. package/dist/server/utils/skills/can-access-skill.d.ts +9 -0
  139. package/dist/server/utils/skills/can-access-skill.js +1 -0
  140. package/dist/server/utils/skills/get-accessible-skills.d.ts +5 -0
  141. package/dist/server/utils/skills/get-accessible-skills.js +1 -0
  142. package/dist/server/utils/skills/get-skill-url.d.ts +2 -0
  143. package/dist/server/utils/skills/get-skill-url.js +1 -0
  144. package/dist/server/web-server/auth.js +4 -4
  145. package/dist/server/web-server/middleware/apiKeyMiddleware.js +1 -1
  146. package/dist/server/web-server/middleware/catalogAuthMiddleware.js +1 -1
  147. package/dist/server/web-server/middleware/corsMiddleware.d.ts +1 -0
  148. package/dist/server/web-server/middleware/corsMiddleware.js +1 -1
  149. package/dist/server/web-server/middleware/ensureSearchData.js +1 -1
  150. package/dist/server/web-server/routes/ask-ai.js +1 -1
  151. package/dist/server/web-server/routes/auth.js +1 -1
  152. package/dist/server/web-server/routes/catalog/helpers/create-entity-schema.d.ts +305 -256
  153. package/dist/server/web-server/routes/catalog/helpers/create-entity-update-schema.d.ts +46 -39
  154. package/dist/server/web-server/routes/catalog/helpers/upsert-pages-stats.js +1 -1
  155. package/dist/server/web-server/routes/feedback.js +1 -1
  156. package/dist/server/web-server/routes/health.js +1 -1
  157. package/dist/server/web-server/routes/index.js +1 -1
  158. package/dist/server/web-server/routes/mcp-routes/a2a.d.ts +10 -0
  159. package/dist/server/web-server/routes/mcp-routes/a2a.js +1 -0
  160. package/dist/server/web-server/routes/mcp-routes/agent-card.d.ts +4 -0
  161. package/dist/server/web-server/routes/mcp-routes/agent-card.js +1 -0
  162. package/dist/server/web-server/routes/mcp-routes/constants.d.ts +14 -0
  163. package/dist/server/web-server/routes/mcp-routes/constants.js +1 -0
  164. package/dist/server/web-server/routes/mcp-routes/mcp-routes.d.ts +1 -1
  165. package/dist/server/web-server/routes/mcp-routes/mcp-routes.js +1 -1
  166. package/dist/server/web-server/routes/mcp-routes/mcp-server-card.d.ts +4 -0
  167. package/dist/server/web-server/routes/mcp-routes/mcp-server-card.js +1 -0
  168. package/dist/server/web-server/routes/mcp-routes/types.d.ts +34 -0
  169. package/dist/server/web-server/routes/mcp-routes/types.js +0 -0
  170. package/dist/server/web-server/routes/mcp-routes/utils/build-agent-card.d.ts +10 -0
  171. package/dist/server/web-server/routes/mcp-routes/utils/build-agent-card.js +1 -0
  172. package/dist/server/web-server/routes/page-data.js +1 -1
  173. package/dist/server/web-server/routes/semantic-search.js +1 -1
  174. package/dist/server/web-server/routes/skills/build-skills-index.d.ts +4 -0
  175. package/dist/server/web-server/routes/skills/build-skills-index.js +1 -0
  176. package/dist/server/web-server/routes/skills/constants.d.ts +4 -0
  177. package/dist/server/web-server/routes/skills/constants.js +1 -0
  178. package/dist/server/web-server/routes/skills/skill-markdown.d.ts +4 -0
  179. package/dist/server/web-server/routes/skills/skill-markdown.js +1 -0
  180. package/dist/server/web-server/routes/skills/skills-index.d.ts +4 -0
  181. package/dist/server/web-server/routes/skills/skills-index.js +1 -0
  182. package/dist/server/web-server/routes/skills/skills-routes.d.ts +4 -0
  183. package/dist/server/web-server/routes/skills/skills-routes.js +1 -0
  184. package/dist/server/web-server/routes/skills/types.d.ts +12 -0
  185. package/dist/server/web-server/routes/skills/types.js +0 -0
  186. package/dist/server/web-server/utils/resolve-public-base-url.d.ts +4 -0
  187. package/dist/server/web-server/utils/resolve-public-base-url.js +1 -0
  188. package/dist/server/web-server/utils.js +1 -1
  189. package/dist/server/workers/api-routes-worker-pool.js +1 -1
  190. package/dist/server/workers/mcp-tool-worker-pool.js +1 -1
  191. package/dist/server/workers/scorecards-worker-pool.js +1 -1
  192. package/dist/server/workers/worker-pool.d.ts +1 -0
  193. package/dist/server/workers/worker-pool.js +1 -1
  194. package/package.json +10 -10
  195. package/dist/server/plugins/mcp/docs-mcp/codemode/prompts.d.ts +0 -5
  196. package/dist/server/plugins/mcp/docs-mcp/codemode/prompts.js +0 -4
  197. package/dist/server/plugins/mcp/docs-mcp/codemode/sandbox.d.ts +0 -3
  198. package/dist/server/plugins/mcp/docs-mcp/codemode/sandbox.js +0 -7
  199. package/dist/server/plugins/mcp/docs-mcp/codemode/types.d.ts +0 -9
  200. package/dist/server/plugins/mcp/docs-mcp/tools/execute.js +0 -1
  201. package/dist/server/plugins/mcp/mode.d.ts +0 -9
  202. package/dist/server/plugins/mcp/mode.js +0 -1
  203. /package/dist/server/plugins/mcp/{docs-mcp/codemode → codemode}/build-tool-type-declarations.js +0 -0
  204. /package/dist/server/plugins/mcp/{docs-mcp/codemode → codemode/capabilities}/types.js +0 -0
  205. /package/dist/server/plugins/mcp/{docs-mcp → codemode}/tools/execute.d.ts +0 -0
@@ -1 +1 @@
1
- import b from"@markdoc/markdoc";import{getPathnameForLocale as A}from"@redocly/theme/core/utils";import{DEFAULT_LOCALE_PLACEHOLDER as g}from"../constants/common.js";import{DEFAULT_TITLE as O}from"./constants/common.js";import{GATED_MARKDOC_TAGS as D}from"./constants/entitlements.js";import{MARKDOC_PARTIALS_DATA_KEY as m,MARKDOC_PARTIALS_DEPS_KEY as T}from"./constants/common.js";import{isObject as M}from"../utils/guards/is-object.js";import{mapObject as L}from"../utils/object/map-object.js";import{getValueDeep as y}from"../utils/object/get-value-deep.js";import{removeTrailingSlash as k}from"../utils/url/remove-trailing-slash.js";import{normalizeRouteSlug as u}from"../utils/path/normalize-route-slug.js";import{isLocalLink as R}from"../utils/path/is-local-link.js";import{reporter as S}from"./tools/notifiers/reporter.js";import{logger as h}from"./tools/notifiers/logger.js";import{sha1 as H}from"./utils/crypto/sha1.js";import{envConfig as _,setEnv as G}from"./config/env-config.js";import{KvService as B}from"./persistence/kv/services/kv-service.js";import{writeSharedData as F}from"./utils/index.js";import{renderComponents as I}from"./ssr/render.js";import{readStaticData as N,writeStaticData as q}from"./utils/static-data.js";import{parseAndResolveMarkdoc as V}from"./plugins/markdown/compiler.js";import{getMarkdocOptions as j}from"./plugins/markdown/markdoc/markdoc-options.js";import{EntitlementsProvider as w}from"./entitlements/entitlements-provider.js";import{isL10nPath as U}from"./fs/utils/is-l10n-path.js";import{resolveGlobMapValue as K}from"./utils/globs.js";import{replaceEnvVariablesDeep as J}from"./utils/envs/replace-env-variables-deep.js";import{findRedirect as x}from"./utils/redirects/find-redirect.js";import{followRedirectChain as W}from"./utils/redirects/follow-redirect-chain.js";import{addWildcardRedirectToTree as $}from"./utils/redirects/add-wildcard-redirect-to-tree.js";import{telemetryTraceStep as z}from"../cli/telemetry/helpers/trace-step.js";const v={routesBySlug:"map",apiRoutes:"object",middleware:"object",routesByFsPath:"map",routesSharedData:"map",globalData:"object",config:"object",ssr:"object",searchFacets:"map",routesPartials:"map",mcpToolHandlers:"map"},E="PLAN_GATES",Y=["OAUTH_CLIENT_ID","OAUTH_CLIENT_SECRET","ORGANIZATION_SLUG","ORGANIZATION_ID","ORG_ID"],Oe="userDefinedApiFunctions";class P{routesBySlug=new Map;replacedEnvVars={};unsetEnvVars=new Set;lifecycleContext;newRoutes=[];#t={};routesByFsPath=new Map;apiRoutes=[];middleware=[];routesSharedData=new Map;sharedDataDeps=new Map;sharedDataMarkdocComponents=new Map;routesDynamicComponents=new Map;routesPartials=new Map;ssr={preBodyTags:[],postBodyTags:[],headTags:[]};searchFacets=new Map;searchEngine;templates=new Map;browserPlugins=new Set;apiRoutesRequestHandlers=new Map;mcpToolHandlers=new Map;serverPropsGetters=new Map;pagePropsGetters=new Map;listeners=new Map;globalData={};#o=void 0;config={configFilePath:"",redirects:{},wildcardRedirectsTree:{},access:{rbac:{},requiresLogin:!1},directoryPermissions:{},devLogin:!1,ssoDirect:{}};#i;serverMode;serverOutDir;outdir;buildRevision=0;hasSitemap=!1;compilationErrors=[];#n;userCodeReady;#s=Promise.resolve();#c;#l=Promise.resolve();#d;#u=Promise.resolve();#h;#e=!1;#r=0;#f=0;#a=new Map;constructor({outdir:e,contentDir:s,serverMode:t=!1,serverOutDir:a}){this.#i=s,this.outdir=e,this.serverMode=t,this.serverOutDir=a,this.userCodeReady=new Promise(r=>{this.#n=r})}on(e,s){const t=this.listeners.get(e);t?t.add(s):this.listeners.set(e,new Set([s]))}queueEvent=(e,s,...t)=>{this.#a.set(e+String(s),[e,s,...t])};runListeners=(e,s,...t)=>{for(const a of this.listeners.get(e)||new Set)s?a(s,...t):a(...t)};startPluginsRun(){this.clear(),this.#s=new Promise(e=>{this.#c=e})}waitForPluginsLifecycle(){return Promise.all([this.#s,this.#l,this.#u])}waitForPluginsRun(){return this.#s}finishPluginsRun(){this.#c?.();for(const e of this.#a.values())this.runListeners(...e);this.#a.clear()}startEsbuildRun(){this.#l=new Promise(e=>{this.#d=e})}finishEsbuildRun(){this.#d?.()}markRequestHandlersEntryOutdated(){this.#r++,!this.#e&&(this.#e=!0,this.#u=new Promise(e=>{this.#h=e}))}noteRequestHandlersEntryBuildStart(){this.#f=this.#r}markRequestHandlersEntryUpdated(){this.#e&&(this.#r>this.#f||(this.#e=!1,this.#h?.()))}get contentDir(){if(this.serverMode)throw new Error("contentDir should not be used in server mode");return this.#i}markUserCodeReady(){this.#n?.(!0)}async reloadMarkdocOptions(){await z("build.reload_markdoc_options",async()=>{const e=w.instance(),s=await j(this.serverOutDir),t=Object.fromEntries(Object.entries(s.tags).filter(([a])=>D[a]!=null?e.canAccessFeature(D[a]):!0));this.#o={...s,tags:t}})}get markdocOptions(){return{...this.#o,partials:this.getGlobalConfig(m),themeConfig:this.config.markdown}}setGlobalData=e=>{const s=this.globalData,t={...this.globalData,...e};this.globalData=t,JSON.stringify(t)!==JSON.stringify(s)&&this.queueEvent("global-data-updated",void 0,t)};getGlobalData=()=>this.globalData;getKv=async()=>B.getInstance({baseDbDir:this.serverOutDir});parseMarkdoc=async({input:e,context:s,deps:t,resource:a})=>{const{data:{info:r,ast:o},compoundHash:l}=await V(e,this.markdocOptions,{actions:this,context:s},a);for(const i of r.sharedDataDeps||[]){for(const n of t?.routeSlugs||[])this.addRouteSharedData(n,i,i);for(const n of t?.sharedDataIds||[]){const c=this.sharedDataDeps.get(n)||new Set;c.add(i),this.sharedDataDeps.set(n,c)}}for(const i of r.dynamicMarkdocComponents||[]){for(const n of t?.routeSlugs||[]){const c=this.routesDynamicComponents.get(n)||new Set;c.add(i),this.routesDynamicComponents.set(n,c)}for(const n of t?.sharedDataIds||[]){const c=this.sharedDataMarkdocComponents.get(n)||new Set;c.add(i),this.sharedDataMarkdocComponents.set(n,c)}}if(t?.routeSlugs&&r.partials?.length)for(const i of t.routeSlugs){const n=this.routesPartials.get(i)||[];for(const c of r.partials)n.includes(c)||n.push(c);this.routesPartials.set(i,n)}return{info:r,ast:o,compoundHash:l}};async loadOpenApiDefinitions(e){return(await e.cache.load(".","load-oas-docs")).data}async loadAsyncApiDefinitions(e){return(await e.cache.load(".","asyncapi-docs")).data}async loadGraphqlDefinitions(e){return(await e.cache.load(".","load-graphql-docs")).data}setSearchEngine(e){this.searchEngine=e}setSearchFacets=e=>{this.searchFacets=e};setGlobalConfig=e=>{const s=Object.keys(e);for(const o of s)for(const l in this.replacedEnvVars)if(l===o||l.startsWith(`${o}:`)){const i=l.split(":"),{error:n,value:c}=y(e,i);(n||c!==this.replacedEnvVars[l].replaced)&&delete this.replacedEnvVars[l]}const{resolvedObj:t,unsetEnvVars:a,replacedValues:r}=J(e);for(const o of a)this.unsetEnvVars.add(o);Object.assign(this.replacedEnvVars,r),Object.assign(this.config,t)};getConfig=()=>this.config;getGlobalConfig=e=>this.config[e];getSearchFacets=()=>this.searchFacets;addRedirect=(e,s,t={})=>{if(!w.instance().canAccessFeature("redirects")&&e!=="/")return;this.config.redirects||(this.config.redirects={});const o=u(e).toLowerCase();this.config.redirects[o]=s;const{trackOriginalSource:l=!0}=t,i=this.getGlobalConfig("originalRedirectSources");l&&Array.isArray(i)&&!i.includes(o)&&i.push(o),o.endsWith("*")&&$(this.config.wildcardRedirectsTree,o)};getRedirect=e=>{const s=u(e).toLowerCase(),t=x(s,this.config.redirects,this.config.wildcardRedirectsTree);if(!t)return null;if(R(t.to)){const a=u(t.to).toLowerCase();if(!a.endsWith("*")&&W(a,[s],this.config.redirects,this.config.wildcardRedirectsTree).type==="cycle")return null}return{to:t.to,type:t.type}};createSharedData=async(e,s,t)=>{if(t&&this.#t[e]===t)return e;const a=JSON.stringify(s),r=t??H(a);return this.#t[e]===r||(this.#t[e]=r,await F(e,a,this.outdir),this.queueEvent("shared-data-updated",e)),e};addRouteSharedData=(e,s,t)=>{const a=k(e),r=this.routesSharedData.get(a)||{};r[s]=t,this.routesSharedData.set(a,r),h.verbose(`Adding shared data to ${e}, ${s}, ${t}`)};getRouteSharedDataByFsPath=e=>{const s=this.routesByFsPath.get(e);return s?this.routesSharedData.get(s)||{}:{}};getPartialsForRoute=e=>{const s=this.getGlobalConfig(m)||{},t=this.routesPartials.get(e);if(!t||t.length===0)return{};const a=this.getGlobalConfig(T)||{},r=new Set(t),o=Array.from(t);for(let i=0;i<o.length;i++){const n=o[i],c=a[n]?.partials??[];for(const d of c)r.has(d)||(r.add(d),o.push(d))}const l={};for(const i of r)s[i]&&(l[i]=s[i]);return l};addRoute=e=>{const t={...K(e.fsPath,this.config.metadataGlobs),...e.metadata||{}};this.newRoutes.push({...e,metadata:t}),h.verbose("Created route %s",e.slug)};addRouteSharedDataToAllLocales=(e,s,t)=>{const a=[g,...this.lifecycleContext?.fs.localeFolders||[]].map(r=>({code:r,name:r}));for(const r of a){const o=A(e,g,r.code,a);this.addRouteSharedData(o,s,t)}};addApiRoute=e=>{this.apiRoutes.push(e),h.verbose("Created API route %s",e.slug)};addMcpTools=(e,s)=>{for(const t of s)this.mcpToolHandlers.set(t.name,{...t,importPath:e}),h.verbose("Created MCP tool %s",t.name)};getMcpTools=()=>Array.from(this.mcpToolHandlers.values());addMiddleware=e=>{this.middleware.push(e),h.verbose("Created middleware %s",e.id)};setResourceResponseHeaders=(e,s)=>{this.config.responseHeaders||(this.config.responseHeaders={});const t=new Set(s.map(o=>o.name.toLowerCase())),r=[...(this.config.responseHeaders[e]??[]).filter(o=>!t.has(o.name.toLowerCase())),...s];this.config.responseHeaders[e]=r};getRouteByFsPath=e=>{const s=this.routesByFsPath.get(e);return s?this.getRouteBySlug(s):void 0};getRouteBySlug=(e,s={})=>{const{followRedirect:t=!0}=s,a=this.getRedirect(e);return t&&a?this.routesBySlug.get(u(a.to)):this.routesBySlug.get(e)};hasRouteOrRedirectBySlug=e=>{if(this.routesBySlug.has(e))return!0;const s=this.getRedirect(e);if(!s)return!1;if(!R(s.to))return!0;const t=u(s.to);return this.routesBySlug.has(t)};getRoutesByTemplateId=e=>this.newRoutes.filter(s=>s.templateId===e);getAllRoutesForLocale=(e=g)=>{const s=Array.from(this.routesBySlug.values()),t=e.toLowerCase();return s.filter(a=>e===g?!U(a.fsPath):a.slug.startsWith(`/${t}`))};getAllRoutes=()=>Array.from(this.routesBySlug.values());getAllApiRoutes=()=>this.apiRoutes;getAllMiddleware=()=>this.middleware;getTemplate=e=>this.templates.get(e);getRequestHandler=e=>this.apiRoutesRequestHandlers.get(e);createTemplate=(e,s)=>(this.templates.set(e,s),e);addBrowserPlugin=e=>{this.browserPlugins.add(e)};createRequestHandler=(e,s)=>(this.apiRoutesRequestHandlers.set(e,s),e);clearRequestHandlersByPrefix=e=>{for(const s of this.apiRoutesRequestHandlers.keys())s.startsWith(e)&&this.apiRoutesRequestHandlers.delete(s)};registerServerPropsGetter=(e,s)=>(this.serverPropsGetters.set(e,s),e);registerPagePropsGetter=(e,s)=>{this.pagePropsGetters.set(e,s)};async writeRouteStaticData(e,s){const t=await this.resolveRouteStaticData(e,s,!1);t&&q(e.slug,t,this.outdir)}async resolveRouteStaticData(e,s,t){if(this.serverMode)return N(e.slug,this.outdir);const a={...this,contentDir:this.contentDir,parseMarkdoc:({input:c,context:d,resource:f})=>this.parseMarkdoc({input:c,context:d,deps:{routeSlugs:[e.slug]},resource:f})},r=await e.getStaticData?.(e,a)||{},o=new Set(this.routesDynamicComponents.get(e.slug)),l=this.routesSharedData.get(e.slug)||{};for(const c of Object.values(l)){const d=this.sharedDataMarkdocComponents.get(c);d&&d.forEach(p=>o.add(p));const f=this.sharedDataDeps.get(c);f&&f.forEach(p=>this.addRouteSharedData(e.slug,p,p))}const i=this.getGlobalConfig("seo"),n=r?.frontmatter||{};return{...r,frontmatter:{...n,seo:{...n?.seo,title:n?.seo?.title||await e.getNavText?.()}},props:{...r.props,dynamicMarkdocComponents:Array.from(o),metadata:{...r?.props?.metadata,...e.metadata},seo:{title:O,...i,...r.props?.seo},compilationErrors:this.compilationErrors},lastModified:t||!e.fsPath?null:await this.lifecycleContext?.fs.getLastModified(e.fsPath)}}addSsrComponents(e,s){if(!e?.length)return;const t=typeof e[0]=="string"?e.join(""):I(e);t&&(s==="head"?this.ssr.headTags.push(t):s==="preBody"?this.ssr.preBodyTags.push(t):this.ssr.postBodyTags.push(t))}clear=()=>{this.routesByFsPath.clear(),this.templates.clear(),this.newRoutes=[],this.routesBySlug.clear(),this.apiRoutes=[],this.middleware=[],this.routesSharedData.clear(),this.sharedDataDeps.clear(),this.sharedDataMarkdocComponents.clear(),this.routesDynamicComponents.clear(),this.routesPartials.clear(),this.config.redirects={},this.config.wildcardRedirectsTree={},this.config.directoryPermissions={},this.ssr={preBodyTags:[],postBodyTags:[],headTags:[]}};async toJson(){const e=[];for(const[t,a]of Object.entries(v))switch(a){case"map":const r=Array.from(this[t].entries());e.push([t,r]);break;case"object":t==="config"&&e.push([t,await this.getConfigWithEnvPlaceholders()]),e.push([t,this[t]]);break;default:throw new Error("Invalid format")}const s=Object.fromEntries(e);return s[E]=_.PLAN_GATES,s}static fromJson(e,s){const t=new P(s);for(const[r,o]of Object.entries(v))switch(o){case"map":t[r]=new Map(e[r]);break;case"object":if(r==="config"){t.setGlobalConfig(e[r]);break}t[r]=e[r];break;default:throw new Error("Invalid format")}t.config[m]=Z(t.config[m]||{});const a=e[E];return a&&G("PLAN_GATES",a),t}async getConfigWithEnvPlaceholders(){const e=JSON.parse(JSON.stringify(this.config));for(const s in this.replacedEnvVars){const{original:t}=this.replacedEnvVars[s],a=s.split(":"),r=a.pop(),{error:o,value:l}=y(e,a);if(o||!M(l)&&!Array.isArray(l)){await S.panicOnBuild(`Failed to replace env var with env name for ${s}`);continue}l[r]=t}return e}async reportUnsetEnvVars(){if(this.unsetEnvVars.size===0)return;const e=Array.from(this.unsetEnvVars).filter(t=>!Y.includes(t));if(e.length===0)return;const s=`Failed to resolve config. The following environment variables are not set: ${e.join(", ")}`;await S.panicOnBuildContentError(s)}}function Z(C){return L(C,e=>b.Ast.fromJSON(JSON.stringify(e)))}export{P as Store,Oe as USER_DEFINED_API_FUNCTIONS_COUNTER_KEY};
1
+ import C from"@markdoc/markdoc";import{getPathnameForLocale as A}from"@redocly/theme/core/utils";import{DEFAULT_LOCALE_PLACEHOLDER as g}from"../constants/common.js";import{DEFAULT_TITLE as O}from"./constants/common.js";import{GATED_MARKDOC_TAGS as D}from"./constants/entitlements.js";import{MARKDOC_PARTIALS_DATA_KEY as m,MARKDOC_PARTIALS_DEPS_KEY as T}from"./constants/common.js";import{isObject as M}from"../utils/guards/is-object.js";import{mapObject as k}from"../utils/object/map-object.js";import{getValueDeep as y}from"../utils/object/get-value-deep.js";import{removeTrailingSlash as L}from"../utils/url/remove-trailing-slash.js";import{normalizeRouteSlug as h}from"../utils/path/normalize-route-slug.js";import{isLocalLink as R}from"../utils/path/is-local-link.js";import{reporter as S}from"./tools/notifiers/reporter.js";import{logger as u}from"./tools/notifiers/logger.js";import{sha1 as H}from"./utils/crypto/sha1.js";import{envConfig as _,setEnv as G}from"./config/env-config.js";import{KvService as B}from"./persistence/kv/services/kv-service.js";import{writeSharedData as F}from"./utils/index.js";import{renderComponents as I}from"./ssr/render.js";import{readStaticData as N,writeStaticData as q}from"./utils/static-data.js";import{parseAndResolveMarkdoc as V}from"./plugins/markdown/compiler.js";import{getMarkdocOptions as j}from"./plugins/markdown/markdoc/markdoc-options.js";import{EntitlementsProvider as w}from"./entitlements/entitlements-provider.js";import{isL10nPath as U}from"./fs/utils/is-l10n-path.js";import{resolveGlobMapValue as K}from"./utils/globs.js";import{replaceEnvVariablesDeep as J}from"./utils/envs/replace-env-variables-deep.js";import{findRedirect as x}from"./utils/redirects/find-redirect.js";import{followRedirectChain as W}from"./utils/redirects/follow-redirect-chain.js";import{addWildcardRedirectToTree as $}from"./utils/redirects/add-wildcard-redirect-to-tree.js";import{telemetryTraceStep as z}from"../cli/telemetry/helpers/trace-step.js";const v={routesBySlug:"map",apiRoutes:"object",middleware:"object",routesByFsPath:"map",routesSharedData:"map",globalData:"object",config:"object",ssr:"object",searchFacets:"map",routesPartials:"map",mcpToolHandlers:"map",skills:"map"},E="PLAN_GATES",Y=["OAUTH_CLIENT_ID","OAUTH_CLIENT_SECRET","ORGANIZATION_SLUG","ORGANIZATION_ID","ORG_ID"],Oe="userDefinedApiFunctions";class P{routesBySlug=new Map;replacedEnvVars={};unsetEnvVars=new Set;lifecycleContext;newRoutes=[];#t={};routesByFsPath=new Map;apiRoutes=[];middleware=[];routesSharedData=new Map;sharedDataDeps=new Map;sharedDataMarkdocComponents=new Map;routesDynamicComponents=new Map;routesPartials=new Map;ssr={preBodyTags:[],postBodyTags:[],headTags:[]};searchFacets=new Map;searchEngine;templates=new Map;browserPlugins=new Set;apiRoutesRequestHandlers=new Map;mcpToolHandlers=new Map;skills=new Map;serverPropsGetters=new Map;pagePropsGetters=new Map;listeners=new Map;globalData={};#o=void 0;config={configFilePath:"",redirects:{},wildcardRedirectsTree:{},access:{rbac:{},requiresLogin:!1},directoryPermissions:{},devLogin:!1,ssoDirect:{}};#i;serverMode;serverOutDir;outdir;buildRevision=0;hasSitemap=!1;compilationErrors=[];#n;userCodeReady;#s=Promise.resolve();#c;#l=Promise.resolve();#d;#u=Promise.resolve();#h;#e=!1;#r=0;#f=0;#a=new Map;constructor({outdir:e,contentDir:t,serverMode:s=!1,serverOutDir:a}){this.#i=t,this.outdir=e,this.serverMode=s,this.serverOutDir=a,this.userCodeReady=new Promise(r=>{this.#n=r})}on(e,t){const s=this.listeners.get(e);s?s.add(t):this.listeners.set(e,new Set([t]))}queueEvent=(e,t,...s)=>{this.#a.set(e+String(t),[e,t,...s])};runListeners=(e,t,...s)=>{for(const a of this.listeners.get(e)||new Set)t?a(t,...s):a(...s)};startPluginsRun(){this.clear(),this.#s=new Promise(e=>{this.#c=e})}waitForPluginsLifecycle(){return Promise.all([this.#s,this.#l,this.#u])}waitForPluginsRun(){return this.#s}finishPluginsRun(){this.#c?.();for(const e of this.#a.values())this.runListeners(...e);this.#a.clear()}startEsbuildRun(){this.#l=new Promise(e=>{this.#d=e})}finishEsbuildRun(){this.#d?.()}markRequestHandlersEntryOutdated(){this.#r++,!this.#e&&(this.#e=!0,this.#u=new Promise(e=>{this.#h=e}))}noteRequestHandlersEntryBuildStart(){this.#f=this.#r}markRequestHandlersEntryUpdated(){this.#e&&(this.#r>this.#f||(this.#e=!1,this.#h?.()))}get contentDir(){if(this.serverMode)throw new Error("contentDir should not be used in server mode");return this.#i}markUserCodeReady(){this.#n?.(!0)}async reloadMarkdocOptions(){await z("build.reload_markdoc_options",async()=>{const e=w.instance(),t=await j(this.serverOutDir),s=Object.fromEntries(Object.entries(t.tags).filter(([a])=>D[a]!=null?e.canAccessFeature(D[a]):!0));this.#o={...t,tags:s}})}get markdocOptions(){return{...this.#o,partials:this.getGlobalConfig(m),themeConfig:this.config.markdown}}setGlobalData=e=>{const t=this.globalData,s={...this.globalData,...e};this.globalData=s,JSON.stringify(s)!==JSON.stringify(t)&&this.queueEvent("global-data-updated",void 0,s)};getGlobalData=()=>this.globalData;getKv=async()=>B.getInstance({baseDbDir:this.serverOutDir});parseMarkdoc=async({input:e,context:t,deps:s,resource:a})=>{const{data:{info:r,ast:o},compoundHash:l}=await V(e,this.markdocOptions,{actions:this,context:t},a);for(const i of r.sharedDataDeps||[]){for(const n of s?.routeSlugs||[])this.addRouteSharedData(n,i,i);for(const n of s?.sharedDataIds||[]){const c=this.sharedDataDeps.get(n)||new Set;c.add(i),this.sharedDataDeps.set(n,c)}}for(const i of r.dynamicMarkdocComponents||[]){for(const n of s?.routeSlugs||[]){const c=this.routesDynamicComponents.get(n)||new Set;c.add(i),this.routesDynamicComponents.set(n,c)}for(const n of s?.sharedDataIds||[]){const c=this.sharedDataMarkdocComponents.get(n)||new Set;c.add(i),this.sharedDataMarkdocComponents.set(n,c)}}if(s?.routeSlugs&&r.partials?.length)for(const i of s.routeSlugs){const n=this.routesPartials.get(i)||[];for(const c of r.partials)n.includes(c)||n.push(c);this.routesPartials.set(i,n)}return{info:r,ast:o,compoundHash:l}};async loadOpenApiDefinitions(e){return(await e.cache.load(".","load-oas-docs")).data}async loadAsyncApiDefinitions(e){return(await e.cache.load(".","asyncapi-docs")).data}async loadGraphqlDefinitions(e){return(await e.cache.load(".","load-graphql-docs")).data}setSearchEngine(e){this.searchEngine=e}setSearchFacets=e=>{this.searchFacets=e};setGlobalConfig=e=>{const t=Object.keys(e);for(const o of t)for(const l in this.replacedEnvVars)if(l===o||l.startsWith(`${o}:`)){const i=l.split(":"),{error:n,value:c}=y(e,i);(n||c!==this.replacedEnvVars[l].replaced)&&delete this.replacedEnvVars[l]}const{resolvedObj:s,unsetEnvVars:a,replacedValues:r}=J(e);for(const o of a)this.unsetEnvVars.add(o);Object.assign(this.replacedEnvVars,r),Object.assign(this.config,s)};getConfig=()=>this.config;getGlobalConfig=e=>this.config[e];getSearchFacets=()=>this.searchFacets;addRedirect=(e,t,s={})=>{if(!w.instance().canAccessFeature("redirects")&&e!=="/")return;this.config.redirects||(this.config.redirects={});const o=h(e).toLowerCase();this.config.redirects[o]=t;const{trackOriginalSource:l=!0}=s,i=this.getGlobalConfig("originalRedirectSources");l&&Array.isArray(i)&&!i.includes(o)&&i.push(o),o.endsWith("*")&&$(this.config.wildcardRedirectsTree,o)};getRedirect=e=>{const t=h(e).toLowerCase(),s=x(t,this.config.redirects,this.config.wildcardRedirectsTree);if(!s)return null;if(R(s.to)){const a=h(s.to).toLowerCase();if(!a.endsWith("*")&&W(a,[t],this.config.redirects,this.config.wildcardRedirectsTree).type==="cycle")return null}return{to:s.to,type:s.type}};createSharedData=async(e,t,s)=>{if(s&&this.#t[e]===s)return e;const a=JSON.stringify(t),r=s??H(a);return this.#t[e]===r||(this.#t[e]=r,await F(e,a,this.outdir),this.queueEvent("shared-data-updated",e)),e};addRouteSharedData=(e,t,s)=>{const a=L(e),r=this.routesSharedData.get(a)||{};r[t]=s,this.routesSharedData.set(a,r),u.verbose(`Adding shared data to ${e}, ${t}, ${s}`)};getRouteSharedDataByFsPath=e=>{const t=this.routesByFsPath.get(e);return t?this.routesSharedData.get(t)||{}:{}};getPartialsForRoute=e=>{const t=this.getGlobalConfig(m)||{},s=this.routesPartials.get(e);if(!s||s.length===0)return{};const a=this.getGlobalConfig(T)||{},r=new Set(s),o=Array.from(s);for(let i=0;i<o.length;i++){const n=o[i],c=a[n]?.partials??[];for(const d of c)r.has(d)||(r.add(d),o.push(d))}const l={};for(const i of r)t[i]&&(l[i]=t[i]);return l};addRoute=e=>{const s={...K(e.fsPath,this.config.metadataGlobs),...e.metadata||{}};this.newRoutes.push({...e,metadata:s}),u.verbose("Created route %s",e.slug)};addRouteSharedDataToAllLocales=(e,t,s)=>{const a=[g,...this.lifecycleContext?.fs.localeFolders||[]].map(r=>({code:r,name:r}));for(const r of a){const o=A(e,g,r.code,a);this.addRouteSharedData(o,t,s)}};addApiRoute=e=>{this.apiRoutes.push(e),u.verbose("Created API route %s",e.slug)};addMcpTools=(e,t)=>{for(const s of t)this.mcpToolHandlers.set(s.name,{...s,importPath:e}),u.verbose("Created MCP tool %s",s.name)};getMcpTools=()=>Array.from(this.mcpToolHandlers.values());addSkills=e=>{for(const t of e)this.skills.set(t.slug,t),u.verbose("Discovered skill %s",t.slug)};getSkills=()=>Array.from(this.skills.values());addMiddleware=e=>{this.middleware.push(e),u.verbose("Created middleware %s",e.id)};setResourceResponseHeaders=(e,t)=>{this.config.responseHeaders||(this.config.responseHeaders={});const s=new Set(t.map(o=>o.name.toLowerCase())),r=[...(this.config.responseHeaders[e]??[]).filter(o=>!s.has(o.name.toLowerCase())),...t];this.config.responseHeaders[e]=r};getRouteByFsPath=e=>{const t=this.routesByFsPath.get(e);return t?this.getRouteBySlug(t):void 0};getRouteBySlug=(e,t={})=>{const{followRedirect:s=!0}=t,a=this.getRedirect(e);return s&&a?this.routesBySlug.get(h(a.to)):this.routesBySlug.get(e)};hasRouteOrRedirectBySlug=e=>{if(this.routesBySlug.has(e))return!0;const t=this.getRedirect(e);if(!t)return!1;if(!R(t.to))return!0;const s=h(t.to);return this.routesBySlug.has(s)};getRoutesByTemplateId=e=>this.newRoutes.filter(t=>t.templateId===e);getAllRoutesForLocale=(e=g)=>{const t=Array.from(this.routesBySlug.values()),s=e.toLowerCase();return t.filter(a=>e===g?!U(a.fsPath):a.slug.startsWith(`/${s}`))};getAllRoutes=()=>Array.from(this.routesBySlug.values());getAllApiRoutes=()=>this.apiRoutes;getAllMiddleware=()=>this.middleware;getTemplate=e=>this.templates.get(e);getRequestHandler=e=>this.apiRoutesRequestHandlers.get(e);createTemplate=(e,t)=>(this.templates.set(e,t),e);addBrowserPlugin=e=>{this.browserPlugins.add(e)};createRequestHandler=(e,t)=>(this.apiRoutesRequestHandlers.set(e,t),e);clearRequestHandlersByPrefix=e=>{for(const t of this.apiRoutesRequestHandlers.keys())t.startsWith(e)&&this.apiRoutesRequestHandlers.delete(t)};registerServerPropsGetter=(e,t)=>(this.serverPropsGetters.set(e,t),e);registerPagePropsGetter=(e,t)=>{this.pagePropsGetters.set(e,t)};async writeRouteStaticData(e,t){const s=await this.resolveRouteStaticData(e,t,!1);s&&q(e.slug,s,this.outdir)}async resolveRouteStaticData(e,t,s){if(this.serverMode)return N(e.slug,this.outdir);const a={...this,contentDir:this.contentDir,parseMarkdoc:({input:c,context:d,resource:f})=>this.parseMarkdoc({input:c,context:d,deps:{routeSlugs:[e.slug]},resource:f})},r=await e.getStaticData?.(e,a)||{},o=new Set(this.routesDynamicComponents.get(e.slug)),l=this.routesSharedData.get(e.slug)||{};for(const c of Object.values(l)){const d=this.sharedDataMarkdocComponents.get(c);d&&d.forEach(p=>o.add(p));const f=this.sharedDataDeps.get(c);f&&f.forEach(p=>this.addRouteSharedData(e.slug,p,p))}const i=this.getGlobalConfig("seo"),n=r?.frontmatter||{};return{...r,frontmatter:{...n,seo:{...n?.seo,title:n?.seo?.title||await e.getNavText?.()}},props:{...r.props,dynamicMarkdocComponents:Array.from(o),metadata:{...r?.props?.metadata,...e.metadata},seo:{title:O,...i,...r.props?.seo},compilationErrors:this.compilationErrors},lastModified:s||!e.fsPath?null:await this.lifecycleContext?.fs.getLastModified(e.fsPath)}}addSsrComponents(e,t){if(!e?.length)return;const s=typeof e[0]=="string"?e.join(""):I(e);s&&(t==="head"?this.ssr.headTags.push(s):t==="preBody"?this.ssr.preBodyTags.push(s):this.ssr.postBodyTags.push(s))}clear=()=>{this.routesByFsPath.clear(),this.templates.clear(),this.newRoutes=[],this.routesBySlug.clear(),this.apiRoutes=[],this.middleware=[],this.routesSharedData.clear(),this.sharedDataDeps.clear(),this.sharedDataMarkdocComponents.clear(),this.routesDynamicComponents.clear(),this.routesPartials.clear(),this.skills.clear(),this.config.redirects={},this.config.wildcardRedirectsTree={},this.config.directoryPermissions={},this.ssr={preBodyTags:[],postBodyTags:[],headTags:[]}};async toJson(){const e=[];for(const[s,a]of Object.entries(v))switch(a){case"map":const r=Array.from(this[s].entries());e.push([s,r]);break;case"object":s==="config"&&e.push([s,await this.getConfigWithEnvPlaceholders()]),e.push([s,this[s]]);break;default:throw new Error("Invalid format")}const t=Object.fromEntries(e);return t[E]=_.PLAN_GATES,t}static fromJson(e,t){const s=new P(t);for(const[r,o]of Object.entries(v))switch(o){case"map":s[r]=new Map(e[r]);break;case"object":if(r==="config"){s.setGlobalConfig(e[r]);break}s[r]=e[r];break;default:throw new Error("Invalid format")}s.config[m]=Z(s.config[m]||{});const a=e[E];return a&&G("PLAN_GATES",a),s}async getConfigWithEnvPlaceholders(){const e=JSON.parse(JSON.stringify(this.config));for(const t in this.replacedEnvVars){const{original:s}=this.replacedEnvVars[t],a=t.split(":"),r=a.pop(),{error:o,value:l}=y(e,a);if(o||!M(l)&&!Array.isArray(l)){await S.panicOnBuild(`Failed to replace env var with env name for ${t}`);continue}l[r]=s}return e}async reportUnsetEnvVars(){if(this.unsetEnvVars.size===0)return;const e=Array.from(this.unsetEnvVars).filter(s=>!Y.includes(s));if(e.length===0)return;const t=`Failed to resolve config. The following environment variables are not set: ${e.join(", ")}`;await S.panicOnBuildContentError(t)}}function Z(b){return k(b,e=>C.Ast.fromJSON(JSON.stringify(e)))}export{P as Store,Oe as USER_DEFINED_API_FUNCTIONS_COUNTER_KEY};
@@ -18,6 +18,7 @@ import type { AiDocumentsStore } from '../../plugins/search/types';
18
18
  import type { ParseMarkdocOpts } from '../../types/plugins/markdown';
19
19
  import type { MarkdocConfigProps } from '../../plugins/markdown/compiler';
20
20
  import type { ToolAnnotations } from '@redocly/mcp-typescript-sdk/types.js';
21
+ import type { Skill } from '../../types/plugins/skills';
21
22
  export type ResolveItemsOptions = {
22
23
  groupCustomSidebars?: boolean;
23
24
  locale?: string;
@@ -207,6 +208,8 @@ export type AfterRoutesCreatedActions = {
207
208
  addBrowserPlugin: (importPath: string) => void;
208
209
  addSsrComponents: (components: JSX.Element[] | string[], position: 'head' | 'preBody' | 'postBody') => void;
209
210
  addApiRoute: (route: ApiRoute) => void;
211
+ addSkills: (skills: Skill[]) => void;
212
+ getSkills: () => Skill[];
210
213
  loadOpenApiDefinitions(context: LifecycleContext): Promise<BundledDefinition[]>;
211
214
  getRouteSharedDataByFsPath: (routeFsPath: string) => Record<string, string> | undefined;
212
215
  getKv: () => Promise<KvService>;
@@ -6,7 +6,6 @@ import type { SearchFacet, SearchFacetCount, OperationParameter } from '@redocly
6
6
  import type { ExportHandler } from 'flexsearch';
7
7
  import type { AuthDetails } from '../../types';
8
8
  import type { SEARCH_DOCUMENT_METADATA_KEY } from '../../constants/plugins/search';
9
- export type SearchEngineType = 'flexsearch' | 'typesense';
10
9
  export type SearchEngine = {
11
10
  addDocuments(documents: SearchDocument[], params: AddDocumentsParams): Promise<void>;
12
11
  search(params: SearchRequestParams, auth: AuthDetails): Promise<SearchResponse>;
@@ -0,0 +1,16 @@
1
+ import type { RbacScopeItems } from '@redocly/config';
2
+ export type Skill = {
3
+ /** URL-safe slug: the @skills subfolder name, or the project-default name for a root SKILL.md. */
4
+ slug: string;
5
+ /** Display name (frontmatter `name`) */
6
+ name: string;
7
+ description: string;
8
+ /** Raw SKILL.md content, served verbatim as text/markdown. */
9
+ content: string;
10
+ /** `sha256:<hex>` over the raw content. */
11
+ digest: string;
12
+ fsPath: string;
13
+ rbac?: RbacScopeItems;
14
+ tags: string[];
15
+ };
16
+ //# sourceMappingURL=skills.d.ts.map
File without changes
@@ -1,5 +1,8 @@
1
1
  import type { Context } from 'hono';
2
2
  export declare function clearAuthCookies(ctx: Context): void;
3
+ export declare function setPostLogoutCookie(ctx: Context): void;
4
+ export declare function clearPostLogoutCookie(ctx: Context): void;
5
+ export declare function hasPostLogoutCookie(ctx: Context): boolean;
3
6
  export declare function safeDecodeURIComponent(value: string): string;
4
7
  /**
5
8
  * Parses cookie header string according to RFC 6265
@@ -1 +1 @@
1
- import{deleteCookie as m,getCookie as u}from"hono/cookie";import{getPathPrefix as p}from"@redocly/theme/core/utils";import{AuthCookieNames as k}from"../../constants/common.js";function C(e){const o=p()||"/";for(const t of Object.values(k))m(e,t,{path:o})}function n(e){try{return decodeURIComponent(e)}catch{return e}}function x(e){const o=new Map,t=e.req.header("cookie")||"";return t&&t.split(";").forEach(c=>{const[a,...s]=c.split("="),r=a?.trim();if(!r)return;const f=s.join("=").trim();try{const i=u(e,r);if(!i)return;o.set(n(r),i)}catch{o.set(n(r),n(f))}}),o}export{C as clearAuthCookies,x as parseCookieHeader,n as safeDecodeURIComponent};
1
+ import{deleteCookie as a,getCookie as m,setCookie as C}from"hono/cookie";import{getPathPrefix as n}from"@redocly/theme/core/utils";import{AuthCookieNames as O,POST_LOGOUT_COOKIE_EXPIRATION as h,POST_LOGOUT_COOKIE_NAME as i}from"../../constants/common.js";function x(o){const e=n()||"/";for(const t of Object.values(O))a(o,t,{path:e})}function I(o){C(o,i,"1",{path:n()||"/",httpOnly:!0,maxAge:h})}function _(o){l(o)&&a(o,i,{path:n()||"/"})}function l(o){return o.get("cookies")?.[i]==="1"}function c(o){try{return decodeURIComponent(o)}catch{return o}}function A(o){const e=new Map,t=o.req.header("cookie")||"";return t&&t.split(";").forEach(u=>{const[p,...f]=u.split("="),r=p?.trim();if(!r)return;const k=f.join("=").trim();try{const s=m(o,r);if(!s)return;e.set(c(r),s)}catch{e.set(c(r),c(k))}}),e}export{x as clearAuthCookies,_ as clearPostLogoutCookie,l as hasPostLogoutCookie,A as parseCookieHeader,c as safeDecodeURIComponent,I as setPostLogoutCookie};
@@ -0,0 +1,10 @@
1
+ /**
2
+ * `fetch` for requests to Redocly APIs (Reunite main API, feedback, search,
3
+ * Ask AI). Stamps the `x-redocly-client` identification header so portal
4
+ * traffic is attributed correctly — use it instead of bare `fetch` for any
5
+ * Redocly-bound request.
6
+ */
7
+ export declare function fetchWithClient(input: string | URL, init?: Omit<RequestInit, 'headers'> & {
8
+ headers?: Record<string, string>;
9
+ }): Promise<Response>;
10
+ //# sourceMappingURL=fetch-with-client.d.ts.map
@@ -0,0 +1 @@
1
+ import{envConfig as o}from"../config/env-config.js";const r="realm-server",t=o.REDOCLY_PORTAL_VERSION,E=t?`${r}/${t}`:r;function s(n,e={}){return fetch(n,{...e,headers:{...e.headers,"x-redocly-client":E}})}export{s as fetchWithClient};
@@ -0,0 +1,9 @@
1
+ import type { RbacConfig } from '@redocly/config';
2
+ import type { Skill } from '../../types/plugins/skills.js';
3
+ export type SkillAccessUser = {
4
+ isAuthenticated?: boolean;
5
+ email?: string;
6
+ teams?: string[];
7
+ };
8
+ export declare function canAccessSkill(skill: Skill, user?: SkillAccessUser, rbacConfig?: RbacConfig, requiresLogin?: boolean): boolean;
9
+ //# sourceMappingURL=can-access-skill.d.ts.map
@@ -0,0 +1 @@
1
+ import{REDOCLY_ROUTE_RBAC as s,REDOCLY_TEAMS_RBAC as t}from"@redocly/config";import{canAccessResource as a}from"../../utils/rbac.js";function n(c,r={},e={},o=!1){return a({[t]:c.rbac,[s]:{fsPath:c.fsPath}},r,e,o)}export{n as canAccessSkill};
@@ -0,0 +1,5 @@
1
+ import type { RbacConfig } from '@redocly/config';
2
+ import type { Skill } from '../../types/plugins/skills.js';
3
+ import { type SkillAccessUser } from './can-access-skill.js';
4
+ export declare function getAccessibleSkills(skills: Skill[], user?: SkillAccessUser, rbacConfig?: RbacConfig, requiresLogin?: boolean): Skill[];
5
+ //# sourceMappingURL=get-accessible-skills.d.ts.map
@@ -0,0 +1 @@
1
+ import{canAccessSkill as s}from"./can-access-skill.js";function f(e,l={},c={},i=!1){return e.filter(r=>s(r,l,c,i))}export{f as getAccessibleSkills};
@@ -0,0 +1,2 @@
1
+ export declare function getSkillUrl(baseUrl: string, skillSlug: string): string;
2
+ //# sourceMappingURL=get-skill-url.d.ts.map
@@ -0,0 +1 @@
1
+ import{combineUrls as t,withPathPrefix as e}from"@redocly/theme/core/utils";import{AGENT_SKILLS_BASE as i,USER_SKILL_FILENAME as n}from"../../../constants/common.js";function E(o,r){return t(o,e(`${i}/${encodeURIComponent(r)}/${n}`))}export{E as getSkillUrl};
@@ -1,12 +1,12 @@
1
- import"../node-crypto-polyfill.js";import{DOMParser as P}from"@xmldom/xmldom";import{SignedXml as J}from"xml-crypto";import q from"xpath";import{deflateSync as K,inflateSync as Y}from"fflate";import{createHash as Q}from"crypto";import{ulid as X}from"ulid";import{AuthProviderType as u,DEFAULT_TEAM_CLAIM_NAME as Z}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 N}from"../../constants/api.js";import{AuthCookieNames as A,DEFAULT_AUTHENTICATED_TEAM as re,REQUIRED_OIDC_SCOPES as R}from"../../constants/common.js";import{appendQueryParams as oe}from"../../utils/url/append-query-params.js";import{parseHttpsUrl as b}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 v}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 U,encodeBase64URL as le,urlSafeBase64 as j}from"./jwt/encode.js";import{formatSamlCertificate as de}from"./utils/format-saml-certificate.js";function V(e){return e?.type===u.OIDC}function me(e){return e?.type===u.SAML2}async function Ze(e,t){if(V(t))return pe(e,t);if(me(t))return fe(e,t)}async function pe(e,t){const n=await F(e,t),r=new Set((t.scopes||[]).concat(R)),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(R));return await fetch(e,{method:"POST",body:new URLSearchParams({client_id:r.clientId,scope:Array.from(a).join(" "),code:t,redirect_uri:$(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(N.OIDC_CALLBACK)}`,_={state:v(),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=j(se(50)),x=j(Q("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)),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||X(),n=t.startsWith("mcp_")?t:`mcp_${t}`;return{id:n,object:"mcpSession",uri:`urn:redocly:realm:mcp:session:${n}`}}function $(e){const t=b(e);if(!t)return e;const n=we(t.hostname);if(n)return t.hostname=`previewauth--${n.previewBranch}${n.after}`,H(e,t);const r=B(t.hostname);return r?(t.hostname=`${r.projectSlug}.previewauth.${r.after}`,H(e,t)):e}function ye(e){const t=b(e);if(t)return B(t.hostname)?.previewBranch}function H(e,t){return e.replace(/^https:\/\/[^/?#]+/i,`https://${t.host}`)}function B(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 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"
2
2
  xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
3
3
  Version="2.0"
4
- ID="_${v()}"
4
+ ID="_${U()}"
5
5
  IssueInstant="${new Date().toISOString()}"
6
- AssertionConsumerServiceURL="${e}${N.SAML_CALLBACK}"
6
+ AssertionConsumerServiceURL="${e}${R.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(K(new TextEncoder().encode(e)).buffer)}function at(e){const t=U(e);if(t.startsWith("<samlp:Response")||t.indexOf("<saml2p:Response")>-1)return t;const n=Y(new Uint8Array(atob(e).split("").map(r=>r.charCodeAt(0))));return new TextDecoder().decode(n)}function st(e){try{return JSON.parse(U(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 F(e,t){if(!T[e]){const n=t.configurationUrl?await z(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(!V(n))continue;const r=await F(t,n);if(r.jwks_uri){const o=await z(r.jwks_uri);for(const a of o.keys)S.jwks[a.kid]={...a,idpId:t}}}}async function z(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 J({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 W(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([...W(r.payload.teams||[],l),..."defaultTeams"in a&&a.defaultTeams||[],...W("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;case u.OIDC:return e.teamsClaimName;default:return Z}}function c(e,t){return q.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,F as getOidcMetadata,ct as getRedoclyTokenPayload,fe as getSaml2LoginParams,mt as getUserParamsFromCookies,Oe as getUsernameFromPayload,V 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,$ as rewritePreviewAuthRedirectUri,nt as verifyMcpAuthorizationCode,lt as verifySAMLResponse};
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};
@@ -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 +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,5 +1,6 @@
1
1
  type CorsMiddlewareOptions = {
2
2
  allowMethods?: string[];
3
+ exposeHeaders?: string[];
3
4
  };
4
5
  export declare function corsMiddleware(options: CorsMiddlewareOptions): import("hono").MiddlewareHandler;
5
6
  export {};
@@ -1 +1 @@
1
- import{cors as o}from"hono/cors";import{envConfig as r}from"../../config/env-config.js";function n(e){return r.PROJECT_URL?o({origin:r.PROJECT_URL,allowMethods:e.allowMethods}):o()}export{n as corsMiddleware};
1
+ import{cors as r}from"hono/cors";import{envConfig as o}from"../../config/env-config.js";function a(e){return o.PROJECT_URL?r({origin:o.PROJECT_URL,allowMethods:e.allowMethods,exposeHeaders:e.exposeHeaders}):r({exposeHeaders:e.exposeHeaders})}export{a as corsMiddleware};
@@ -1 +1 @@
1
- import{DEFAULT_SEARCH_ENGINE as r}from"../../constants/plugins/search.js";import{logger as e}from"../../tools/notifiers/logger.js";import{SearchEngine as t}from"../../plugins/search/engines/search-engine.js";function E(a){return async(o,i)=>{if(!a.searchEngine&&!a.config?.search?.hide){e.info("Loading search data...");const c=a.config?.search?.engine??r,n=new t(c,a.globalData.l10n);await n.initIndexSchema(a.searchFacets),await n.import(a.outdir),a.setSearchEngine(n),e.info("Search data loaded")}await i()}}export{E as ensureSearchData};
1
+ import{DEFAULT_SEARCH_ENGINE as r}from"@redocly/config";import{logger as e}from"../../tools/notifiers/logger.js";import{SearchEngine as t}from"../../plugins/search/engines/search-engine.js";function E(a){return async(o,i)=>{if(!a.searchEngine&&!a.config?.search?.hide){e.info("Loading search data...");const c=a.config?.search?.engine??r,n=new t(c,a.globalData.l10n);await n.initIndexSchema(a.searchFacets),await n.import(a.outdir),a.setSearchEngine(n),e.info("Search data loaded")}await i()}}export{E as ensureSearchData};
@@ -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 y,deleteCookie as X}from"hono/cookie";import{AuthProviderType as W}from"@redocly/config";import{withPathPrefix as L,getPathPrefix as O}from"@redocly/theme/core/utils";import{compareURIs as Y}from"../../../utils/url/compare-uris.js";import{ensureArray as b}from"../../../utils/array/ensure-array.js";import{ALTERNATIVE_AUD_CLAIM_NAME as N,JWT_SECRET_KEY as v,ORG_SLUG as Q,ORG_ID as x}from"../../constants/common.js";import{AUTH_SEGMENT as ee,ServerRoutes as S}from"../../../constants/api.js";import{AuthCookieNames as A,DEFAULT_COOKIE_EXPIRATION as F}from"../../../constants/common.js";import{sanitizeRedirectPathname as H}from"../../../utils/url/sanitize-redirect-pathname.js";import{telemetry as T}from"../../telemetry/index.js";import{envConfig as B}from"../../config/env-config.js";import{clearAuthCookies as j}from"../../utils/cookie.js";import{getAuthProviderLoginParams as re,isOidcProviderConfig as $,isSaml2ProviderConfig as oe,oidcExchangeCodeForToken as ne,buildLoginUrl as te,decodeSamlResponse as se,extractUserClaims as ie,parseSamlResponse as ae,parseOidcState as de,verifySAMLResponse as ce,getUsernameFromPayload as le,buildOidcLogoutUrl as ue,getOidcMetadata as K,getRedoclyTokenPayload as pe,isRedoclySso as ge,rewritePreviewAuthRedirectUri as fe,parsePreviewBranch as z,buildOidcLoginUrl as me,createMcpSessionResource as D}from"../auth.js";import*as k from"../jwt/jwt.js";import{AlgorithmTypes as U}from"../jwt/types.js";import{handleErrorPageRender as he}from"../utils.js";import{encodeBase64URL as Ie}from"../jwt/encode.js";import{resolveUiLocalesForIdpLogin as we}from"./helpers/resolve-ui-locales-for-idp-login.js";async function be(s){if(B.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 y(s,A.AUTHORIZATION,a,{path:O()||"/",httpOnly:!0,secure:!0,sameSite:"none"}),s.newResponse(null,200,{})}function qe(){return async s=>{const e=s.get("logger"),r=encodeURIComponent(s.req.query("message")||"");e.error(`Login error: ${r}`);const a=`${S.LOGIN}/?error=${encodeURIComponent(r)}`;return s.newResponse(null,301,{Location:a})}}function G(s){if(!s||!s.includes(S.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 Ne(s){return async e=>{const r=e.get("logger"),a=s.getConfig().ssoDirect,o=de(e.req.query("state")),m=o.idpId,t=o.source==="mcp"||o.redirectTo&&typeof o.redirectTo=="string"&&o.redirectTo.includes(S.MCP_CALLBACK),c=t?G(typeof o.redirectTo=="string"?o.redirectTo:void 0):null,i=a?.[m];if(!$(i))return r.error("OIDC login error: missing OIDC provider config"),e.text("Forbidden",403);const d=await K(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}]),he(e,s,{slug:"/"},403,"403OIDC");if(!u){const w="Code is expected but not present";return r.error(`OIDC login error: ${w}`),t&&T.sendMcpAuthorizationFailedMessage([{...D(c),error:w,error_details:null}]),new Response(`Forbidden: ${w}`,{status:403})}const R=typeof o.redirectUri=="string"?o.redirectUri:new URL(L(S.OIDC_CALLBACK),e.req.url).toString(),I=e.get("cookies")?.code_verifier,l=await ne(p,u,R,i,{...i.tokenRequestCustomParams,...I?{code_verifier:I}:{}});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 w="No id_token, please, add openid to scopes";return r.error(`OIDC login error: ${w}`),t&&T.sendMcpAuthorizationFailedMessage([{...D(c),error:w,error_details:null}]),new Response(`Forbidden: ${w}`,{status:403})}const{payload:f,header:M}=k.decode(l.id_token),n=M.alg===U.RS256;if(i.audience?.length&&![...b(f.aud||[]),...b(f[N]||[])].some(_=>i.audience?.includes(_))){const _="No valid audience found in id_token";return r.error(`OIDC login error: ${_}`),t&&T.sendMcpAuthorizationFailedMessage([{...D(c),error:_,error_details:null}]),new Response(`Forbidden: ${_}`)}const g=n?l.id_token:await k.sign({...f,idpId:m},v,U.HS256);le(f)||r.warn("To display your username, the required 'email' or 'full_profile' scope must be added to the identity provider configuration");const P=i?.tokenExpirationTime?Date.now()+i.tokenExpirationTime*1e3:f.exp*1e3||Date.now()+F*1e3;if(i.introspectEndpoint){const w=await fetch(i.introspectEndpoint,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({access_token:l.access_token})});if(w.ok){const E=(await w.json()).ext?.federatedIdentity;E&&(y(e,A.FEDERATED_ACCESS_TOKEN,E.access_token||"",{path:O()||"/",httpOnly:!1,expires:new Date(P)}),y(e,A.FEDERATED_ID_TOKEN,E.id_token||"",{path:O()||"/",httpOnly:!1,expires:new Date(P)}))}else r.warn(`OIDC introspect error: ${w.statusText}`)}if(y(e,A.AUTHORIZATION,g,{path:O()||"/",httpOnly:!0,expires:new Date(P)}),g!==l.id_token&&y(e,A.IDP_ID_TOKEN,l.id_token||"",{path:O()||"/",httpOnly:!0,expires:new Date(P)}),y(e,A.IDP_ACCESS_TOKEN,l.access_token||"",{path:O()||"/",httpOnly:!0,expires:new Date(P)}),X(e,"code_verifier",{path:O()||"/"}),t&&o.redirectTo&&typeof o.redirectTo=="string"&&o.redirectTo.includes(S.MCP_CALLBACK)){const _=`${e.req.url.split("?")[0].replace(S.OIDC_CALLBACK,"")}${o.redirectTo}`;return e.newResponse(null,302,{Location:_})}const J=typeof o.redirectTo=="string"?o.redirectTo:void 0;let Z=H(new URL(J||"/",e.req.url).pathname);const V=e.newResponse(null,302,{Location:Z});return r.updateContext({email:f.email,subject:f.sub}),r.info("OIDC login successful"),V}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 C="Something went wrong";return r.error(`OIDC login error: ${C}`),t&&T.sendMcpAuthorizationFailedMessage([{...D(c),error:C,error_details:null}]),e.text(C,500)}}function Fe(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 $(t)||j(e),r.info("Logout successful"),e.newResponse(null,200,{});let c;if($(t)){const i=(await K(o,t)).end_session_endpoint;if(i){const d=new URL(e.req.url),C=e.req.header("x-forwarded-proto")||d.protocol.slice(0,-1)||"https",p=e.req.header("x-forwarded-host")||d.host,u=`${C}://${p}`,h=z(u),R=h?Ie(JSON.stringify({branch:z(u)})):void 0,I=h?`${fe(u)}/${ee}/logout`:`${u}${L(S.POST_LOGOUT)}`;c=ue(i,I,e.get("cookies")?.[A.IDP_ID_TOKEN]||e.get("cookies")?.[A.AUTHORIZATION]||"",R)}}return r.info("Logout successful"),j(e),e.newResponse(null,302,{Location:c||L("/")})}}function He(s){return async e=>{const r=s.getConfig().access?.logoutReturnUrl,a=r||L("/");return e.newResponse(null,302,{Location:a})}}function Be(s){return async e=>{const r=e.get("logger"),a=e.req.param("code"),o=B.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(L("/"));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(L("/"))):(r.error("Invite error",await c.text()),e.redirect(L("/")));const i=await c.json(),d=new URL(L("/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 C=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 q=G(C||void 0);T.sendMcpAuthorizationFailedMessage([{...D(q),error:g,error_details:null}])}return e.text(`Forbidden: ${g}`,403)}const I=we({localePrefixParam:o.searchParams.get("localePrefix"),l10n:s.getGlobalData()?.l10n}),l=d&&a?await re(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;let M,n={};if(h&&u&&l&&l.type===W.OIDC){r.info(`Building MCP OAuth login URL with redirect_uri: ${u}`);const g=me("",{...l,extraParams:f},C,m,{redirectUriOverride:u,sourceOverride:"mcp",branchOverride:void 0,uiLocales:I});M=g.loginUrl,n=g.cookies||{}}else if(l){const g=te({...l,extraParams:f},i,C,m,I);M=g.loginUrl,n=g.cookies||{}}return Object.keys(n).forEach(g=>{y(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 Ke(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=se(o),{success:c,uid:i,nameFormat:d,attrs:C,issuerId:p,expiresAt:u}=ae(t),{idpId:h,redirectTo:R}=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 I=s.getConfig().ssoDirect?.[h];if(!I||!oe(I)){const n="Cannot find valid IdP";return r.error(`SAML2 login error: ${n}`),e.text(`Permission denied: ${n}`,401)}if(!(I.issuerId&&p&&Y(I.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 ce(t,I.x509PublicCert)){const n="SAMLResponse signature invalid";return r.error(`SAML2 login error: ${n}`),e.text(n,401)}const f=ie(i,d,C,I.teamsAttributeName);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 y(e,A.AUTHORIZATION,M,{path:O()||"/",httpOnly:!0,expires:new Date(u*1e3)}),r.updateContext({email:f.email,subject:f.sub}),r.info("SAML2 login successful"),e.newResponse(null,302,{Location:R||"/"})}}function ze(s){return async e=>{const r=e.get("logger"),a=new URL(e.req.query("redirectTo")||"/",e.req.url),o=L(H(a.pathname)),m=s.getConfig().ssoDirect,t=Object.entries(m||{}).find(([,R])=>$(R)&&ge(R));if(!(m&&t))return e.newResponse(null,302,{Location:o});const i=e.req.query("token"),d=i&&await pe(i);if(!d)return e.newResponse(null,302,{Location:o});if(!b(d[N]||[]).some(R=>R===Q||R===x))return e.newResponse(null,302,{Location:o});const u=await k.sign({...d,idpId:t?.at(0)},v,U.HS256),h=Date.now()+F*1e3;return y(e,A.AUTHORIZATION,u,{path:O()||"/",httpOnly:!0,expires:new Date(h),sameSite:"None",secure:!0}),r.info("Token login successful"),e.newResponse(null,302,{Location:o})}}export{be as authorizeHandler,je as idpLoginHandler,Be as inviteHandler,Fe as logoutHandler,Ne as oidcCallbackHandler,He as postLogoutHandler,qe as redoclyLoginCallbackHandler,ze as redoclyTokenLoginHandler,Ke as samlCallbackHandler};
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{fetchWithClient as te}from"../../utils/fetch-with-client.js";import{clearAuthCookies as K,clearPostLogoutCookie as $,hasPostLogoutCookie as se,setPostLogoutCookie as z}from"../../utils/cookie.js";import{getAuthProviderLoginParams as ie,isOidcProviderConfig as E,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 G,getRedoclyTokenPayload as Ce,isRedoclySso as Ae,rewritePreviewAuthRedirectUri as Ie,parsePreviewBranch as J,buildOidcLoginUrl as we,createMcpSessionResource as D}from"../auth.js";import*as k from"../jwt/jwt.js";import{AlgorithmTypes as U}from"../jwt/types.js";import{handleErrorPageRender as Le}from"../utils.js";import{encodeBase64URL as Re}from"../jwt/encode.js";import{resolveUiLocalesForIdpLogin as _e}from"./helpers/resolve-ui-locales-for-idp-login.js";async function je(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 Ke(){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 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),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}]),Le(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 de(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);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()+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 W=B(new URL(V||"/",e.req.url).pathname);const X=e.newResponse(null,302,{Location:W});return r.updateContext({email:f.email,subject:f.sub}),r.info("OIDC login successful"),X}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 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 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?Re(JSON.stringify({branch:J(u)})):void 0,C=h?`${Ie(u)}/${ne}/logout`:`${u}${_(P.POST_LOGOUT)}`;c=he(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 Je(s){return async e=>{const r=s.getConfig().access?.logoutReturnUrl,a=r||_("/");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,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 te(`${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 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",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=_e({localePrefixParam:o.searchParams.get("localePrefix"),l10n:s.getGlobalData()?.l10n}),l=d&&a?await ie(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;se(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=we("",{...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=ce({...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 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:c,uid:i,nameFormat:d,attrs:I,issuerId:p,expiresAt:u}=pe(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||!ae(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 fe(t,C.x509PublicCert)){const n="SAMLResponse signature invalid";return r.error(`SAML2 login error: ${n}`),e.text(n,401)}const f=ue(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 Xe(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)&&Ae(w));if(!(m&&t))return e.newResponse(null,302,{Location:o});const i=e.req.query("token"),d=i&&await Ce(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{je as authorizeHandler,Ve as idpLoginHandler,Ze as inviteHandler,Ge as logoutHandler,ze as oidcCallbackHandler,Je as postLogoutHandler,Ke as redoclyLoginCallbackHandler,Xe as redoclyTokenLoginHandler,We as samlCallbackHandler};