@redocly/reef 0.137.0-next.7 → 0.137.0-next.9
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.
- package/CHANGELOG.md +36 -0
- package/dist/client/templates/api-docs/template.js +8 -3
- package/dist/constants/l10n/langs/ar.js +1 -1
- package/dist/constants/l10n/langs/de.js +1 -1
- package/dist/constants/l10n/langs/en.js +1 -1
- package/dist/constants/l10n/langs/es.js +1 -1
- package/dist/constants/l10n/langs/fr.js +1 -1
- package/dist/constants/l10n/langs/hi.js +1 -1
- package/dist/constants/l10n/langs/it.js +1 -1
- package/dist/constants/l10n/langs/ja.js +1 -1
- package/dist/constants/l10n/langs/ko.js +1 -1
- package/dist/constants/l10n/langs/pl.js +1 -1
- package/dist/constants/l10n/langs/pt-BR.js +1 -1
- package/dist/constants/l10n/langs/pt.js +1 -1
- package/dist/constants/l10n/langs/ru.js +1 -1
- package/dist/constants/l10n/langs/uk.js +1 -1
- package/dist/constants/l10n/langs/zh.js +1 -1
- package/dist/server/config/env-schemas/feature-flags.d.ts +1 -1
- package/dist/server/constants/common.d.ts +1 -0
- package/dist/server/constants/common.js +1 -1
- package/dist/server/plugins/mcp/handlers/docs-mcp-handler.js +1 -1
- package/dist/server/plugins/mcp/handlers/errors.d.ts +1 -1
- package/dist/server/plugins/mcp/handlers/errors.js +1 -1
- package/dist/server/plugins/mcp/servers/docs-server.d.ts +2 -2
- package/dist/server/plugins/mcp/servers/docs-server.js +1 -1
- package/dist/server/plugins/mcp/servers/mcp-server.d.ts +2 -11
- package/dist/server/plugins/mcp/servers/mcp-server.js +3 -3
- package/dist/server/plugins/search/ai-indexer/prepare-semantic-documents.d.ts +4 -2
- package/dist/server/plugins/search/ai-indexer/prepare-semantic-documents.js +1 -3
- package/dist/server/plugins/search/index.js +1 -1
- package/dist/server/plugins/search/llmstxt/build-page-llms-txt-md.d.ts +4 -0
- package/dist/server/plugins/search/llmstxt/build-page-llms-txt-md.js +3 -0
- package/dist/server/plugins/search/llmstxt/create-llms-txt-generator.d.ts +4 -0
- package/dist/server/plugins/search/llmstxt/create-llms-txt-generator.js +1 -0
- package/dist/server/plugins/search/llmstxt/get-llms-txt-exclude-matcher.d.ts +4 -0
- package/dist/server/plugins/search/llmstxt/get-llms-txt-exclude-matcher.js +1 -0
- package/dist/server/plugins/search/llmstxt/index.d.ts +2 -2
- package/dist/server/plugins/search/llmstxt/is-included-in-llms-txt.d.ts +6 -0
- package/dist/server/plugins/search/llmstxt/is-included-in-llms-txt.js +1 -0
- package/dist/server/store.js +1 -1
- package/dist/server/types/web-server.d.ts +8 -0
- package/dist/server/utils/envs/get-api-route-allowed-env-variables.js +1 -1
- package/dist/server/utils/get-route-ai-documents-store.d.ts +5 -0
- package/dist/server/utils/get-route-ai-documents-store.js +1 -0
- package/dist/server/utils/get-route-static-data.d.ts +4 -0
- package/dist/server/utils/get-route-static-data.js +1 -0
- package/dist/server/utils/llmstxt/agent-feedback-llms-footer.js +1 -1
- package/dist/server/utils/llmstxt/resolve-llms-txt-md.d.ts +10 -0
- package/dist/server/utils/llmstxt/resolve-llms-txt-md.js +1 -0
- package/dist/server/web-server/auth.d.ts +13 -2
- package/dist/server/web-server/auth.js +3 -3
- package/dist/server/web-server/dev-server.js +1 -1
- package/dist/server/web-server/routes/auth.js +1 -1
- package/dist/server/web-server/routes/dynamic-route.d.ts +2 -1
- package/dist/server/web-server/routes/dynamic-route.js +1 -1
- package/dist/server/web-server/routes/index.d.ts +2 -1
- package/dist/server/web-server/routes/index.js +1 -1
- package/dist/server/web-server/routes/llms-txt.d.ts +4 -0
- package/dist/server/web-server/routes/llms-txt.js +1 -0
- package/package.json +10 -10
|
@@ -1 +1 @@
|
|
|
1
|
-
import{setCookie as O,deleteCookie as U}from"hono/cookie";import{AuthProviderType as Q,DEFAULT_TEAM_CLAIM_NAME as x}from"@redocly/config";import{withPathPrefix as L,getPathPrefix as C}from"@redocly/theme/core/utils";import{compareURIs as ee}from"../../../utils/url/compare-uris.js";import{ensureArray as N}from"../../../utils/array/ensure-array.js";import{ALTERNATIVE_AUD_CLAIM_NAME as H,JWT_SECRET_KEY as v,ORG_SLUG as re,ORG_ID as oe}from"../../constants/common.js";import{AUTH_SEGMENT as ne,ServerRoutes as P}from"../../../constants/api.js";import{AuthCookieNames as R,DEFAULT_COOKIE_EXPIRATION as B}from"../../../constants/common.js";import{sanitizeRedirectPathname as K}from"../../../utils/url/sanitize-redirect-pathname.js";import{telemetry as D}from"../../telemetry/index.js";import{envConfig as j}from"../../config/env-config.js";import{fetchWithClient as te}from"../../utils/fetch-with-client.js";import{clearAuthCookies as z,clearPostLogoutCookie as $,hasPostLogoutCookie as se,setPostLogoutCookie as G}from"../../utils/cookie.js";import{getAuthProviderLoginParams as ie,isOidcProviderConfig as q,isSaml2ProviderConfig as ae,oidcExchangeCodeForToken as de,buildLoginUrl as ce,decodeSamlResponse as le,extractUserClaims as ue,parseSamlResponse as pe,parseOidcState as ge,verifySAMLResponse as fe,getUsernameFromPayload as me,buildOidcLogoutUrl as he,getOidcMetadata as J,getRedoclyTokenPayload as Ie,isRedoclySso as Re,rewritePreviewAuthRedirectUri as _e,parsePreviewBranch as Z,buildOidcLoginUrl as Ce,createMcpSessionResource as T}from"../auth.js";import*as k from"../jwt/jwt.js";import{AlgorithmTypes as E}from"../jwt/types.js";import{handleErrorPageRender as Ae}from"../utils.js";import{encodeBase64URL as we}from"../jwt/encode.js";import{resolveUiLocalesForIdpLogin as Oe}from"./helpers/resolve-ui-locales-for-idp-login.js";async function Ke(s){if(j.isProductionEnv)return s.newResponse(null,404,{});const{password:e,...r}=await s.req.json(),a=await k.sign({...r,name:r.username||r.email||"Unknown"},v,E.HS256);return O(s,R.AUTHORIZATION,a,{path:C()||"/",httpOnly:!0,secure:!0,sameSite:"none"}),$(s),s.newResponse(null,200,{})}function je(){return async s=>{const e=s.get("logger"),r=encodeURIComponent(s.req.query("message")||"");e.error(`Login error: ${r}`);const a=`${P.LOGIN}/?error=${encodeURIComponent(r)}`;return s.newResponse(null,301,{Location:a})}}function V(s){if(!s||!s.includes(P.MCP_CALLBACK))return null;try{const e=s.split("/"),r=e[e.length-1];if(r){const a=Buffer.from(r,"base64url").toString("utf-8");return JSON.parse(a).mcpSessionId||null}}catch{}return null}function ze(s){return async e=>{const r=e.get("logger"),a=s.getConfig().ssoDirect;let o;try{o=ge(e.req.query("state"))}catch{return r.warn("OIDC login error: Invalid OAuth2 state"),e.text("Bad request: Invalid OAuth2 state",400)}const m=o.idpId,t=o.source==="mcp"||o.redirectTo&&typeof o.redirectTo=="string"&&o.redirectTo.includes(P.MCP_CALLBACK),l=t?V(typeof o.redirectTo=="string"?o.redirectTo:void 0):null,i=a?.[m];if(!q(i))return r.error("OIDC login error: missing OIDC provider config"),e.text("Forbidden",403);const d=await J(m,i);if(a&&!d.token_endpoint){const p="Invalid OIDC configuration: token_endpoint is required";return r.error(`OIDC login error: ${p}`),e.text(p,500)}try{const p=d.token_endpoint,u=e.req.query("code"),h=e.req.query("error");if(h)return t&&D.sendMcpAuthorizationFailedMessage([{...T(l),error:`OIDC error: ${h}`,error_details:e.req.query("error_description")||null}]),Ae(e,s,{slug:"/"},403,"403OIDC");if(!u){const _="Code is expected but not present";return r.error(`OIDC login error: ${_}`),t&&D.sendMcpAuthorizationFailedMessage([{...T(l),error:_,error_details:null}]),new Response(`Forbidden: ${_}`,{status:403})}const w=typeof o.redirectUri=="string"?o.redirectUri:new URL(L(P.OIDC_CALLBACK),e.req.url).toString(),I=e.get("cookies")?.code_verifier,c=await de(p,u,w,i,{...i.tokenRequestCustomParams,...I?{code_verifier:I}:{}});if(c.error)return r.error(`Error from OIDC provider: "${c.error}"`),t&&D.sendMcpAuthorizationFailedMessage([{...T(l),error:`Token exchange error: ${c.error}`,error_details:c.error_description||null}]),e.text(`Forbidden: ${c.error_description||c.error}`,403);if(!c?.id_token){const _="No id_token, please, add openid to scopes";return r.error(`OIDC login error: ${_}`),t&&D.sendMcpAuthorizationFailedMessage([{...T(l),error:_,error_details:null}]),new Response(`Forbidden: ${_}`,{status:403})}const{payload:f,header:M}=k.decode(c.id_token),n=M.alg===E.RS256;if(i.audience?.length&&![...N(f.aud||[]),...N(f[H]||[])].some(y=>i.audience?.includes(y))){const y="No valid audience found in id_token";return r.error(`OIDC login error: ${y}`),t&&D.sendMcpAuthorizationFailedMessage([{...T(l),error:y,error_details:null}]),new Response(`Forbidden: ${y}`)}const g=n?c.id_token:await k.sign({...f,idpId:m},v,E.HS256);me(f)||r.warn("To display your username, the required 'email' or 'full_profile' scope must be added to the identity provider configuration");const S=i?.tokenExpirationTime?Date.now()+i.tokenExpirationTime*1e3:f.exp*1e3||Date.now()+B*1e3;if(i.introspectEndpoint){const _=await fetch(i.introspectEndpoint,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({access_token:c.access_token})});if(_.ok){const b=(await _.json()).ext?.federatedIdentity;b&&(O(e,R.FEDERATED_ACCESS_TOKEN,b.access_token||"",{path:C()||"/",httpOnly:!1,expires:new Date(S)}),O(e,R.FEDERATED_ID_TOKEN,b.id_token||"",{path:C()||"/",httpOnly:!1,expires:new Date(S)}))}else r.warn(`OIDC introspect error: ${_.statusText}`)}if(O(e,R.AUTHORIZATION,g,{path:C()||"/",httpOnly:!0,expires:new Date(S)}),g!==c.id_token&&O(e,R.IDP_ID_TOKEN,c.id_token||"",{path:C()||"/",httpOnly:!0,expires:new Date(S)}),O(e,R.IDP_ACCESS_TOKEN,c.access_token||"",{path:C()||"/",httpOnly:!0,expires:new Date(S)}),c.refresh_token?O(e,R.IDP_REFRESH_TOKEN,c.refresh_token,{path:C()||"/",httpOnly:!0,expires:new Date(S)}):U(e,R.IDP_REFRESH_TOKEN,{path:C()||"/"}),U(e,"code_verifier",{path:C()||"/"}),$(e),t&&o.redirectTo&&typeof o.redirectTo=="string"&&o.redirectTo.includes(P.MCP_CALLBACK)){const y=`${e.req.url.split("?")[0].replace(P.OIDC_CALLBACK,"")}${o.redirectTo}`;return e.newResponse(null,302,{Location:y})}const W=typeof o.redirectTo=="string"?o.redirectTo:void 0;let X=K(new URL(W||"/",e.req.url).pathname);const Y=e.newResponse(null,302,{Location:X});return r.updateContext({email:f.email,subject:f.sub}),r.info("OIDC login successful"),Y}catch(p){const u=p instanceof Error?p.message:String(p),h=p instanceof Error?p.stack:String(p);if(r.error(`OIDC login error: ${u}`),t&&D.sendMcpAuthorizationFailedMessage([{...T(l),error:u,error_details:h}]),p.error==="access_denied")return r.info("Access denied"),e.text("Forbidden",403)}const A="Something went wrong";return r.error(`OIDC login error: ${A}`),t&&D.sendMcpAuthorizationFailedMessage([{...T(l),error:A,error_details:null}]),e.text(A,500)}}function Ge(s){return async e=>{const r=e.get("logger"),o=e.get("auth").claims?.idpId,t=s.getConfig().ssoDirect?.[o];if(e.req.method==="POST")return q(t)||(z(e),G(e)),r.info("Logout successful"),e.newResponse(null,200,{});let l;if(q(t)){const i=(await J(o,t)).end_session_endpoint;if(i){const d=new URL(e.req.url),A=e.req.header("x-forwarded-proto")||d.protocol.slice(0,-1)||"https",p=e.req.header("x-forwarded-host")||d.host,u=`${A}://${p}`,h=Z(u),w=h?we(JSON.stringify({branch:Z(u)})):void 0,I=h?`${_e(u)}/${ne}/logout`:`${u}${L(P.POST_LOGOUT)}`;l=he(i,I,e.get("cookies")?.[R.IDP_ID_TOKEN]||e.get("cookies")?.[R.AUTHORIZATION]||"",w)}}return r.info("Logout successful"),z(e),G(e),e.newResponse(null,302,{Location:l||L("/")})}}function Je(s){return async e=>{const r=s.getConfig().access?.logoutReturnUrl,a=r||L("/");return e.newResponse(null,302,{Location:a})}}function Ze(s){return async e=>{const r=e.get("logger"),a=e.req.param("code"),o=j.BH_API_URL,m=(t,l,i)=>t&&l?`${t} ${l.charAt(0)}`:i;try{if(!o)throw new Error("BH_API_URL is not set");const t=s.getConfig().ssoDirect;if(!t||!Object.keys(t).length)return r.warn("Invite no sso configured to handle"),e.redirect(L("/"));const l=await te(`${o}/public-user-invites/${a}`);if(!l.ok)return l.status===404?(r.warn(`Invite ${a} not found redirect to homepage`),e.redirect(L("/"))):(r.error("Invite error",await l.text()),e.redirect(L("/")));const i=await l.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 Ve(s){return async e=>{const r=e.get("logger"),a=s.getConfig().ssoDirect,o=new URL(e.req.url),m=e.req.query("inviteCode"),t=e.req.header("x-forwarded-proto")||o.protocol.slice(0,-1)||"https",l=e.req.header("x-forwarded-host")||o.host,i=`${t}://${l}`;let d=o.searchParams.get("idpId");const A=o.searchParams.get("redirectTo"),p=Object.keys(a||{})[0];d=d||p;const u=o.searchParams.get("mcp_redirect_uri"),h=!!u;if(!a?.[d]){const g="Invalid idpId";if(r.error(`IdP login error: ${g}`),h){const F=V(A||void 0);D.sendMcpAuthorizationFailedMessage([{...T(F),error:g,error_details:null}])}return e.text(`Forbidden: ${g}`,403)}const I=Oe({localePrefixParam:o.searchParams.get("localePrefix"),l10n:s.getGlobalData()?.l10n}),c=d&&a?await ie(d,a[d]):void 0,f={};for(const g of Object.keys(c?.extraParams||{}))f[g]=o.searchParams.get(g)||c?.extraParams?.[g]||void 0;se(e)&&(f.prompt="login",f.post_logout="1");let M,n={};if(h&&u&&c&&c.type===Q.OIDC){r.info(`Building MCP OAuth login URL with redirect_uri: ${u}`);const g=Ce("",{...c,extraParams:f},A,m,{redirectUriOverride:u,sourceOverride:"mcp",branchOverride:void 0,uiLocales:I});M=g.loginUrl,n=g.cookies||{}}else if(c){const g=ce({...c,extraParams:f},i,A,m,I);M=g.loginUrl,n=g.cookies||{}}return Object.keys(n).forEach(g=>{O(e,g,n[g].value,n[g].options)}),r.info(`IdP login initiated for ID '${d}'`),e.newResponse(null,302,{Location:M||new URL(e.req.url).pathname})}}function We(s){return async e=>{const r=e.get("logger"),a=await e.req.formData(),o=a.get("SAMLResponse"),m=a.get("RelayState");if(typeof o!="string"||typeof m!="string"){const n="SAMLResponse is required";return r.error(`SAML2 login error: ${n}`),e.text(`Bad request: ${n}`,400)}const t=le(o),{success:l,uid:i,nameFormat:d,attrs:A,issuerId:p,expiresAt:u}=pe(t),{idpId:h,redirectTo:w}=JSON.parse(m);if(!l){const n="SAML2 assertion is not successful";return r.error(`SAML2 login error: ${n}`),e.text(`Permission denied: ${n}`,401)}if(!u||Math.ceil(Date.now()/1e3)>=u){const n="SAML2 Token Expired";return r.error(`SAML2 login error: ${n}`),e.text(n,401)}const I=s.getConfig().ssoDirect?.[h];if(!I||!ae(I)){const n="Cannot find valid IdP";return r.error(`SAML2 login error: ${n}`),e.text(`Permission denied: ${n}`,401)}if(!(I.issuerId&&p&&ee(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 fe(t,I.x509PublicCert)){const n="SAMLResponse signature invalid";return r.error(`SAML2 login error: ${n}`),e.text(n,401)}const f=ue(i,d,A,I.teamsAttributeName??x);if(!f.sub){const n="The provider did not return a valid user identity.";return r.error(`SAML2 login error: ${n}`),e.text(n,400)}if(!f.email){const n="The provider did not return a valid user email.";return r.error(`SAML2 login error: ${n}`),e.text(n,400)}const M=await k.sign({...f,idpId:h},v,E.HS256);return O(e,R.AUTHORIZATION,M,{path:C()||"/",httpOnly:!0,expires:new Date(u*1e3)}),U(e,R.IDP_REFRESH_TOKEN,{path:C()||"/"}),$(e),r.updateContext({email:f.email,subject:f.sub}),r.info("SAML2 login successful"),e.newResponse(null,302,{Location:w||"/"})}}function Xe(s){return async e=>{const r=e.get("logger"),a=new URL(e.req.query("redirectTo")||"/",e.req.url),o=L(K(a.pathname)),m=s.getConfig().ssoDirect,t=Object.entries(m||{}).find(([,w])=>q(w)&&Re(w));if(!(m&&t))return e.newResponse(null,302,{Location:o});const i=e.req.query("token"),d=i&&await Ie(i);if(!d)return e.newResponse(null,302,{Location:o});if(!N(d[H]||[]).some(w=>w===re||w===oe))return e.newResponse(null,302,{Location:o});const u=await k.sign({...d,idpId:t?.at(0)},v,E.HS256),h=Date.now()+B*1e3;return O(e,R.AUTHORIZATION,u,{path:C()||"/",httpOnly:!0,expires:new Date(h),sameSite:"None",secure:!0}),U(e,R.IDP_REFRESH_TOKEN,{path:C()||"/"}),$(e),r.info("Token login successful"),e.newResponse(null,302,{Location:o})}}export{Ke as authorizeHandler,Ve as idpLoginHandler,Ze as inviteHandler,Ge as logoutHandler,ze as oidcCallbackHandler,Je as postLogoutHandler,je as redoclyLoginCallbackHandler,Xe as redoclyTokenLoginHandler,We as samlCallbackHandler};
|
|
1
|
+
import{setCookie as L,deleteCookie as P}from"hono/cookie";import{AuthProviderType as ee,DEFAULT_TEAM_CLAIM_NAME as re}from"@redocly/config";import{withPathPrefix as w,getPathPrefix as A}from"@redocly/theme/core/utils";import{compareURIs as oe}from"../../../utils/url/compare-uris.js";import{ensureArray as N}from"../../../utils/array/ensure-array.js";import{ALTERNATIVE_AUD_CLAIM_NAME as H,JWT_SECRET_KEY as U,MAX_AUTH_TOKEN_COOKIE_BYTES as F,ORG_SLUG as te,ORG_ID as ne}from"../../constants/common.js";import{AUTH_SEGMENT as ie,ServerRoutes as D}from"../../../constants/api.js";import{AuthCookieNames as _,DEFAULT_COOKIE_EXPIRATION as K}from"../../../constants/common.js";import{sanitizeRedirectPathname as z}from"../../../utils/url/sanitize-redirect-pathname.js";import{telemetry as k}from"../../telemetry/index.js";import{envConfig as j}from"../../config/env-config.js";import{fetchWithClient as se}from"../../utils/fetch-with-client.js";import{clearAuthCookies as J,clearPostLogoutCookie as v,hasPostLogoutCookie as ae,setPostLogoutCookie as G}from"../../utils/cookie.js";import{getAuthProviderLoginParams as de,isOidcProviderConfig as b,isSaml2ProviderConfig as le,oidcExchangeCodeForToken as ce,buildLoginUrl as ue,decodeSamlResponse as pe,extractUserClaims as ge,parseSamlResponse as fe,parseOidcState as me,verifySAMLResponse as he,getUsernameFromPayload as Ce,buildOidcLogoutUrl as Ie,isIdpIssuedToken as _e,getOidcMetadata as Z,getRedoclyTokenPayload as Ae,isRedoclySso as Re,rewritePreviewAuthRedirectUri as Oe,parsePreviewBranch as V,buildOidcLoginUrl as Te,createMcpSessionResource as M,signTokenWithinCookieSizeLimit as W}from"../auth.js";import*as E from"../jwt/jwt.js";import{AlgorithmTypes as $}from"../jwt/types.js";import{handleErrorPageRender as ye}from"../utils.js";import{encodeBase64URL as Le}from"../jwt/encode.js";import{resolveUiLocalesForIdpLogin as we}from"./helpers/resolve-ui-locales-for-idp-login.js";async function Je(n){if(j.isProductionEnv)return n.newResponse(null,404,{});const{password:e,...r}=await n.req.json(),d=await E.sign({...r,name:r.username||r.email||"Unknown"},U,$.HS256);return L(n,_.AUTHORIZATION,d,{path:A()||"/",httpOnly:!0,secure:!0,sameSite:"none"}),v(n),n.newResponse(null,200,{})}function Ge(){return async n=>{const e=n.get("logger"),r=encodeURIComponent(n.req.query("message")||"");e.error(`Login error: ${r}`);const d=`${D.LOGIN}/?error=${encodeURIComponent(r)}`;return n.newResponse(null,301,{Location:d})}}function X(n){if(!n||!n.includes(D.MCP_CALLBACK))return null;try{const e=n.split("/"),r=e[e.length-1];if(r){const d=Buffer.from(r,"base64url").toString("utf-8");return JSON.parse(d).mcpSessionId||null}}catch{}return null}function Ze(n){return async e=>{const r=e.get("logger"),d=n.getConfig().ssoDirect;let o;try{o=me(e.req.query("state"))}catch{return r.warn("OIDC login error: Invalid OAuth2 state"),e.text("Bad request: Invalid OAuth2 state",400)}const h=o.idpId,i=o.source==="mcp"||o.redirectTo&&typeof o.redirectTo=="string"&&o.redirectTo.includes(D.MCP_CALLBACK),u=i?X(typeof o.redirectTo=="string"?o.redirectTo:void 0):null,s=d?.[h];if(!b(s))return r.error("OIDC login error: missing OIDC provider config"),e.text("Forbidden",403);const p=await Z(h,s);if(d&&!p.token_endpoint){const m="Invalid OIDC configuration: token_endpoint is required";return r.error(`OIDC login error: ${m}`),e.text(m,500)}try{const m=p.token_endpoint,g=e.req.query("code"),C=e.req.query("error");if(C)return i&&k.sendMcpAuthorizationFailedMessage([{...M(u),error:`OIDC error: ${C}`,error_details:e.req.query("error_description")||null}]),ye(e,n,{slug:"/"},403,"403OIDC");if(!g){const f="Code is expected but not present";return r.error(`OIDC login error: ${f}`),i&&k.sendMcpAuthorizationFailedMessage([{...M(u),error:f,error_details:null}]),new Response(`Forbidden: ${f}`,{status:403})}const O=typeof o.redirectUri=="string"?o.redirectUri:new URL(w(D.OIDC_CALLBACK),e.req.url).toString(),I=e.get("cookies")?.code_verifier,a=await ce(m,g,O,s,{...s.tokenRequestCustomParams,...I?{code_verifier:I}:{}});if(a.error)return r.error(`Error from OIDC provider: "${a.error}"`),i&&k.sendMcpAuthorizationFailedMessage([{...M(u),error:`Token exchange error: ${a.error}`,error_details:a.error_description||null}]),e.text(`Forbidden: ${a.error_description||a.error}`,403);if(!a?.id_token){const f="No id_token, please, add openid to scopes";return r.error(`OIDC login error: ${f}`),i&&k.sendMcpAuthorizationFailedMessage([{...M(u),error:f,error_details:null}]),new Response(`Forbidden: ${f}`,{status:403})}const{payload:l,header:y}=E.decode(a.id_token),t=y.alg===$.RS256;if(s.audience?.length&&![...N(l.aud||[]),...N(l[H]||[])].some(T=>s.audience?.includes(T))){const T="No valid audience found in id_token";return r.error(`OIDC login error: ${T}`),i&&k.sendMcpAuthorizationFailedMessage([{...M(u),error:T,error_details:null}]),new Response(`Forbidden: ${T}`)}let c=t?a.id_token:await E.sign({...l,idpId:h},U,$.HS256);if(Buffer.byteLength(c)>F){const f=await W(l,h,s.teamsClaimName,{rbacConfig:n.getConfig().access?.rbac,teamsMapping:s.teamsClaimMap});if(!f){const T=`The id_token claims are too large for the session cookie: ${Buffer.byteLength(JSON.stringify(l))} bytes of claims`;return r.error(`OIDC login error: ${T}`),i&&k.sendMcpAuthorizationFailedMessage([{...M(u),error:T,error_details:null}]),e.text(`Forbidden: ${T}`,403)}f.teamsKept<f.teamsTotal&&r.warn(`OIDC login: the "${s.teamsClaimName}" claim is too large for the session cookie size limit; kept ${f.teamsKept} of ${f.teamsTotal} values, with teams from the RBAC configuration first; RBAC ignores the dropped teams: ${JSON.stringify(f.droppedTeams)}`),c=f.token}Ce(l)||r.warn("To display your username, the required 'email' or 'full_profile' scope must be added to the identity provider configuration");const S=s?.tokenExpirationTime?Date.now()+s.tokenExpirationTime*1e3:l.exp*1e3||Date.now()+K*1e3;if(s.introspectEndpoint){const f=await fetch(s.introspectEndpoint,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({access_token:a.access_token})});if(f.ok){const q=(await f.json()).ext?.federatedIdentity;q&&(L(e,_.FEDERATED_ACCESS_TOKEN,q.access_token||"",{path:A()||"/",httpOnly:!1,expires:new Date(S)}),L(e,_.FEDERATED_ID_TOKEN,q.id_token||"",{path:A()||"/",httpOnly:!1,expires:new Date(S)}))}else r.warn(`OIDC introspect error: ${f.statusText}`)}if(L(e,_.AUTHORIZATION,c,{path:A()||"/",httpOnly:!0,expires:new Date(S)}),c!==a.id_token&&Buffer.byteLength(a.id_token)<=F?L(e,_.IDP_ID_TOKEN,a.id_token||"",{path:A()||"/",httpOnly:!0,expires:new Date(S)}):P(e,_.IDP_ID_TOKEN,{path:A()||"/"}),L(e,_.IDP_ACCESS_TOKEN,a.access_token||"",{path:A()||"/",httpOnly:!0,expires:new Date(S)}),a.refresh_token?L(e,_.IDP_REFRESH_TOKEN,a.refresh_token,{path:A()||"/",httpOnly:!0,expires:new Date(S)}):P(e,_.IDP_REFRESH_TOKEN,{path:A()||"/"}),P(e,"code_verifier",{path:A()||"/"}),v(e),i&&o.redirectTo&&typeof o.redirectTo=="string"&&o.redirectTo.includes(D.MCP_CALLBACK)){const T=`${e.req.url.split("?")[0].replace(D.OIDC_CALLBACK,"")}${o.redirectTo}`;return e.newResponse(null,302,{Location:T})}const Y=typeof o.redirectTo=="string"?o.redirectTo:void 0;let Q=z(new URL(Y||"/",e.req.url).pathname);const x=e.newResponse(null,302,{Location:Q});return r.updateContext({email:l.email,subject:l.sub}),r.info("OIDC login successful"),x}catch(m){const g=m instanceof Error?m.message:String(m),C=m instanceof Error?m.stack:String(m);if(r.error(`OIDC login error: ${g}`),i&&k.sendMcpAuthorizationFailedMessage([{...M(u),error:g,error_details:C}]),m.error==="access_denied")return r.info("Access denied"),e.text("Forbidden",403)}const R="Something went wrong";return r.error(`OIDC login error: ${R}`),i&&k.sendMcpAuthorizationFailedMessage([{...M(u),error:R,error_details:null}]),e.text(R,500)}}function Ve(n){return async e=>{const r=e.get("logger"),o=e.get("auth").claims?.idpId,i=n.getConfig().ssoDirect?.[o];if(e.req.method==="POST")return b(i)||(J(e),G(e)),r.info("Logout successful"),e.newResponse(null,200,{});let u;if(b(i)){const s=(await Z(o,i)).end_session_endpoint;if(s){const p=new URL(e.req.url),R=e.req.header("x-forwarded-proto")||p.protocol.slice(0,-1)||"https",m=e.req.header("x-forwarded-host")||p.host,g=`${R}://${m}`,C=V(g),O=C?Le(JSON.stringify({branch:V(g)})):void 0,I=C?`${Oe(g)}/${ie}/logout`:`${g}${w(D.POST_LOGOUT)}`,a=e.get("cookies"),l=a?.[_.AUTHORIZATION],y=a?.[_.IDP_ID_TOKEN]||(_e(l)?l:void 0);u=Ie(s,I,y,O)}}return r.info("Logout successful"),J(e),G(e),e.newResponse(null,302,{Location:u||w("/")})}}function We(n){return async e=>{const r=n.getConfig().access?.logoutReturnUrl,d=r||w("/");return e.newResponse(null,302,{Location:d})}}function Xe(n){return async e=>{const r=e.get("logger"),d=e.req.param("code"),o=j.BH_API_URL,h=(i,u,s)=>i&&u?`${i} ${u.charAt(0)}`:s;try{if(!o)throw new Error("BH_API_URL is not set");const i=n.getConfig().ssoDirect;if(!i||!Object.keys(i).length)return r.warn("Invite no sso configured to handle"),e.redirect(w("/"));const u=await se(`${o}/public-user-invites/${d}`);if(!u.ok)return u.status===404?(r.warn(`Invite ${d} not found redirect to homepage`),e.redirect(w("/"))):(r.error("Invite error",await u.text()),e.redirect(w("/")));const s=await u.json(),p=new URL(w("/invite"),e.req.url);return p.searchParams.set("code",d),p.searchParams.set("org",s.organization.name),p.searchParams.set("invitedBy",h(s.invitedBy.firstName,s.invitedBy.lastName,s.invitedBy.name)),e.newResponse(null,302,{Location:p.toString()})}catch(i){return r.error("Error processing invite",{error:i,inviteCode:d}),e.text(i.message||"Failed to process invite",400)}}}function Ye(n){return async e=>{const r=e.get("logger"),d=n.getConfig().ssoDirect,o=new URL(e.req.url),h=e.req.query("inviteCode"),i=e.req.header("x-forwarded-proto")||o.protocol.slice(0,-1)||"https",u=e.req.header("x-forwarded-host")||o.host,s=`${i}://${u}`;let p=o.searchParams.get("idpId");const R=o.searchParams.get("redirectTo"),m=Object.keys(d||{})[0];p=p||m;const g=o.searchParams.get("mcp_redirect_uri"),C=!!g;if(!d?.[p]){const c="Invalid idpId";if(r.error(`IdP login error: ${c}`),C){const B=X(R||void 0);k.sendMcpAuthorizationFailedMessage([{...M(B),error:c,error_details:null}])}return e.text(`Forbidden: ${c}`,403)}const I=we({localePrefixParam:o.searchParams.get("localePrefix"),l10n:n.getGlobalData()?.l10n}),a=p&&d?await de(p,d[p]):void 0,l={};for(const c of Object.keys(a?.extraParams||{}))l[c]=o.searchParams.get(c)||a?.extraParams?.[c]||void 0;ae(e)&&(l.prompt="login",l.post_logout="1");let y,t={};if(C&&g&&a&&a.type===ee.OIDC){r.info(`Building MCP OAuth login URL with redirect_uri: ${g}`);const c=Te("",{...a,extraParams:l},R,h,{redirectUriOverride:g,sourceOverride:"mcp",branchOverride:void 0,uiLocales:I});y=c.loginUrl,t=c.cookies||{}}else if(a){const c=ue({...a,extraParams:l},s,R,h,I);y=c.loginUrl,t=c.cookies||{}}return Object.keys(t).forEach(c=>{L(e,c,t[c].value,t[c].options)}),r.info(`IdP login initiated for ID '${p}'`),e.newResponse(null,302,{Location:y||new URL(e.req.url).pathname})}}function Qe(n){return async e=>{const r=e.get("logger"),d=await e.req.formData(),o=d.get("SAMLResponse"),h=d.get("RelayState");if(typeof o!="string"||typeof h!="string"){const t="SAMLResponse is required";return r.error(`SAML2 login error: ${t}`),e.text(`Bad request: ${t}`,400)}const i=pe(o),{success:u,uid:s,nameFormat:p,attrs:R,issuerId:m,expiresAt:g}=fe(i),{idpId:C,redirectTo:O}=JSON.parse(h);if(!u){const t="SAML2 assertion is not successful";return r.error(`SAML2 login error: ${t}`),e.text(`Permission denied: ${t}`,401)}if(!g||Math.ceil(Date.now()/1e3)>=g){const t="SAML2 Token Expired";return r.error(`SAML2 login error: ${t}`),e.text(t,401)}const I=n.getConfig().ssoDirect?.[C];if(!I||!le(I)){const t="Cannot find valid IdP";return r.error(`SAML2 login error: ${t}`),e.text(`Permission denied: ${t}`,401)}if(!(I.issuerId&&m&&oe(I.issuerId,m))){const t="IssuerID is misconfigured or untrusted assertions issuer received";return r.error(`SAML2 login error: ${t}`),e.text(`Permission denied: ${t}`,401)}if(!await he(i,I.x509PublicCert)){const t="SAMLResponse signature invalid";return r.error(`SAML2 login error: ${t}`),e.text(t,401)}const l=ge(s,p,R,I.teamsAttributeName??re);if(!l.sub){const t="The provider did not return a valid user identity.";return r.error(`SAML2 login error: ${t}`),e.text(t,400)}if(!l.email){const t="The provider did not return a valid user email.";return r.error(`SAML2 login error: ${t}`),e.text(t,400)}let y=await E.sign({...l,idpId:C},U,$.HS256);if(Buffer.byteLength(y)>F){const t=await W({...l},C,"teams",{rbacConfig:n.getConfig().access?.rbac,teamsMapping:I.teamsAttributeMap});if(!t){const c=`The SAML2 claims are too large for the session cookie: ${Buffer.byteLength(JSON.stringify(l))} bytes of claims`;return r.error(`SAML2 login error: ${c}`),e.text(`Forbidden: ${c}`,403)}t.teamsKept<t.teamsTotal&&r.warn(`SAML2 login: the "teams" claim is too large for the session cookie size limit; kept ${t.teamsKept} of ${t.teamsTotal} values, with teams from the RBAC configuration first; RBAC ignores the dropped teams: ${JSON.stringify(t.droppedTeams)}`),y=t.token}return L(e,_.AUTHORIZATION,y,{path:A()||"/",httpOnly:!0,expires:new Date(g*1e3)}),P(e,_.IDP_REFRESH_TOKEN,{path:A()||"/"}),v(e),r.updateContext({email:l.email,subject:l.sub}),r.info("SAML2 login successful"),e.newResponse(null,302,{Location:O||"/"})}}function xe(n){return async e=>{const r=e.get("logger"),d=new URL(e.req.query("redirectTo")||"/",e.req.url),o=w(z(d.pathname)),h=n.getConfig().ssoDirect,i=Object.entries(h||{}).find(([,O])=>b(O)&&Re(O));if(!(h&&i))return e.newResponse(null,302,{Location:o});const s=e.req.query("token"),p=s&&await Ae(s);if(!p)return e.newResponse(null,302,{Location:o});if(!N(p[H]||[]).some(O=>O===te||O===ne))return e.newResponse(null,302,{Location:o});const g=await E.sign({...p,idpId:i?.at(0)},U,$.HS256),C=Date.now()+K*1e3;return L(e,_.AUTHORIZATION,g,{path:A()||"/",httpOnly:!0,expires:new Date(C),sameSite:"None",secure:!0}),P(e,_.IDP_REFRESH_TOKEN,{path:A()||"/"}),v(e),r.info("Token login successful"),e.newResponse(null,302,{Location:o})}}export{Je as authorizeHandler,Ye as idpLoginHandler,Xe as inviteHandler,Ve as logoutHandler,Ze as oidcCallbackHandler,We as postLogoutHandler,Ge as redoclyLoginCallbackHandler,xe as redoclyTokenLoginHandler,Qe as samlCallbackHandler};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Handler } from 'hono';
|
|
2
2
|
import type { Store } from '../../store';
|
|
3
3
|
import type { RouteDataResolver, StaticAssetReader } from './index';
|
|
4
|
-
|
|
4
|
+
import type { LlmsTxtGenerator } from '../../types';
|
|
5
|
+
export declare function dynamicRouteHandler(store: Store, resolveRouteData: RouteDataResolver, readStaticAsset: StaticAssetReader, llmsTxtGenerator?: LlmsTxtGenerator): Handler;
|
|
5
6
|
//# sourceMappingURL=dynamic-route.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import m from"path";import{REDOCLY_ROUTE_RBAC as
|
|
1
|
+
import m from"path";import{REDOCLY_ROUTE_RBAC as v,REDOCLY_TEAMS_RBAC as B}from"@redocly/config";import{combineUrls as F,withoutPathPrefix as Q,withPathPrefix as ee}from"@redocly/theme/core/utils";import{CACHE_CONTROL_NO_STORE_HEADER_VALUE as z,CACHE_CONTROL_PUBLIC_HTML as te,DEFAULT_IMMUTABLE_CACHE_MAX_AGE as ne,X_REDOCLY_CACHE_CONTROL_HEADER as oe,X_REDOCLY_CACHE_CONTROL_PUBLIC_HTML as re}from"../../constants/common.js";import{removeTrailingSlash as ie}from"../../../utils/url/remove-trailing-slash.js";import{findInIterable as ae}from"../../../utils/collection/find-in-iterable.js";import{sanitizeRedirectPathname as se}from"../../../utils/url/sanitize-redirect-pathname.js";import{envConfig as ce}from"../../config/env-config.js";import{sanitizePath as le}from"../../../utils/path/sanitize-path.js";import{normalizeRouteSlug as me}from"../../../utils/path/normalize-route-slug.js";import{isPathInFolder as ue}from"../../../utils/path/is-path-in-folder.js";import{getLlmsTxtMdPathBySlug as de}from"../../utils/llmstxt/get-llms-txt-md-path-by-slug.js";import{resolveLlmsTxtMd as X}from"../../utils/llmstxt/resolve-llms-txt-md.js";import{removeLeadingSlash as fe}from"../../../utils/url/remove-leading-slash.js";import{processRedirects as ge}from"./helpers/process-redirects.js";import{renderPage as pe,getServerProps as he}from"../../ssr/index.js";import{canAccessAsset as Ce,canAccessResource as Y}from"../../utils/rbac.js";import{handleErrorPageRender as $,handleUnauthorized as k,handleUnauthorizedAsset as N}from"../utils.js";import{DEFAULT_MAX_AGE_FOR_MIME_TYPE as Re,MIME_TYPES as Ae}from"../mime-types.js";import{fileExistsAsync as Ee}from"../../utils/index.js";import{isAiAgentRequest as Le}from"../../utils/ai-agent-detection.js";import{getRedirectRoute as _e}from"../utils/legacy-openapi-redirects.js";import{getContentTypeHeaderValue as G}from"../utils/content-type.js";import{telemetry as we}from"../../../cli/telemetry/index.js";import{telemetry as Te}from"../../telemetry/index.js";function Ke(e,j,V,E){return async n=>{const L=n.get("logger"),r=n.req,a=new URL(r.url),i=Q(le(decodeURIComponent(a.pathname))),_=m.parse(i).ext===".md",w=Le({accept:r.header("accept"),signatureAgent:r.header("signature-agent"),signature:r.header("signature"),signatureInput:r.header("signature-input"),userAgent:r.header("user-agent")}),s=me(i),o=(r.method==="GET"||r.method==="HEAD")&&!_?e.getRouteBySlug(s,{followRedirect:!1})||ae(e.routesBySlug?.values(),t=>t.hasClientRoutes&&(i===t.slug||i.startsWith(t.slug+"/"))):void 0,T=e.getRedirect(s);if(T){const t=ge({redirect:T,reqUrlSearch:a.search});return Te.sendRedirectMessage([{id:s,object:"redirect",uri:`urn:redocly:realm:api:redirect:${s}`,from:s,templateId:t.type.toString()}]),n.newResponse(null,t.type,{Location:t.location})}const g=ce.isProductionEnv?301:302;if(o?.metadata?.type==="openapi"){const t=_e(a.pathname);if(t)return L.info("Legacy OpenAPI docs redirect from "+a.pathname),n.newResponse(null,g,{Location:encodeURI(t)});if(a.pathname.match(/[A-Z]/))return L.warn("Redirect to lowercase route to avoid 404 error"),n.newResponse(null,g,{Location:encodeURI(a.pathname.toLowerCase())})}if(i.endsWith("/")&&i!=="/"){const t=se(new URL(s||"/",n.req.url).pathname);return n.newResponse(null,g,{Location:encodeURI(ee((t==="/"?"/":ie(t))+a.search))})}const{isAuthenticated:u,teams:p,claims:{email:h}}=n.get("auth");if(o&&!Y(o,{isAuthenticated:u,email:h,teams:p},e.config.access?.rbac,e.config.access?.requiresLogin))return u?$(n,e,{slug:o.slug,[B]:o[B],[v]:o[v]},403):k(n,e,o.slug);const d=o&&w?de(o.slug):void 0,P=d?await X(d,e,E):void 0,U=P?.exists??!1;if(o&&(!w||!U)){const t=await j(o),Z=await he(o,n,t,e),{html:x,statusCode:S,error:J}=await pe(o,Z,n,e,we),D=e.config.access?.rbac,H=!e.config.access?.requiresLogin&&(!D||!Object.keys(D).length),q=S>=400||!!J||!!e.compilationErrors?.length,K=H&&!q;let f;return q?f=z:H?f=te:f="private",n.html(x,S,{"Cache-Control":f,...K&&{[oe]:re}})}const C=d&&U?d:i,W=fe(C),c=m.resolve(e.outdir,W);if(!ue(c,e.outdir))return N(n);let l,M;if(_){const t=await X(i,e,E);if(l=t.route,M=t.content,l&&!Y(l,{isAuthenticated:u,email:h,teams:p},e.config.access?.rbac,e.config.access?.requiresLogin))return k(n,e,i)}const b=e.getGlobalConfig("access");if(!Ce(C,b?.rbac||{},b?.requiresLogin||!1,e.getGlobalConfig("directoryPaths"),{isAuthenticated:u,email:h,teams:p}))return N(n);const R=Ae[m.extname(c)]||"text/plain",A=c.match(/assets\/.*\.[a-f0-9]{8,}\..+/)||c.match(/runtime\/chunks\/.*/)?ne:Re[R],y=A?{"Cache-Control":`public, max-age=${A}, immutable`,Expires:new Date(Date.now()+A*1e3).toUTCString()}:{"Cache-Control":z},O=r.query("download")!=null,I=P?.content??M;if(I!==void 0)return n.newResponse(I,200,{"Content-Type":G(R),"Access-Control-Allow-Origin":"*",...y,...l&&{"X-Robots-Tag":"noindex, follow",...e.config.seo?.siteUrl&&{Link:`<${F(e.config.seo.siteUrl,l.slug)}>; rel="canonical"`}},...O&&{"Content-Disposition":`attachment; filename="${m.basename(C)}"`}});if(await Ee(c)){const t=await V(c);return n.newResponse(t,200,{"Content-Type":G(R),"Access-Control-Allow-Origin":"*",...y,...l&&{"X-Robots-Tag":"noindex, follow",...e.config.seo?.siteUrl&&{Link:`<${F(e.config.seo.siteUrl,l.slug)}>; rel="canonical"`}},...O&&{"Content-Disposition":`attachment; filename="${m.basename(c)}"`}})}else return $(n,e,{slug:s},404)}}export{Ke as dynamicRouteHandler};
|
|
@@ -2,12 +2,13 @@ import type { Hono } from 'hono';
|
|
|
2
2
|
import type { ReadStream } from 'fs';
|
|
3
3
|
import type { Store } from '../../store';
|
|
4
4
|
import type { PageStaticData } from '@redocly/config';
|
|
5
|
-
import type { RouteDetails } from '../../types';
|
|
5
|
+
import type { LlmsTxtGenerator, RouteDetails } from '../../types';
|
|
6
6
|
export type RouteDataResolver = (route: RouteDetails) => Promise<PageStaticData>;
|
|
7
7
|
export type StaticAssetReader = (assetPath: string) => Promise<ReadableStream | ReadStream>;
|
|
8
8
|
export type RouteProviders = {
|
|
9
9
|
resolveRouteData: RouteDataResolver;
|
|
10
10
|
readStaticAsset: StaticAssetReader;
|
|
11
|
+
llmsTxtGenerator?: LlmsTxtGenerator;
|
|
11
12
|
};
|
|
12
13
|
export declare function installProdRoutes(router: Hono, store: Store, providers: RouteProviders): void;
|
|
13
14
|
export declare function waitForPluginsLifecycle(store: Store): (_: any, next: any) => Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{serveStatic as
|
|
1
|
+
import{serveStatic as c}from"hono/serve-static";import{withPathPrefix as i,withoutPathPrefix as H}from"@redocly/theme/core/utils";import{ServerRoutes as l}from"../../../constants/api.js";import{LLMS_TXT_FILE_NAME as L,PUBLIC_STATIC_FOLDER as C}from"../../constants/common.js";import{envConfig as I}from"../../config/env-config.js";import{authMiddleware as g}from"../middleware/authMiddleware.js";import{ensureSearchData as h}from"../middleware/ensureSearchData.js";import{dynamicMiddleware as D}from"../middleware/dynamic-middleware/dynamic-middleware.js";import{installRoutes as P}from"../../plugins/dev-onboarding/api/routes/index.js";import{installSkillsRoutes as N}from"./skills/skills-routes.js";import{llmsTxtHandler as M}from"./llms-txt.js";import{authorizeHandler as w,oidcCallbackHandler as B,logoutHandler as E,postLogoutHandler as v,idpLoginHandler as F,redoclyLoginCallbackHandler as G,samlCallbackHandler as U,redoclyTokenLoginHandler as Y,inviteHandler as y}from"./auth.js";import{appDataHandler as K}from"./app-data.js";import{searchFacetsHandler as k,searchHandler as x}from"./search.js";import{dynamicRouteHandler as b}from"./dynamic-route.js";import{pageDataHandler as V,sharedPageDataHandler as q}from"./page-data.js";import{pathPrefixRedirectHandler as X}from"./path-prefix-redirect.js";import{getRoutesByLineHandler as _,resolvePathHandler as S,resolvePathsHandler as $,resolveSlugHandler as f}from"./resolve-route.js";import{feedbackHandler as j}from"./feedback.js";import{loggerMiddleware as z}from"../middleware/loggerMiddleware.js";import{responseHeadersMiddleware as W}from"../middleware/responseHeadersMiddleware.js";import{idleTimeoutMiddleware as Z}from"../middleware/idleTimeoutMiddleware.js";import{otelTracesHandler as u}from"./otel/otel.js";import{healthCheckHandler as J}from"./health.js";import{askAiHandler as Q,aiAssistantEscalationsHandler as aa,aiAssistantFeedbackHandler as ea,AI_ASSISTANT_IDENTITY_STATUS_HEADER as ia}from"./ask-ai.js";import{semanticSearchHandler as la}from"./semantic-search.js";import{replayOauth2RedirectCallbackHandler as ta}from"./replay-oauth2-redirect.js";import{corsProxyHandler as r}from"./cors-proxy.js";import{corsMiddleware as t}from"../middleware/corsMiddleware.js";import{installApiRoutes as ma}from"./api-routes/api-routes.js";import{cookieMiddleware as oa}from"../middleware/cookieMiddleware.js";import{staticContentHandler as da}from"../routes/static-content.js";import{infoHandler as O}from"./info.js";import{catalogHandler as Aa}from"./catalog/catalog.js";import{catalogRelationsHandler as na}from"./catalog/catalog-relations.js";import{bffCatalogHandler as sa}from"./catalog/bff-catalog.js";import{bffCatalogRevisionsHandler as pa}from"./catalog/bff-catalog-revisions.js";import{bffCatalogRelatedEntitiesHandler as Ta}from"./catalog/bff-catalog-related-entities.js";import{catalogAuthMiddleware as m}from"../middleware/catalogAuthMiddleware.js";import{telemetryMiddleware as Ea}from"../middleware/telemetry-middleware.js";import{errorHandler as _a}from"./error.js";import{installMcpRoutes as Sa}from"./mcp-routes/mcp-routes.js";import{jsonValidatorMiddleware as n}from"../middleware/jsonValidatorMiddleware.js";import{otelTracesRequestSchema as fa}from"../../../api-schemas/otel-traces.js";import{searchFacetsRequestSchema as ra}from"../../../api-schemas/search-facets.js";import{searchRequestSchema as Oa}from"../../../api-schemas/search.js";function Te(a,e,o){const{resolveRouteData:s,readStaticAsset:p,llmsTxtGenerator:d}=o;a.use("*",Z()),a.use("*",oa()),a.use("*",D(e)),a.use("*",g(e)),a.use("*",z()),a.use("*",W(e)),a.use("*",Ea()),a.use(i("*"),c({root:`./${C}`,getContent:(A,R)=>da(A,R,e,p),rewriteRequestPath:A=>H(A)})),a.use(i(l.FEEDBACK),t({allowMethods:["POST"]})),a.use(i(l.ASK_AI),t({allowMethods:["POST"],exposeHeaders:[ia]})),a.use(i(l.AI_ASSISTANT_ESCALATIONS),t({allowMethods:["POST"]})),a.use(i(l.AI_ASSISTANT_FEEDBACK),t({allowMethods:["POST"]})),a.use(i(l.SEMANTIC_SEARCH),t({allowMethods:["POST"]})),a.use("*",Ra(e));const T=h(e);a.use(i(l.INFO),O()),I.NEW_CATALOG_ENABLED&&(a.use(i(l.CATALOG_ENTITIES),m({serverOutDir:e.serverOutDir}),Aa(e)),a.use(i(l.CATALOG_ENTITIES_RELATIONS),m({serverOutDir:e.serverOutDir}),na(e)),a.get(i(l.BFF_CATALOG_ENTITIES),m({serverOutDir:e.serverOutDir,protectReadMethods:!1}),sa(e)),a.get(i(l.BFF_CATALOG_RELATED_ENTITIES),m({serverOutDir:e.serverOutDir,protectReadMethods:!1}),Ta(e)),a.get(i(l.BFF_CATALOG_REVISIONS),m({serverOutDir:e.serverOutDir,protectReadMethods:!1}),pa(e))),a.get(i(l.SHARED_PAGE_DATA),q(e)),a.get(i(l.PAGE_DATA),V(e,s)),a.get(i(l.APP_DATA),K(e)),a.post(i(l.SEARCH),T,n(Oa),x(e)),a.post(i(l.SEARCH_FACETS),T,n(ra),k(e)),a.post(i(l.AUTHORIZATION),w),a.post(i(l.LOGOUT),E(e)),a.get(i(l.LOGOUT),E(e)),a.get(i(l.POST_LOGOUT),v(e)),a.get(i(l.OIDC_CALLBACK),B(e)),a.get(i(l.REDOCLY_TOKEN_LOGIN),Y(e)),a.get(i(l.REDOCLY_LOGIN_CALLBACK),G()),a.get(i(l.IDP_LOGIN),F(e)),a.post(i(l.SAML_CALLBACK),U(e)),a.get(i(l.INVITE),y(e)),a.get(i(l.HEALTH),J),Sa(a,e),P(a,e),N(a,e),a.all(i(l.CORS_PROXY),r(e)),a.all(i(`${l.CORS_PROXY}/*`),r(e)),ma(a,e),a.post(i(l.FEEDBACK),j(e)),a.post(i(l.RESOLVE_ROUTE_BY_PATH),S(e)),a.post(i(l.RESOLVE_ROUTES_BY_PATHS),$(e)),a.post(i(l.RESOLVE_ROUTE_BY_SLUG),f(e)),a.post(i(l.ASK_AI),Q(e)),a.post(i(l.AI_ASSISTANT_ESCALATIONS),aa(e)),a.post(i(l.AI_ASSISTANT_FEEDBACK),ea(e)),a.post(i(l.SEMANTIC_SEARCH),la(e)),a.get(i(l.GET_ROUTES_BY_LINE),_(e)),a.post(i(l.OTEL_TRACES),n(fa),u),a.get(i(l.REPLAY_OAUTH2_CALLBACK),ta),d&&a.get(i(`/${L}`),M(d)),a.all(i("/*"),b(e,s,p,d)),a.get("*",X),a.onError(_a)}function Ra(a){return async(e,o)=>{await a.waitForPluginsLifecycle(),await o()}}function Ee(a,e){a.get(i(l.INFO),O()),a.post(i(l.RESOLVE_ROUTE_BY_PATH),S(e)),a.post(i(l.RESOLVE_ROUTE_BY_SLUG),f(e)),a.get(i(l.GET_ROUTES_BY_LINE),_(e))}export{Ee as installDevRoutes,Te as installProdRoutes,Ra as waitForPluginsLifecycle};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{CACHE_CONTROL_NO_STORE_HEADER_VALUE as r,LLMS_TXT_FILE_NAME as i}from"../../constants/common.js";import{MIME_TYPES as l}from"../mime-types.js";import{getContentTypeHeaderValue as a}from"../utils/content-type.js";function E(n){return async(t,o)=>{const e=await n.getLlmsTxt();return e===void 0?o():t.newResponse(e,200,{"Content-Type":a(l[".txt"]),"Access-Control-Allow-Origin":"*","Cache-Control":r,...t.req.query("download")!=null&&{"Content-Disposition":`attachment; filename="${i}"`}})}}export{E as llmsTxtHandler};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@redocly/reef",
|
|
3
|
-
"version": "0.137.0-next.
|
|
3
|
+
"version": "0.137.0-next.9",
|
|
4
4
|
"description": "",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -33,7 +33,13 @@
|
|
|
33
33
|
"@opentelemetry/sdk-trace-web": "2.8.0",
|
|
34
34
|
"@opentelemetry/semantic-conventions": "1.40.0",
|
|
35
35
|
"@redocly/ajv": "8.18.0",
|
|
36
|
-
"@redocly/
|
|
36
|
+
"@redocly/api-docs": "0.2.0-next.9",
|
|
37
|
+
"@redocly/config": "0.56.0",
|
|
38
|
+
"@redocly/openapi-core": "2.51.2",
|
|
39
|
+
"@redocly/portal-legacy-ui": "0.19.0",
|
|
40
|
+
"@redocly/portal-plugin-mock-server": "0.22.0-next.7",
|
|
41
|
+
"@redocly/realm-asyncapi-sdk": "0.15.0-next.3",
|
|
42
|
+
"@redocly/theme": "0.69.0-next.8",
|
|
37
43
|
"@shikijs/transformers": "3.21.0",
|
|
38
44
|
"@tanstack/react-query": "5.62.3",
|
|
39
45
|
"@tanstack/react-table": "8.21.3",
|
|
@@ -64,7 +70,7 @@
|
|
|
64
70
|
"mri": "1.2.0",
|
|
65
71
|
"nanoid": "5.1.16",
|
|
66
72
|
"nprogress": "0.2.0",
|
|
67
|
-
"openapi-sampler": "^1.7.
|
|
73
|
+
"openapi-sampler": "^1.7.5",
|
|
68
74
|
"os-browserify": "0.3.0",
|
|
69
75
|
"path-browserify": "1.0.1",
|
|
70
76
|
"picomatch": "2.3.2",
|
|
@@ -92,13 +98,7 @@
|
|
|
92
98
|
"xml-crypto": "6.1.0",
|
|
93
99
|
"xpath": "0.0.34",
|
|
94
100
|
"yaml-ast-parser": "0.0.43",
|
|
95
|
-
"zod": "^3.25.76"
|
|
96
|
-
"@redocly/api-docs": "0.2.0-next.7",
|
|
97
|
-
"@redocly/config": "0.55.0",
|
|
98
|
-
"@redocly/portal-legacy-ui": "0.19.0",
|
|
99
|
-
"@redocly/portal-plugin-mock-server": "0.22.0-next.6",
|
|
100
|
-
"@redocly/realm-asyncapi-sdk": "0.15.0-next.3",
|
|
101
|
-
"@redocly/theme": "0.69.0-next.6"
|
|
101
|
+
"zod": "^3.25.76"
|
|
102
102
|
},
|
|
103
103
|
"peerDependencies": {
|
|
104
104
|
"react": "^19.2.7",
|