@redocly/reef 0.132.0-next.1 → 0.132.0-next.2
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 +39 -0
- package/dist/client/App.js +1 -1
- package/dist/client/TestProvider.js +1 -1
- package/dist/client/app/hooks/catalog/useCatalogSort.d.ts +3 -4
- package/dist/client/app/hooks/catalog/useFetchCatalogEntities.js +1 -1
- package/dist/client/app/hooks/catalog/useFetchCatalogEntitiesRelations.js +1 -1
- package/dist/client/app/hooks/index.d.ts +1 -0
- package/dist/client/app/hooks/index.js +1 -1
- package/dist/client/app/hooks/markdown/useMarkdocRenderer.d.ts +3 -0
- package/dist/client/app/hooks/markdown/useMarkdocRenderer.js +1 -0
- package/dist/client/app/hooks/useBanner.d.ts +3 -5
- package/dist/client/app/hooks/useBanner.js +1 -1
- package/dist/client/app/hooks/utils/match-banner-target.d.ts +2 -2
- package/dist/client/app/hooks/utils/match-banner-target.js +1 -1
- package/dist/client/app/utils/loadAndNavigate.js +1 -1
- package/dist/client/app/utils/scroll-to-anchor.d.ts +3 -0
- package/dist/client/app/utils/scroll-to-anchor.js +1 -0
- package/dist/client/providers/theme/ThemeDataProvider.js +1 -1
- package/dist/constants/common.js +1 -1
- package/dist/server/config/env-schema.d.ts +3 -0
- package/dist/server/config/env-schemas/auth.d.ts +3 -0
- package/dist/server/config/env-schemas/auth.js +1 -1
- package/dist/server/plugins/arazzo-docs/index.js +1 -1
- package/dist/server/plugins/asyncapi-docs/index.js +1 -1
- package/dist/server/plugins/asyncapi-docs/search/get-ai-search-documents.js +3 -3
- package/dist/server/plugins/catalog-entities/database/mappers/create-bff-related-entity.js +1 -1
- package/dist/server/plugins/catalog-entities/database/mappers/field-transformations.d.ts +2 -2
- package/dist/server/plugins/catalog-entities/database/mappers/field-transformations.js +1 -1
- package/dist/server/plugins/catalog-entities/database/repositories/utils/create-merged-entity-fields-for-select.d.ts +1 -0
- package/dist/server/plugins/catalog-entities/database/repositories/utils/create-merged-entity-fields-for-select.js +8 -8
- package/dist/server/plugins/catalog-entities/database/repositories/utils.d.ts +4 -0
- package/dist/server/plugins/catalog-entities/database/repositories/utils.js +1 -1
- package/dist/server/plugins/catalog-entities/extensions/extractors/api-description/arazzo-entities-extractor.js +1 -1
- package/dist/server/plugins/catalog-entities/extensions/extractors/api-description/asyncapi-entities-extractor.js +1 -1
- package/dist/server/plugins/catalog-entities/extensions/extractors/api-description/base.d.ts +13 -1
- package/dist/server/plugins/catalog-entities/extensions/extractors/api-description/base.js +1 -1
- package/dist/server/plugins/catalog-entities/extensions/extractors/api-description/graphql-entities-extractor.js +2 -2
- package/dist/server/plugins/catalog-entities/extensions/extractors/api-description/openapi-entities-extractor.js +1 -1
- package/dist/server/plugins/catalog-entities/get-server-props.js +1 -1
- package/dist/server/plugins/catalog-entities/plugin.js +1 -1
- package/dist/server/plugins/catalog-entities/schemas/database-schemas.d.ts +6 -6
- package/dist/server/plugins/catalog-entities/schemas/database-schemas.js +1 -1
- package/dist/server/plugins/config-parser/index.js +1 -1
- package/dist/server/plugins/config-parser/loaders/redocly-config-loader.js +1 -1
- package/dist/server/plugins/config-parser/loaders/utils/read-and-validate-config.d.ts +1 -0
- package/dist/server/plugins/config-parser/loaders/utils/read-and-validate-config.js +1 -1
- package/dist/server/plugins/default-theme/index.js +1 -1
- package/dist/server/plugins/dev-onboarding/index.js +1 -1
- package/dist/server/plugins/enforce-login/index.d.ts +3 -0
- package/dist/server/plugins/enforce-login/index.js +1 -0
- package/dist/server/plugins/graphql-docs/spec-download.api.js +1 -1
- package/dist/server/plugins/lifecycle.js +2 -2
- package/dist/server/plugins/markdown/compiler.d.ts +1 -1
- package/dist/server/plugins/markdown/compiler.js +1 -1
- package/dist/server/plugins/markdown/get-server-props.js +1 -1
- package/dist/server/plugins/markdown/index.js +1 -1
- package/dist/server/plugins/markdown/markdoc/partials.js +1 -1
- package/dist/server/plugins/markdown/markdown-static-data-loader.js +1 -1
- package/dist/server/plugins/markdown/search/get-ai-search-documents.js +10 -10
- package/dist/server/plugins/mcp/handlers/docs-mcp-handler.js +1 -1
- package/dist/server/plugins/openapi-docs/index.js +1 -1
- package/dist/server/plugins/openapi-docs/load-definition.js +3 -3
- package/dist/server/plugins/openapi-docs/search/get-ai-search-documents.js +32 -32
- package/dist/server/plugins/openapi-docs/spec-download.api.js +1 -1
- package/dist/server/plugins/scorecard-classic/compute-scorecard.js +4 -4
- package/dist/server/plugins/scorecard-classic/loaders/scorecard-config.js +1 -1
- package/dist/server/plugins/scorecard-classic/loaders/scorecard.js +1 -1
- package/dist/server/plugins/search/ai-indexer/prepare-semantic-documents.js +1 -1
- package/dist/server/plugins/search/documents/search-documents.js +1 -1
- package/dist/server/plugins/search/index.js +1 -1
- package/dist/server/plugins/search/llmstxt/index.d.ts +0 -1
- package/dist/server/plugins/search/llmstxt/index.js +4 -4
- package/dist/server/plugins/sso/index.js +1 -1
- package/dist/server/ssr/index.js +1 -1
- package/dist/server/store.d.ts +2 -3
- package/dist/server/store.js +1 -1
- package/dist/server/tools/notifiers/terminal-manager.js +5 -5
- package/dist/server/types/plugins/common.d.ts +4 -4
- package/dist/server/types/plugins/markdown.d.ts +7 -1
- package/dist/server/utils/llmstxt/get-llms-txt-md-path-by-slug.d.ts +19 -0
- package/dist/server/utils/llmstxt/get-llms-txt-md-path-by-slug.js +1 -0
- package/dist/server/utils/rbac/is-rbac-scope-items.d.ts +3 -0
- package/dist/server/utils/rbac/is-rbac-scope-items.js +1 -0
- package/dist/server/utils/rbac.js +1 -1
- package/dist/server/web-server/routes/api-routes/api-routes.js +1 -1
- package/dist/server/web-server/routes/app-data.js +1 -1
- package/dist/server/web-server/routes/ask-ai.js +1 -1
- package/dist/server/web-server/routes/auth.d.ts +2 -1
- package/dist/server/web-server/routes/auth.js +1 -1
- package/dist/server/web-server/routes/catalog/bff-catalog-related-entities.js +1 -1
- package/dist/server/web-server/routes/catalog/bff-catalog.js +1 -1
- package/dist/server/web-server/routes/catalog/helpers/has-access-to-entity.js +1 -1
- package/dist/server/web-server/routes/dynamic-route.js +1 -1
- package/dist/server/web-server/routes/feedback.js +1 -1
- package/dist/server/web-server/routes/helpers/get-rbac-restrictions-data-for-catalog.js +1 -1
- package/dist/server/web-server/routes/page-data.js +1 -1
- package/dist/server/web-server/routes/search.js +1 -1
- package/dist/server/web-server/routes/static-content.js +1 -1
- package/package.json +10 -10
- package/dist/server/web-server/routes/helpers/get-md-asset-pathname.d.ts +0 -2
- package/dist/server/web-server/routes/helpers/get-md-asset-pathname.js +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
import{DEFAULT_SSO_IDP_TITLE as
|
|
1
|
+
import{DEFAULT_SSO_IDP_TITLE as u}from"../../../constants/common.js";import{envConfig as a}from"../../config/env-config.js";import{telemetryTraceStep as g}from"../../../cli/telemetry/helpers/trace-step.js";const y="https://auth.cloud.redocly.com/oidc/.well-known/openid-configuration",C="https://auth.cloud.redocly.com/api/sso/oidc/introspect";async function I(O){return{id:"sso",async processContent(t){await g("build.plugin.sso",async l=>{const s=t.getConfig(),o=s.access;if(l?.setAttribute("config",`{"ssoDirect": ${JSON.stringify(s.ssoDirect||{})}}, {"sso": ${JSON.stringify(o?.sso||{})}}`),s.ssoDirect&&typeof s.ssoDirect=="object"&&Object.keys(s.ssoDirect).length!==0||o?.sso&&Array.isArray(o.sso)&&!o.sso.length)return;const p=!!(o?.rbac&&typeof o.rbac=="object"&&Object.keys(o.rbac).length!==0),d=o?.requiresLogin;if(!p&&!d)return;let n=y,c=a.REDOCLY_OAUTH_USE_INTROSPECT?C:"";const e=o?.residency;if(e){const r=e.endsWith("/")?e.slice(0,-1):e;n=`${r.replace("app.","auth.")}/oidc/.well-known/openid-configuration`,c=a.REDOCLY_OAUTH_USE_INTROSPECT?`${r}/api/sso/oidc/introspect`:""}let i="AUTO";o?.sso&&(Array.isArray(o.sso)?i=o.sso.join(","):i=o.sso);const f={oidc:{title:u,type:"OIDC",configurationUrl:n,clientId:"{{ process.env.OAUTH_CLIENT_ID }}",clientSecret:"{{ process.env.OAUTH_CLIENT_SECRET }}",teamsClaimName:"https://redocly.com/sso/teams",scopes:["openid"],authorizationRequestCustomParams:{login_hint:"{{ process.env.ORGANIZATION_ID }}",login_type:i,prompt:"login"},audience:"{{ process.env.ORGANIZATION_ID }}",introspectEndpoint:c}};t.setGlobalConfig({ssoDirect:f})})},async afterRoutesCreated(t){}}}export{I as ssoPlugin};
|
package/dist/server/ssr/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{withPathPrefix as O}from"@redocly/theme/core/utils";import{SSR_RENDER_MODE as y}from"../constants/common.js";import{logger as b}from"../tools/notifiers/logger.js";import{canAccessResource as L,filterDataByAccessDeep as d,isResourcePubliclyAccessible as _}from"../utils/rbac.js";import{readSharedData as x}from"../utils/index.js";import{render as C}from"./render.js";import{getServerProps as T}from"./server-side-props/get-server-props.js";import{ssrWorkers as $}from"../workers/ssr-worker-pool.js";import{SSR_WORKER_KEY as j}from"../workers/ssr-worker-pool.js";async function J(e,s,a,r,o,
|
|
1
|
+
import{withPathPrefix as O}from"@redocly/theme/core/utils";import{SSR_RENDER_MODE as y}from"../constants/common.js";import{logger as b}from"../tools/notifiers/logger.js";import{canAccessResource as L,filterDataByAccessDeep as d,isResourcePubliclyAccessible as _}from"../utils/rbac.js";import{readSharedData as x}from"../utils/index.js";import{render as C}from"./render.js";import{getServerProps as T}from"./server-side-props/get-server-props.js";import{ssrWorkers as $}from"../workers/ssr-worker-pool.js";import{SSR_WORKER_KEY as j}from"../workers/ssr-worker-pool.js";async function J(e,s,a,r,o,c=!1){const w=b.startTiming(),E=r.routesSharedData.get(e.slug)||{},S=s.sharedDataIds||{},m={...E,...S},{isAuthenticated:g,teams:u,claims:{name:q,picture:I,email:f}}=a?.get("auth")||{claims:{}},t={isAuthenticated:g,email:f,teams:u},R=Object.fromEntries(await Promise.all(Object.entries(m).map(async([H,D])=>[D,await x(D,r.outdir)]))),P=d(R,t,r.config.access?.rbac,r.config.access?.requiresLogin),v=d(r.globalData,t,r.config.access?.rbac,r.config.access?.requiresLogin),p=L(e,t,r.config.access?.rbac,r.config.access?.requiresLogin),A=!!r.compilationErrors?.length?{templateId:"compilation-error",props:{compilationErrors:r.compilationErrors},sharedDataIds:{}}:null,h={page:{templateId:e.templateId,isPublic:_(e,r.config),slug:O(e.slug),versions:d(e.versions,t,r.config.access?.rbac,r.config.access?.requiresLogin),props:s,sharedDataIds:p?m:{},product:e.product,request:{search:a?.req.raw.context.url?.search||"",url:a?.req.raw.context.url?.href||""},userInfo:{isAuthenticated:g,name:q,picture:I,email:f,teams:u},...A},store:{globalData:v,config:r.config,ssr:r.ssr,hasSitemap:r.hasSitemap},sharedData:p?P:{},serverOutDir:r.serverOutDir,outdir:r.outdir,ssrHref:k(a),userAgent:a?.req.raw.headers.get("user-agent")||"",telemetry:o,omitSuspense:c};let i,n,l;return y==="worker"?{html:i,statusCode:n,error:l}=await $.exec(j,[h]):{html:i,statusCode:n,error:l}=await C(h),b.verboseTime(w,`Page rendered ${e.slug}`),{html:i,props:s,statusCode:n,error:l}}function k(e){const s=e?.req.raw.url;if(!s)return"";const a=new URL(s),r=e?.req.raw.headers,o=r?.get("x-forwarded-proto")||a.protocol.replace(":",""),c=r?.get("x-forwarded-host")||a.host;return`${o}://${c}`}export{T as getServerProps,J as renderPage};
|
package/dist/server/store.d.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import type { Node } from '@markdoc/markdoc';
|
|
2
2
|
import type { JSX } from 'react';
|
|
3
3
|
import type { CommonError, GlobalData } from '../types/index.js';
|
|
4
|
-
import type { WildcardRedirectsTree } from './types';
|
|
5
|
-
import type { MiddlewareDetails, PageRouteInit, PageRouteDetails, RouteDetails, LifecycleContext, MarkdownParseInput, ApiRoute, MarkdocDeps } from './types';
|
|
4
|
+
import type { MiddlewareDetails, PageRouteInit, PageRouteDetails, RouteDetails, LifecycleContext, ApiRoute, ParseMarkdocOpts, WildcardRedirectsTree } from './types';
|
|
6
5
|
import type { RedoclyConfig, RedirectConfig, CompilationError, PageStaticData } from '@redocly/config';
|
|
7
6
|
import type { SearchFacet } from '@redocly/theme/core/types';
|
|
8
7
|
import type { BundledDefinition as OpenApiBundledDefinition } from './plugins/openapi-docs/load-definition.js';
|
|
@@ -119,7 +118,7 @@ export declare class Store {
|
|
|
119
118
|
setGlobalData: (data: GlobalData) => void;
|
|
120
119
|
getGlobalData: () => GlobalData;
|
|
121
120
|
getKv: () => Promise<KvService>;
|
|
122
|
-
parseMarkdoc: (input
|
|
121
|
+
parseMarkdoc: ({ input, context, deps, resource }: ParseMarkdocOpts) => Promise<{
|
|
123
122
|
info: {
|
|
124
123
|
sharedDataDeps?: Set<string>;
|
|
125
124
|
dynamicMarkdocComponents?: string[];
|
package/dist/server/store.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import b from"@markdoc/markdoc";import{getPathnameForLocale as A}from"@redocly/theme/core/utils";import{DEFAULT_LOCALE_PLACEHOLDER as u}from"../constants/common.js";import{DEFAULT_TITLE as C}from"./constants/common.js";import{GATED_MARKDOC_TAGS as D}from"./constants/entitlements.js";import{isObject as O}from"../utils/guards/is-object.js";import{mapObject as T}from"../utils/object/map-object.js";import{getValueDeep as S}from"../utils/object/get-value-deep.js";import{removeTrailingSlash as M}from"../utils/url/remove-trailing-slash.js";import{normalizeRouteSlug as f}from"../utils/path/normalize-route-slug.js";import{isLocalLink as L}from"../utils/path/is-local-link.js";import{reporter as w}from"./tools/notifiers/reporter.js";import{logger as p}from"./tools/notifiers/logger.js";import{sha1 as k}from"./utils/crypto/sha1.js";import{writeEnvVariable as _}from"./utils/envs/write-env-variable.js";import{envConfig as F}from"./config/env-config.js";import{KvService as G}from"./persistence/kv/services/kv-service.js";import{writeSharedData as B}from"./utils/index.js";import{renderComponents as I}from"./ssr/render.js";import{readStaticData as N,writeStaticData as V}from"./utils/static-data.js";import{parseAndResolveMarkdoc as j}from"./plugins/markdown/compiler.js";import{getMarkdocOptions as H}from"./plugins/markdown/markdoc/markdoc-options.js";import{EntitlementsProvider as y}from"./entitlements/entitlements-provider.js";import{isL10nPath as K}from"./fs/utils/is-l10n-path.js";import{resolveMetadataGlobs as U}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{addWildcardRedirectToTree as q}from"./utils/redirects/add-wildcard-redirect-to-tree.js";import{telemetryTraceStep as $}from"../cli/telemetry/helpers/trace-step.js";const R={routesBySlug:"map",apiRoutes:"object",middleware:"object",routesByFsPath:"map",routesSharedData:"map",globalData:"object",config:"object",ssr:"object",searchFacets:"map",routesPartials:"map"},g="markdown/partials",W="markdown/partials-deps",v="PLAN_GATES",z=["OAUTH_CLIENT_ID","OAUTH_CLIENT_SECRET","ORGANIZATION_SLUG","ORGANIZATION_ID","ORG_ID"],At="userDefinedApiFunctions";class E{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;serverPropsGetters=new Map;pagePropsGetters=new Map;listeners=new Map;globalData={};#s=void 0;config={configFilePath:"",redirects:{},wildcardRedirectsTree:{},rbac:{},directoryPermissions:{},devLogin:!1,ssoDirect:{}};#r;serverMode;serverOutDir;outdir;buildRevision=0;hasSitemap=!1;compilationErrors=[];#a;userCodeReady;#o=Promise.resolve();#i;#n=Promise.resolve();#c;#e=new Map;constructor({outdir:t,contentDir:e,serverMode:s=!1,serverOutDir:r}){this.#r=e,this.outdir=t,this.serverMode=s,this.serverOutDir=r,this.userCodeReady=new Promise(a=>{this.#a=a})}on(t,e){const s=this.listeners.get(t);s?s.add(e):this.listeners.set(t,new Set([e]))}queueEvent=(t,e,...s)=>{this.#e.set(t+String(e),[t,e,...s])};runListeners=(t,e,...s)=>{for(const r of this.listeners.get(t)||new Set)e?r(e,...s):r(...s)};startPluginsRun(){this.clear(),this.#o=new Promise(t=>{this.#i=t})}waitForPluginsLifecycle(){return Promise.all([this.#o,this.#n])}finishPluginsRun(){this.#i?.();for(const t of this.#e.values())this.runListeners(...t);this.#e.clear()}startEsbuildRun(){this.#n=new Promise(t=>{this.#c=t})}finishEsbuildRun(){this.#c?.()}get contentDir(){if(this.serverMode)throw new Error("contentDir should not be used in server mode");return this.#r}markUserCodeReady(){this.#a?.(!0)}async reloadMarkdocOptions(){await $("build.reload_markdoc_options",async()=>{const t=y.instance(),e=await H(this.serverOutDir),s=Object.fromEntries(Object.entries(e.tags).filter(([r])=>D[r]!=null?t.canAccessFeature(D[r]):!0));this.#s={...e,tags:s}})}get markdocOptions(){return{...this.#s,partials:this.getGlobalConfig(g),themeConfig:this.config.markdown}}setGlobalData=t=>{const e=this.globalData,s={...this.globalData,...t};this.globalData=s,JSON.stringify(s)!==JSON.stringify(e)&&this.queueEvent("global-data-updated",void 0,s)};getGlobalData=()=>this.globalData;getKv=async()=>G.getInstance({baseDbDir:this.serverOutDir});parseMarkdoc=async(t,e,s)=>{const{data:{info:r,ast:a},compoundHash:n}=await j(t,this.markdocOptions,{actions:this,context:e});for(const i of r.sharedDataDeps||[]){for(const o of s?.routeSlugs||[])this.addRouteSharedData(o,i,i);for(const o of s?.sharedDataIds||[]){const c=this.sharedDataDeps.get(o)||new Set;c.add(i),this.sharedDataDeps.set(o,c)}}for(const i of r.dynamicMarkdocComponents||[]){for(const o of s?.routeSlugs||[]){const c=this.routesDynamicComponents.get(o)||new Set;c.add(i),this.routesDynamicComponents.set(o,c)}for(const o of s?.sharedDataIds||[]){const c=this.sharedDataMarkdocComponents.get(o)||new Set;c.add(i),this.sharedDataMarkdocComponents.set(o,c)}}if(s?.routeSlugs&&r.partials?.length)for(const i of s.routeSlugs){const o=this.routesPartials.get(i)||[];for(const c of r.partials)o.includes(c)||o.push(c);this.routesPartials.set(i,o)}return{info:r,ast:a,compoundHash:n}};async loadOpenApiDefinitions(t){return(await t.cache.load(".","load-oas-docs")).data}async loadAsyncApiDefinitions(t){return(await t.cache.load(".","asyncapi-docs")).data}setSearchEngine(t){this.searchEngine=t}setSearchFacets=t=>{this.searchFacets=t};setGlobalConfig=t=>{const e=Object.keys(t);for(const n of e)for(const i in this.replacedEnvVars)if(i===n||i.startsWith(`${n}:`)){const o=i.split(":"),{error:c,value:l}=S(t,o);(c||l!==this.replacedEnvVars[i].replaced)&&delete this.replacedEnvVars[i]}const{resolvedObj:s,unsetEnvVars:r,replacedValues:a}=J(t);for(const n of r)this.unsetEnvVars.add(n);Object.assign(this.replacedEnvVars,a),Object.assign(this.config,s)};getConfig=()=>this.config;getGlobalConfig=t=>this.config[t];getSearchFacets=()=>this.searchFacets;addRedirect=(t,e)=>{if(!y.instance().canAccessFeature("redirects")&&t!=="/")return;this.config.redirects||(this.config.redirects={});const a=f(t).toLowerCase();this.config.redirects[a]=e,a.endsWith("*")&&q(this.config.wildcardRedirectsTree,a)};getRedirect=t=>{const e=f(t).toLowerCase();return x(e,this.config.redirects,this.config.wildcardRedirectsTree)};createSharedData=async(t,e,s)=>{if(s&&this.#t[t]===s)return t;const r=JSON.stringify(e),a=s??k(r);return this.#t[t]===a||(this.#t[t]=a,await B(t,r,this.outdir),this.queueEvent("shared-data-updated",t)),t};addRouteSharedData=(t,e,s)=>{const r=M(t),a=this.routesSharedData.get(r)||{};a[e]=s,this.routesSharedData.set(r,a),p.verbose(`Adding shared data to ${t}, ${e}, ${s}`)};getRouteSharedDataByFsPath=t=>{const e=this.routesByFsPath.get(t);return e?this.routesSharedData.get(e)||{}:{}};getPartialsForRoute=t=>{const e=this.getGlobalConfig(g)||{},s=this.routesPartials.get(t);if(!s||s.length===0)return{};const r=this.getGlobalConfig(W)||{},a=new Set(s),n=Array.from(s);for(let o=0;o<n.length;o++){const c=n[o],l=r[c]?.partials??[];for(const d of l)a.has(d)||(a.add(d),n.push(d))}const i={};for(const o of a)e[o]&&(i[o]=e[o]);return i};addRoute=t=>{const s={...U(t.fsPath,this.config.metadataGlobs),...t.metadata||{}};this.newRoutes.push({...t,metadata:s}),p.verbose("Created route %s",t.slug)};addRouteSharedDataToAllLocales=(t,e,s)=>{const r=[u,...this.lifecycleContext?.fs.localeFolders||[]].map(a=>({code:a,name:a}));for(const a of r){const n=A(t,u,a.code,r);this.addRouteSharedData(n,e,s)}};addApiRoute=t=>{this.apiRoutes.push(t),p.verbose("Created API route %s",t.slug)};addMiddleware=t=>{this.middleware.push(t),p.verbose("Created middleware %s",t.id)};getRouteByFsPath=t=>{const e=this.routesByFsPath.get(t);return e?this.getRouteBySlug(e):void 0};getRouteBySlug=(t,e={})=>{const{followRedirect:s=!0}=e,r=this.getRedirect(t);return s&&r?this.routesBySlug.get(f(r.to)):this.routesBySlug.get(t)};slugHasRouteOrRedirect=t=>{if(this.routesBySlug.has(t))return!0;const e=this.getRedirect(t);if(!e)return!1;if(!L(e.to))return!0;const s=f(e.to);return this.routesBySlug.has(s)};getRoutesByTemplateId=t=>this.newRoutes.filter(e=>e.templateId===t);getAllRoutesForLocale=(t=u)=>{const e=Array.from(this.routesBySlug.values()),s=t.toLowerCase();return e.filter(r=>t===u?!K(r.fsPath):r.slug.startsWith(`/${s}`))};getAllRoutes=()=>Array.from(this.routesBySlug.values());getAllApiRoutes=()=>this.apiRoutes;getAllMiddleware=()=>this.middleware;getTemplate=t=>this.templates.get(t);getRequestHandler=t=>this.apiRoutesRequestHandlers.get(t);createTemplate=(t,e)=>(this.templates.set(t,e),t);addBrowserPlugin=t=>{this.browserPlugins.add(t)};createRequestHandler=(t,e)=>(this.apiRoutesRequestHandlers.set(t,e),t);registerServerPropsGetter=(t,e)=>(this.serverPropsGetters.set(t,e),t);registerPagePropsGetter=(t,e)=>{this.pagePropsGetters.set(t,e)};async writeRouteStaticData(t,e){const s=await this.resolveRouteStaticData(t,e,!1);s&&V(t.slug,s,this.outdir)}async resolveRouteStaticData(t,e,s){if(this.serverMode)return N(t.slug,this.outdir);const r={...this,contentDir:this.contentDir,parseMarkdoc:(l,d)=>this.parseMarkdoc(l,d,{routeSlugs:[t.slug]})},a=await t.getStaticData?.(t,r)||{},n=new Set(this.routesDynamicComponents.get(t.slug)),i=this.routesSharedData.get(t.slug)||{};for(const l of Object.values(i)){const d=this.sharedDataMarkdocComponents.get(l);d&&d.forEach(h=>n.add(h));const m=this.sharedDataDeps.get(l);m&&m.forEach(h=>this.addRouteSharedData(t.slug,h,h))}const o=this.getGlobalConfig("seo"),c=a?.frontmatter||{};return{...a,frontmatter:{...c,seo:{...c?.seo,title:c?.seo?.title||await t.getNavText?.()}},props:{...a.props,dynamicMarkdocComponents:Array.from(n),metadata:{...a?.props?.metadata,...t.metadata},seo:{title:C,...o,...a.props?.seo},compilationErrors:this.compilationErrors},lastModified:s||!t.fsPath?null:await this.lifecycleContext?.fs.getLastModified(t.fsPath)}}addSsrComponents(t,e){if(!t?.length)return;const s=typeof t[0]=="string"?t.join(""):I(t);s&&(e==="head"?this.ssr.headTags.push(s):e==="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.config.redirects={},this.config.wildcardRedirectsTree={},this.config.directoryPermissions={},this.ssr={preBodyTags:[],postBodyTags:[],headTags:[]}};async toJson(){const t=[];for(const[s,r]of Object.entries(R))switch(r){case"map":const a=Array.from(this[s].entries());t.push([s,a]);break;case"object":s==="config"&&t.push([s,await this.getConfigWithEnvPlaceholders()]),t.push([s,this[s]]);break;default:throw new Error("Invalid format")}const e=Object.fromEntries(t);return e[v]=F.PLAN_GATES,e}static fromJson(t,e){const s=new E(e);for(const[a,n]of Object.entries(R))switch(n){case"map":s[a]=new Map(t[a]);break;case"object":if(a==="config"){s.setGlobalConfig(t[a]);break}s[a]=t[a];break;default:throw new Error("Invalid format")}s.config[g]=Y(s.config[g]||{});const r=t[v];return r&&_("PLAN_GATES",r),s}async getConfigWithEnvPlaceholders(){const t=JSON.parse(JSON.stringify(this.config));for(const e in this.replacedEnvVars){const{original:s}=this.replacedEnvVars[e],r=e.split(":"),a=r.pop(),{error:n,value:i}=S(t,r);if(n||!O(i)&&!Array.isArray(i)){await w.panicOnBuild(`Failed to replace env var with env name for ${e}`);continue}i[a]=s}return t}async reportUnsetEnvVars(){if(this.unsetEnvVars.size===0)return;const t=Array.from(this.unsetEnvVars).filter(s=>!z.includes(s));if(t.length===0)return;const e=`Failed to resolve config. The following environment variables are not set: ${t.join(", ")}`;await w.panicOnBuildContentError(e)}}function Y(P){return T(P,t=>b.Ast.fromJSON(JSON.stringify(t)))}export{g as MARKDOC_PARTIALS_DATA_KEY,W as MARKDOC_PARTIALS_DEPS_KEY,E as Store,At as USER_DEFINED_API_FUNCTIONS_COUNTER_KEY};
|
|
1
|
+
import b from"@markdoc/markdoc";import{getPathnameForLocale as A}from"@redocly/theme/core/utils";import{DEFAULT_LOCALE_PLACEHOLDER as f}from"../constants/common.js";import{DEFAULT_TITLE as C}from"./constants/common.js";import{GATED_MARKDOC_TAGS as D}from"./constants/entitlements.js";import{isObject as O}from"../utils/guards/is-object.js";import{mapObject as T}from"../utils/object/map-object.js";import{getValueDeep as S}from"../utils/object/get-value-deep.js";import{removeTrailingSlash as M}from"../utils/url/remove-trailing-slash.js";import{normalizeRouteSlug as p}from"../utils/path/normalize-route-slug.js";import{isLocalLink as L}from"../utils/path/is-local-link.js";import{reporter as w}from"./tools/notifiers/reporter.js";import{logger as g}from"./tools/notifiers/logger.js";import{sha1 as k}from"./utils/crypto/sha1.js";import{writeEnvVariable as _}from"./utils/envs/write-env-variable.js";import{envConfig as F}from"./config/env-config.js";import{KvService as G}from"./persistence/kv/services/kv-service.js";import{writeSharedData as B}from"./utils/index.js";import{renderComponents as I}from"./ssr/render.js";import{readStaticData as N,writeStaticData as V}from"./utils/static-data.js";import{parseAndResolveMarkdoc as j}from"./plugins/markdown/compiler.js";import{getMarkdocOptions as H}from"./plugins/markdown/markdoc/markdoc-options.js";import{EntitlementsProvider as y}from"./entitlements/entitlements-provider.js";import{isL10nPath as K}from"./fs/utils/is-l10n-path.js";import{resolveMetadataGlobs as U}from"./utils/globs.js";import{replaceEnvVariablesDeep as J}from"./utils/envs/replace-env-variables-deep.js";import{findRedirect as q}from"./utils/redirects/find-redirect.js";import{addWildcardRedirectToTree as x}from"./utils/redirects/add-wildcard-redirect-to-tree.js";import{telemetryTraceStep as $}from"../cli/telemetry/helpers/trace-step.js";const R={routesBySlug:"map",apiRoutes:"object",middleware:"object",routesByFsPath:"map",routesSharedData:"map",globalData:"object",config:"object",ssr:"object",searchFacets:"map",routesPartials:"map"},m="markdown/partials",W="markdown/partials-deps",v="PLAN_GATES",z=["OAUTH_CLIENT_ID","OAUTH_CLIENT_SECRET","ORGANIZATION_SLUG","ORGANIZATION_ID","ORG_ID"],At="userDefinedApiFunctions";class E{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;serverPropsGetters=new Map;pagePropsGetters=new Map;listeners=new Map;globalData={};#s=void 0;config={configFilePath:"",redirects:{},wildcardRedirectsTree:{},access:{rbac:{},requiresLogin:!1},directoryPermissions:{},devLogin:!1,ssoDirect:{}};#r;serverMode;serverOutDir;outdir;buildRevision=0;hasSitemap=!1;compilationErrors=[];#a;userCodeReady;#o=Promise.resolve();#i;#n=Promise.resolve();#c;#e=new Map;constructor({outdir:t,contentDir:e,serverMode:s=!1,serverOutDir:a}){this.#r=e,this.outdir=t,this.serverMode=s,this.serverOutDir=a,this.userCodeReady=new Promise(r=>{this.#a=r})}on(t,e){const s=this.listeners.get(t);s?s.add(e):this.listeners.set(t,new Set([e]))}queueEvent=(t,e,...s)=>{this.#e.set(t+String(e),[t,e,...s])};runListeners=(t,e,...s)=>{for(const a of this.listeners.get(t)||new Set)e?a(e,...s):a(...s)};startPluginsRun(){this.clear(),this.#o=new Promise(t=>{this.#i=t})}waitForPluginsLifecycle(){return Promise.all([this.#o,this.#n])}finishPluginsRun(){this.#i?.();for(const t of this.#e.values())this.runListeners(...t);this.#e.clear()}startEsbuildRun(){this.#n=new Promise(t=>{this.#c=t})}finishEsbuildRun(){this.#c?.()}get contentDir(){if(this.serverMode)throw new Error("contentDir should not be used in server mode");return this.#r}markUserCodeReady(){this.#a?.(!0)}async reloadMarkdocOptions(){await $("build.reload_markdoc_options",async()=>{const t=y.instance(),e=await H(this.serverOutDir),s=Object.fromEntries(Object.entries(e.tags).filter(([a])=>D[a]!=null?t.canAccessFeature(D[a]):!0));this.#s={...e,tags:s}})}get markdocOptions(){return{...this.#s,partials:this.getGlobalConfig(m),themeConfig:this.config.markdown}}setGlobalData=t=>{const e=this.globalData,s={...this.globalData,...t};this.globalData=s,JSON.stringify(s)!==JSON.stringify(e)&&this.queueEvent("global-data-updated",void 0,s)};getGlobalData=()=>this.globalData;getKv=async()=>G.getInstance({baseDbDir:this.serverOutDir});parseMarkdoc=async({input:t,context:e,deps:s,resource:a})=>{const{data:{info:r,ast:c},compoundHash:l}=await j(t,this.markdocOptions,{actions:this,context:e},a);for(const i of r.sharedDataDeps||[]){for(const o of s?.routeSlugs||[])this.addRouteSharedData(o,i,i);for(const o of s?.sharedDataIds||[]){const n=this.sharedDataDeps.get(o)||new Set;n.add(i),this.sharedDataDeps.set(o,n)}}for(const i of r.dynamicMarkdocComponents||[]){for(const o of s?.routeSlugs||[]){const n=this.routesDynamicComponents.get(o)||new Set;n.add(i),this.routesDynamicComponents.set(o,n)}for(const o of s?.sharedDataIds||[]){const n=this.sharedDataMarkdocComponents.get(o)||new Set;n.add(i),this.sharedDataMarkdocComponents.set(o,n)}}if(s?.routeSlugs&&r.partials?.length)for(const i of s.routeSlugs){const o=this.routesPartials.get(i)||[];for(const n of r.partials)o.includes(n)||o.push(n);this.routesPartials.set(i,o)}return{info:r,ast:c,compoundHash:l}};async loadOpenApiDefinitions(t){return(await t.cache.load(".","load-oas-docs")).data}async loadAsyncApiDefinitions(t){return(await t.cache.load(".","asyncapi-docs")).data}setSearchEngine(t){this.searchEngine=t}setSearchFacets=t=>{this.searchFacets=t};setGlobalConfig=t=>{const e=Object.keys(t);for(const c of e)for(const l in this.replacedEnvVars)if(l===c||l.startsWith(`${c}:`)){const i=l.split(":"),{error:o,value:n}=S(t,i);(o||n!==this.replacedEnvVars[l].replaced)&&delete this.replacedEnvVars[l]}const{resolvedObj:s,unsetEnvVars:a,replacedValues:r}=J(t);for(const c of a)this.unsetEnvVars.add(c);Object.assign(this.replacedEnvVars,r),Object.assign(this.config,s)};getConfig=()=>this.config;getGlobalConfig=t=>this.config[t];getSearchFacets=()=>this.searchFacets;addRedirect=(t,e)=>{if(!y.instance().canAccessFeature("redirects")&&t!=="/")return;this.config.redirects||(this.config.redirects={});const r=p(t).toLowerCase();this.config.redirects[r]=e,r.endsWith("*")&&x(this.config.wildcardRedirectsTree,r)};getRedirect=t=>{const e=p(t).toLowerCase();return q(e,this.config.redirects,this.config.wildcardRedirectsTree)};createSharedData=async(t,e,s)=>{if(s&&this.#t[t]===s)return t;const a=JSON.stringify(e),r=s??k(a);return this.#t[t]===r||(this.#t[t]=r,await B(t,a,this.outdir),this.queueEvent("shared-data-updated",t)),t};addRouteSharedData=(t,e,s)=>{const a=M(t),r=this.routesSharedData.get(a)||{};r[e]=s,this.routesSharedData.set(a,r),g.verbose(`Adding shared data to ${t}, ${e}, ${s}`)};getRouteSharedDataByFsPath=t=>{const e=this.routesByFsPath.get(t);return e?this.routesSharedData.get(e)||{}:{}};getPartialsForRoute=t=>{const e=this.getGlobalConfig(m)||{},s=this.routesPartials.get(t);if(!s||s.length===0)return{};const a=this.getGlobalConfig(W)||{},r=new Set(s),c=Array.from(s);for(let i=0;i<c.length;i++){const o=c[i],n=a[o]?.partials??[];for(const d of n)r.has(d)||(r.add(d),c.push(d))}const l={};for(const i of r)e[i]&&(l[i]=e[i]);return l};addRoute=t=>{const s={...U(t.fsPath,this.config.metadataGlobs),...t.metadata||{}};this.newRoutes.push({...t,metadata:s}),g.verbose("Created route %s",t.slug)};addRouteSharedDataToAllLocales=(t,e,s)=>{const a=[f,...this.lifecycleContext?.fs.localeFolders||[]].map(r=>({code:r,name:r}));for(const r of a){const c=A(t,f,r.code,a);this.addRouteSharedData(c,e,s)}};addApiRoute=t=>{this.apiRoutes.push(t),g.verbose("Created API route %s",t.slug)};addMiddleware=t=>{this.middleware.push(t),g.verbose("Created middleware %s",t.id)};getRouteByFsPath=t=>{const e=this.routesByFsPath.get(t);return e?this.getRouteBySlug(e):void 0};getRouteBySlug=(t,e={})=>{const{followRedirect:s=!0}=e,a=this.getRedirect(t);return s&&a?this.routesBySlug.get(p(a.to)):this.routesBySlug.get(t)};slugHasRouteOrRedirect=t=>{if(this.routesBySlug.has(t))return!0;const e=this.getRedirect(t);if(!e)return!1;if(!L(e.to))return!0;const s=p(e.to);return this.routesBySlug.has(s)};getRoutesByTemplateId=t=>this.newRoutes.filter(e=>e.templateId===t);getAllRoutesForLocale=(t=f)=>{const e=Array.from(this.routesBySlug.values()),s=t.toLowerCase();return e.filter(a=>t===f?!K(a.fsPath):a.slug.startsWith(`/${s}`))};getAllRoutes=()=>Array.from(this.routesBySlug.values());getAllApiRoutes=()=>this.apiRoutes;getAllMiddleware=()=>this.middleware;getTemplate=t=>this.templates.get(t);getRequestHandler=t=>this.apiRoutesRequestHandlers.get(t);createTemplate=(t,e)=>(this.templates.set(t,e),t);addBrowserPlugin=t=>{this.browserPlugins.add(t)};createRequestHandler=(t,e)=>(this.apiRoutesRequestHandlers.set(t,e),t);registerServerPropsGetter=(t,e)=>(this.serverPropsGetters.set(t,e),t);registerPagePropsGetter=(t,e)=>{this.pagePropsGetters.set(t,e)};async writeRouteStaticData(t,e){const s=await this.resolveRouteStaticData(t,e,!1);s&&V(t.slug,s,this.outdir)}async resolveRouteStaticData(t,e,s){if(this.serverMode)return N(t.slug,this.outdir);const a={...this,contentDir:this.contentDir,parseMarkdoc:({input:n,context:d,resource:h})=>this.parseMarkdoc({input:n,context:d,deps:{routeSlugs:[t.slug]},resource:h})},r=await t.getStaticData?.(t,a)||{},c=new Set(this.routesDynamicComponents.get(t.slug)),l=this.routesSharedData.get(t.slug)||{};for(const n of Object.values(l)){const d=this.sharedDataMarkdocComponents.get(n);d&&d.forEach(u=>c.add(u));const h=this.sharedDataDeps.get(n);h&&h.forEach(u=>this.addRouteSharedData(t.slug,u,u))}const i=this.getGlobalConfig("seo"),o=r?.frontmatter||{};return{...r,frontmatter:{...o,seo:{...o?.seo,title:o?.seo?.title||await t.getNavText?.()}},props:{...r.props,dynamicMarkdocComponents:Array.from(c),metadata:{...r?.props?.metadata,...t.metadata},seo:{title:C,...i,...r.props?.seo},compilationErrors:this.compilationErrors},lastModified:s||!t.fsPath?null:await this.lifecycleContext?.fs.getLastModified(t.fsPath)}}addSsrComponents(t,e){if(!t?.length)return;const s=typeof t[0]=="string"?t.join(""):I(t);s&&(e==="head"?this.ssr.headTags.push(s):e==="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.config.redirects={},this.config.wildcardRedirectsTree={},this.config.directoryPermissions={},this.ssr={preBodyTags:[],postBodyTags:[],headTags:[]}};async toJson(){const t=[];for(const[s,a]of Object.entries(R))switch(a){case"map":const r=Array.from(this[s].entries());t.push([s,r]);break;case"object":s==="config"&&t.push([s,await this.getConfigWithEnvPlaceholders()]),t.push([s,this[s]]);break;default:throw new Error("Invalid format")}const e=Object.fromEntries(t);return e[v]=F.PLAN_GATES,e}static fromJson(t,e){const s=new E(e);for(const[r,c]of Object.entries(R))switch(c){case"map":s[r]=new Map(t[r]);break;case"object":if(r==="config"){s.setGlobalConfig(t[r]);break}s[r]=t[r];break;default:throw new Error("Invalid format")}s.config[m]=Y(s.config[m]||{});const a=t[v];return a&&_("PLAN_GATES",a),s}async getConfigWithEnvPlaceholders(){const t=JSON.parse(JSON.stringify(this.config));for(const e in this.replacedEnvVars){const{original:s}=this.replacedEnvVars[e],a=e.split(":"),r=a.pop(),{error:c,value:l}=S(t,a);if(c||!O(l)&&!Array.isArray(l)){await w.panicOnBuild(`Failed to replace env var with env name for ${e}`);continue}l[r]=s}return t}async reportUnsetEnvVars(){if(this.unsetEnvVars.size===0)return;const t=Array.from(this.unsetEnvVars).filter(s=>!z.includes(s));if(t.length===0)return;const e=`Failed to resolve config. The following environment variables are not set: ${t.join(", ")}`;await w.panicOnBuildContentError(e)}}function Y(P){return T(P,t=>b.Ast.fromJSON(JSON.stringify(t)))}export{m as MARKDOC_PARTIALS_DATA_KEY,W as MARKDOC_PARTIALS_DEPS_KEY,E as Store,At as USER_DEFINED_API_FUNCTIONS_COUNTER_KEY};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import{envConfig as p}from"../../config/env-config.js";import{gray as w}from"./helpers/colors.js";const t="\x1B[",
|
|
1
|
+
import{envConfig as p}from"../../config/env-config.js";import{gray as w}from"./helpers/colors.js";const t="\x1B[",u=`${t}6n`,o=`${t}s`,c=`${t}u`,f=`${t}J`,h=n=>`${t}1;${n}r`,a=`${t}r`,l=`${t}?25h`,R=`${t}?25l`,I=()=>`${w("\u2500".repeat(process.stderr.columns||80))}
|
|
2
2
|
|
|
3
|
-
`,g=3;class
|
|
4
|
-
`.repeat(
|
|
5
|
-
`.repeat(e)),process.stderr.write(h(r-e)),process.stderr.write(c),this.#
|
|
6
|
-
`.repeat(Math.max(0,r-e))),process.stderr.write(h(
|
|
3
|
+
`,g=3;class E{#s=new Map;#i=process.stderr.rows;#o=0;#c=!1;#n=!1;#r;#p=!1;constructor(s=!1){this.#n=s}isInteractive(){return!!(this.#n&&process.stderr&&process.stderr.isTTY&&process.stdin.isTTY&&p.TERM!=="dumb"&&!("CI"in process.env)&&p.isDevelopMode)}isFooterChanged(s,r){return this.#s.get(s)!==r}updateFooter(s,r){const e=!this.#s.has(s);this.#s.set(s,r),this.isInteractive()&&(this.#a(),e?this.#h():this.#t())}get#e(){if(this.#s.size===0)return 0;let s=g;for(const r of this.#s.values())s+=(r.match(/\n/g)||[]).length;return s}#a(){!this.isInteractive()||this.#p||(this.#p=!0,this.#u(),process.stderr.write(u))}#t(){if(!this.isInteractive()||this.#s.size===0||!this.#r)return;this.#d();const s=this.#e,r=process.stderr.rows;if(!(s>r)){process.stderr.write(o),process.stderr.cursorTo(0,r-s-1),process.stderr.write(f),process.stderr.cursorTo(0,r-s+1),process.stderr.write(I());for(const e of this.#s.values())process.stderr.write(e);process.stderr.write(c)}}#h(s=0){if(!this.isInteractive())return;const r=process.stderr.rows;let e=this.#e;e>r&&(e=0);const i=e-this.#o;this.#o=e,i>0&&(process.stderr.write(o),process.stderr.write(`
|
|
4
|
+
`.repeat(i)),process.stderr.write(c)),process.stderr.write(o),s<0&&process.stderr.write(`
|
|
5
|
+
`.repeat(e)),process.stderr.write(h(r-e)),process.stderr.write(c),this.#t()}#d(){this.#c||!this.#r||(this.#c=!0,this.#w(),process.stderr.write(R),process.on("exit",this.#f),process.stderr.on("resize",this.#l))}#w(){if(!this.#r)return;const s=process.stderr.rows,{row:r}=this.#r,e=this.#e,i=s-e;r<i||(process.stderr.write(o),process.stderr.write(a),process.stderr.cursorTo(0,s-1),process.stderr.write(`
|
|
6
|
+
`.repeat(Math.max(0,r-e))),process.stderr.write(h(i)),process.stderr.write(c),process.stderr.cursorTo(0,0))}#u(){if(!this.isInteractive())return;process.stdin.setRawMode(!0),process.stdin.resume(),process.stdin.setEncoding("utf8");const s=/\[(\d+);(\d+)R/;process.stdin.once("data",r=>{if(s.test(r)){const e=s.exec(r);if(e){const i=parseInt(e[1],10),d=parseInt(e[2],10);this.#r={row:i,col:d}}}process.stdin.setRawMode(!1),process.stdin.pause(),this.#s.size>0&&this.#t()})}#f=()=>{this.isInteractive()&&(process.stderr.write(a),process.stderr.write(`${t}${process.stderr.rows};1H`),process.stderr.write(l))};#l=()=>{const s=process.stderr.rows-this.#i;this.#i=process.stderr.rows,this.#h(s)}}export{E as TerminalManager};
|
|
@@ -8,13 +8,13 @@ import type { GlobalData, Feature } from '../../../types/index.js';
|
|
|
8
8
|
import type { SearchDocument } from '../../types';
|
|
9
9
|
import type { RbacScopeItems, RedirectConfig, RedoclyConfig, ServerPropsContext, ServerPropsRequest, PageProps, PageStaticData, NavItem, ResolvedNavItem, Version, MdOptions, KvService } from '@redocly/config';
|
|
10
10
|
import type { LoaderFn } from '../fs';
|
|
11
|
-
import type { MarkdocDeps } from './markdown';
|
|
12
11
|
import type { BundledDefinition } from '../../plugins/openapi-docs/load-definition';
|
|
13
12
|
import type { Cache } from '../../fs/cache';
|
|
14
13
|
import type { ContentFs } from '../../fs/content-fs';
|
|
15
14
|
import type { SearchEngine } from '../../plugins/search/engines/search-engine';
|
|
16
15
|
import type { Logger } from '../../tools/notifiers/logger.js';
|
|
17
16
|
import type { AiDocumentsStore } from '../../plugins/search/types';
|
|
17
|
+
import type { ParseMarkdocOpts } from '../../types/plugins/markdown';
|
|
18
18
|
export type ResolveItemsOptions = {
|
|
19
19
|
groupCustomSidebars?: boolean;
|
|
20
20
|
locale?: string;
|
|
@@ -37,7 +37,7 @@ export type GetStaticDataContext = {
|
|
|
37
37
|
getConfig: () => RedoclyConfig;
|
|
38
38
|
getAllRoutes: () => PageRouteDetails<PageStaticData, PageProps>[];
|
|
39
39
|
getAllApiRoutes: () => ApiRoute[];
|
|
40
|
-
parseMarkdoc: (
|
|
40
|
+
parseMarkdoc: (opts: Omit<ParseMarkdocOpts, 'deps'>) => Promise<{
|
|
41
41
|
ast: Node;
|
|
42
42
|
info: Record<string, unknown>;
|
|
43
43
|
compoundHash: string;
|
|
@@ -132,7 +132,7 @@ export type ProcessContentActions = {
|
|
|
132
132
|
setGlobalConfig: (data: Record<string, unknown>) => void;
|
|
133
133
|
setGlobalData: (data: GlobalData) => void;
|
|
134
134
|
getConfig: () => RedoclyConfig;
|
|
135
|
-
parseMarkdoc: (
|
|
135
|
+
parseMarkdoc: (opt: ParseMarkdocOpts) => Promise<{
|
|
136
136
|
ast: Node;
|
|
137
137
|
info: Record<string, unknown>;
|
|
138
138
|
compoundHash: string;
|
|
@@ -168,7 +168,7 @@ export type AfterRoutesCreatedActions = {
|
|
|
168
168
|
setGlobalData: (data: GlobalData) => void;
|
|
169
169
|
getGlobalData: () => GlobalData;
|
|
170
170
|
setGlobalConfig: (data: Record<string, unknown>) => void;
|
|
171
|
-
parseMarkdoc: (
|
|
171
|
+
parseMarkdoc: (opts: ParseMarkdocOpts) => Promise<{
|
|
172
172
|
ast: Node;
|
|
173
173
|
info: Record<string, unknown>;
|
|
174
174
|
compoundHash: string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { PageStaticData, REDOCLY_ROUTE_RBAC, REDOCLY_TEAMS_RBAC, RbacScopeItems } from '@redocly/config';
|
|
2
|
-
import type { PluginDefaultOptions, PageRouteDetails, LifecycleContext, AfterRoutesCreatedActions } from '../../types';
|
|
2
|
+
import type { PluginDefaultOptions, PageRouteDetails, LifecycleContext, AfterRoutesCreatedActions, MarkdownParseInput } from '../../types';
|
|
3
3
|
import type { LINK_ORIGINAL_ATTR_NAME } from '../../constants/common';
|
|
4
4
|
export type RoutesInfoActions = {
|
|
5
5
|
outdir: string;
|
|
@@ -34,4 +34,10 @@ export type MdPageStaticData = {
|
|
|
34
34
|
export type WithOriginalAttr<T, P = string> = T & {
|
|
35
35
|
[K in `${typeof LINK_ORIGINAL_ATTR_NAME}:${string}`]?: P | null;
|
|
36
36
|
};
|
|
37
|
+
export type ParseMarkdocOpts = {
|
|
38
|
+
input: MarkdownParseInput;
|
|
39
|
+
context: LifecycleContext;
|
|
40
|
+
deps?: MarkdocDeps;
|
|
41
|
+
resource?: string;
|
|
42
|
+
};
|
|
37
43
|
//# sourceMappingURL=markdown.d.ts.map
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builds the markdown asset path used for `llms.txt` / AI agent flows from a route slug.
|
|
3
|
+
*
|
|
4
|
+
* The site root slug (`/`) maps to `index.html.md` so the home page resolves like other HTML routes;
|
|
5
|
+
* every other slug gets a `.md` suffix on the same path.
|
|
6
|
+
*
|
|
7
|
+
* @param routeSlug - URL path segment for the page (e.g. `/`, `/docs`, `/reference/petstore`)
|
|
8
|
+
* @returns Path to the corresponding markdown file (e.g. `/index.html.md`, `/docs.md`)
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* getLlmsTxtMdPathBySlug('/');
|
|
12
|
+
* // returns '/index.html.md'
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* getLlmsTxtMdPathBySlug('/guides/getting-started');
|
|
16
|
+
* // returns '/guides/getting-started.md'
|
|
17
|
+
*/
|
|
18
|
+
export declare function getLlmsTxtMdPathBySlug(routeSlug: string): string;
|
|
19
|
+
//# sourceMappingURL=get-llms-txt-md-path-by-slug.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function d(t){return`${t}${t==="/"?"index.html.md":".md"}`}export{d as getLlmsTxtMdPathBySlug};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function e(t){return!t||typeof t!="object"?!1:!("content"in t||"features"in t||"teamNamePatterns"in t||"teamFolders"in t)}export{e as isRbacScopeItems};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import R from"path";import x from"picomatch";import"../node-crypto-polyfill.js";import{REDOCLY_TEAMS_RBAC as _,REDOCLY_ROUTE_RBAC as A}from"@redocly/config";import{DEFAULT_ANONYMOUS_VISITOR_TEAM as O,ServerRoutes as w,PUBLIC_RBAC_SCOPE_ITEM as y,RBAC_ALL_OTHER_TEAMS as u,DEFAULT_RBAC_SCOPE as S}from"../../constants/common.js";import{DEPRECATED_PUBLIC_API_DEFINITIONS_FOLDER as I,PUBLIC_API_DEFINITIONS_FOLDER as C,PUBLIC_ASSETS_FOLDER as N}from"../constants/common.js";import{removeTrailingSlash as B}from"../../utils/url/remove-trailing-slash.js";import{removeLeadingSlash as k}from"../../utils/url/remove-leading-slash.js";import{parsePathVersions as M}from"../../utils/path/parse-path-versions.js";import{reporter as W}from"../tools/notifiers/reporter.js";import{bold as U}from"../tools/notifiers/helpers/colors.js";import{shaDirPathShort as $}from"../utils/crypto/sha-dir-path-short.js";import{isTruthy as b}from"../../utils/guards/is-truthy.js";import{canExpandConfig as v,expandRbacConfig as Y,getTeamFolderDefaults as z,parseTeamFoldersTemplate as H,parseTeamNameTemplate as K}from"./rbac-expand.js";import{getUserParamsFromCookies as G}from"../web-server/auth.js";import{getDeeperGlobPattern as V}from"./globs.js";import{EntitlementsProvider as J}from"../entitlements/entitlements-provider.js";const j=["NONE","READ","TRIAGE","WRITE","MAINTAIN","ADMIN"],Q=new Set(["x-parsed-md-description","x-parsed-md-summary"]);function yt(t,e){const n=j.indexOf(t.toUpperCase()),r=j.indexOf(e.toUpperCase());return n>r?t:e}const E={};function P(t,e){if(!t?.content)return y;const n=t.content,{slug:r,fsPath:s}=e;if(!r&&!s)return y;const o=f=>{const h=`slug:${f}`,m=E[h]??x(f);E[h]=m;const g=`fsPath:${f}`,L=E[g]??x(k(f));return E[g]=L,!!(r&&m(r))||!!(s&&L(s))};if(X(r||s||"")&&Object.keys(n).filter(m=>o(m)).length===0)return n[S]||y;const c=Object.keys(n).filter(f=>o(f));if(c.length==0)return y;const l=c.map(f=>x.scan(f,{tokens:!0,parts:!0}));let p=l[0];for(let f=1;f<l.length;f++)p=V(p,l[f]);return n[p.input]}function Et(t,e,n={},r=!1){if(r&&Object.keys(n).length===0)return e.isAuthenticated;const s=n.features?.[t];return s?e.teams.some(o=>s[o]&&s[o].toLowerCase()!=="none"):!0}function Pt(t,e){return T(t,{isAuthenticated:!1,teams:[O]},e.rbac||{},e.requiresLogin||!1)}function T(t,e={},n={},r=!1){if(t.slug&&typeof t.slug=="string"&&Object.values(w).some(c=>{const l=c.split(":")[0].replace(/\/$/,"");return t.slug===l||t.slug?.startsWith(c)})||typeof t.slug=="string"&&t.slug?.endsWith("/mcp")&&J.instance().canAccessFeature("mcp"))return!0;if(r&&Object.keys(n).length===0)return!!e.isAuthenticated;const s=Y(n,e.teams||[]),o=t[_]||P(s,t[A]||{});if(Object.keys(o||{}).length===0)return!1;if(Object.keys(o).length===1&&o[u]&&o[u].toLowerCase()!=="none")return!0;const a=(e?.email?[...e?.teams||[],e?.email]:e?.teams)||[],i=[];for(const c of a??[])o[c]?i.push(o[c]):o[u]&&c!==e?.email&&i.push(o[u]);return i.length?i.some(c=>c.toLowerCase()!=="none"):!1}function Tt(t,e,n,r){if(!t.startsWith(C)&&!t.startsWith(I))return!0;const s=t.replace(new RegExp(`^${C}/`),"").replace(new RegExp(`^${I}/`),""),a=s==="."?"":s,i={[A]:{slug:t,fsPath:a},slug:t};return T(i,r,e,n)}function xt(t,e,n,r,s){if(!t.startsWith(N))return!0;const o=t.match(/.*\..{64}\.([A-Fa-f0-9]{8})\.[^\.]+$/)?.[1];if(!o)return!0;const a=r[o];if(!a)return!0;const{base:i,ext:c}=R.parse(t),l=i.split(".")[0],p=c.split(".").join(""),h=a==="."?"":a,m={[A]:{slug:t,fsPath:R.posix.join(h,`${l}.${p}`)},slug:t};return T(m,s,e,n)}async function Ot(t,e){const{isAuthenticated:n=!1,idpAccessToken:r,federatedAccessToken:s,federatedIdToken:o,...a}=await G(t,e),{teams:i=[]}=a;let c;return n?c=i.filter(l=>l!==O):c=[O],{isAuthenticated:n,idpAccessToken:r,teams:c,claims:a}}function F(t,e,n={},r=!1){if(!t)return t;if(Array.isArray(t)){const s=[];for(const o of t){const a=F(o,e,n,r);a!==void 0&&s.push(a)}return s}if(typeof t=="object"){if(!T(t,e,n,r))return;let s=!1;const o={};for(const a in t){if(a===_||a===A)continue;if(Q.has(a)){o[a]=t[a];continue}const i=F(t[a],e,n,r);if(a==="items"&&Array.isArray(i)&&i.length===0&&t[a].length!==0){s=!0;continue}i!==void 0&&(o[a]=i)}return s?void 0:o}return t}function Dt(t){return typeof t=="string"?t.split(" ").filter(Boolean):Array.isArray(t)?t.map(e=>e.toString()):[]}function gt(t,e){if(!e)return;const n=e.content;if(!n)return e;const r=Object.entries(n).flatMap(([o,a])=>o===S?[[o,a]]:[[o,a],...t.localeFolders.map(i=>[o.startsWith("/")?`/${i.toLocaleLowerCase()}${o}`:R.posix.join(t.localizationFolder,i,o),a])]),s=Object.fromEntries(r);return{...e,content:s}}async function Lt(t,e){if(!e)return{};const n={},r=new Set((await t.scan()).flatMap(({relativePath:s})=>{const{versionFolderPath:o}=M(s)||{},a=R.dirname(s);return o?[o,a]:a}));for(const s of r)n[$(s)]=s;return n}const d=t=>typeof t=="object"&&t!==null&&!Array.isArray(t);function X(t){return t?t.split("/").filter(Boolean).some(n=>n.startsWith(".")):!1}const Z=t=>{if(t&&d(t)&&("content"in t&&d(t.content)||"reunite"in t&&d(t.reunite)||"features"in t&&d(t.features)||t.teamFolders&&t.teamNamePatterns)){const e=Object.values(t.content||{});if(e.length===0)return!0;if(e.every(d))return e.every(n=>Object.values(n).every(r=>typeof r=="string"))}return!1},_t=async t=>{if(t){if(Object.keys(t).length===0)return{};if(Z(t))return q(t);await W.panicOnContentError(`You are using an incorrect format of ${U("rbac:")} configuration. See: https://redocly.com/docs/realm/access`)}},q=t=>{const e={...t};if(e.content){const n={};for(const r in e.content)if(e.content[r]!==void 0){const s=B(r);n[s]=e.content[r]}e.content=n}return e};function St(t,e){const n=t.fsPath,r=t.slug,s=[];if(v(e)&&(n||r)){const o=[n,r].filter(b),a=H(e,o);if(a){const i=e?.teamNamePatterns?.map(l=>l.replace("{teamPathSegment}",a.teamPathSegment).replace("{projectRole}","read"))??[];s.push(...i);const c=P({content:{...z(e),...e.content}},t);s.push(...D(c))}else{const i=P(e,t);s.push(...D(i))}}else{const o=P(e,t);s.push(...D(o))}return tt(e,s)}function D(t){if(!t)return[];const e=[],n=u in t?{authenticated:t[u],anonymous:t[u]}:{};for(const[r,s]of Object.entries({...n,...t}))s.toLowerCase()!=="none"&&r!==u&&e.push(r);return e}function tt(t,e){return e.map(r=>K(t,r)??{teamName:r}).map(r=>r.projectRole&&r.projectRole!=="READ"?r.teamName?.toLowerCase().replace(r.projectRole?.toLowerCase?.()??"","read")??"":r.teamName?.toLowerCase()??"")}export{j as PROJECT_ROLES_ORDERED_BY_ACCESS_LEVEL,gt as applyL10nToRbacConfig,xt as canAccessAsset,Et as canAccessFeature,T as canAccessResource,Tt as canDownloadApiDefinition,tt as expandTeamsForRead,D as extractTeamsFromScopeItems,F as filterDataByAccessDeep,Ot as getAuthDetailsFromCookies,yt as getHigherRole,St as getRbacTeamsListForResource,P as getScopeItemsForResource,Z as isRbacConfigValid,Pt as isResourcePubliclyAccessible,q as normalizeRbacConfig,_t as parseRbacConfig,Dt as parseTeamClaimToArray,Lt as resolveDirectoryHashes};
|
|
1
|
+
import R from"path";import x from"picomatch";import"../node-crypto-polyfill.js";import{REDOCLY_TEAMS_RBAC as _,REDOCLY_ROUTE_RBAC as A}from"@redocly/config";import{DEFAULT_ANONYMOUS_VISITOR_TEAM as O,ServerRoutes as w,PUBLIC_RBAC_SCOPE_ITEM as y,RBAC_ALL_OTHER_TEAMS as u,DEFAULT_RBAC_SCOPE as S}from"../../constants/common.js";import{DEPRECATED_PUBLIC_API_DEFINITIONS_FOLDER as I,PUBLIC_API_DEFINITIONS_FOLDER as C,PUBLIC_ASSETS_FOLDER as N}from"../constants/common.js";import{removeTrailingSlash as B}from"../../utils/url/remove-trailing-slash.js";import{removeLeadingSlash as k}from"../../utils/url/remove-leading-slash.js";import{parsePathVersions as M}from"../../utils/path/parse-path-versions.js";import{reporter as W}from"../tools/notifiers/reporter.js";import{bold as U}from"../tools/notifiers/helpers/colors.js";import{shaDirPathShort as $}from"../utils/crypto/sha-dir-path-short.js";import{isTruthy as b}from"../../utils/guards/is-truthy.js";import{canExpandConfig as v,expandRbacConfig as Y,getTeamFolderDefaults as z,parseTeamFoldersTemplate as H,parseTeamNameTemplate as K}from"./rbac-expand.js";import{getUserParamsFromCookies as G}from"../web-server/auth.js";import{getDeeperGlobPattern as V}from"./globs.js";import{EntitlementsProvider as J}from"../entitlements/entitlements-provider.js";const j=["NONE","READ","TRIAGE","WRITE","MAINTAIN","ADMIN"],Q=new Set(["x-parsed-md-description","x-parsed-md-summary"]);function yt(t,e){const n=j.indexOf(t.toUpperCase()),r=j.indexOf(e.toUpperCase());return n>r?t:e}const E={};function P(t,e){if(!t?.content)return y;const n=t.content,{slug:r,fsPath:s}=e;if(!r&&!s)return y;const o=f=>{const h=`slug:${f}`,m=E[h]??x(f);E[h]=m;const g=`fsPath:${f}`,L=E[g]??x(k(f));return E[g]=L,!!(r&&m(r))||!!(s&&L(s))};if(X(r||s||"")&&Object.keys(n).filter(m=>o(m)).length===0)return n[S]||y;const c=Object.keys(n).filter(f=>o(f));if(c.length==0)return y;const l=c.map(f=>x.scan(f,{tokens:!0,parts:!0}));let p=l[0];for(let f=1;f<l.length;f++)p=V(p,l[f]);return n[p.input]}function Et(t,e,n={},r=!1){if(r&&Object.keys(n).length===0)return e.isAuthenticated;const s=n.features?.[t];return s?e.teams.some(o=>s[o]&&s[o].toLowerCase()!=="none"):!0}function Pt(t,e){return T(t,{isAuthenticated:!1,teams:[O]},e.access?.rbac||{},e.access?.requiresLogin||!1)}function T(t,e={},n={},r=!1){if(t.slug&&typeof t.slug=="string"&&Object.values(w).some(c=>{const l=c.split(":")[0].replace(/\/$/,"");return t.slug===l||t.slug?.startsWith(c)})||typeof t.slug=="string"&&t.slug?.endsWith("/mcp")&&J.instance().canAccessFeature("mcp"))return!0;if(r&&Object.keys(n).length===0)return!!e.isAuthenticated;const s=Y(n,e.teams||[]),o=t[_]||P(s,t[A]||{});if(Object.keys(o||{}).length===0)return!1;if(Object.keys(o).length===1&&o[u]&&o[u].toLowerCase()!=="none")return!0;const a=(e?.email?[...e?.teams||[],e?.email]:e?.teams)||[],i=[];for(const c of a??[])o[c]?i.push(o[c]):o[u]&&c!==e?.email&&i.push(o[u]);return i.length?i.some(c=>c.toLowerCase()!=="none"):!1}function Tt(t,e,n,r){if(!t.startsWith(C)&&!t.startsWith(I))return!0;const s=t.replace(new RegExp(`^${C}/`),"").replace(new RegExp(`^${I}/`),""),a=s==="."?"":s,i={[A]:{slug:t,fsPath:a},slug:t};return T(i,r,e,n)}function xt(t,e,n,r,s){if(!t.startsWith(N))return!0;const o=t.match(/.*\..{64}\.([A-Fa-f0-9]{8})\.[^\.]+$/)?.[1];if(!o)return!0;const a=r[o];if(!a)return!0;const{base:i,ext:c}=R.parse(t),l=i.split(".")[0],p=c.split(".").join(""),h=a==="."?"":a,m={[A]:{slug:t,fsPath:R.posix.join(h,`${l}.${p}`)},slug:t};return T(m,s,e,n)}async function Ot(t,e){const{isAuthenticated:n=!1,idpAccessToken:r,federatedAccessToken:s,federatedIdToken:o,...a}=await G(t,e),{teams:i=[]}=a;let c;return n?c=i.filter(l=>l!==O):c=[O],{isAuthenticated:n,idpAccessToken:r,teams:c,claims:a}}function F(t,e,n={},r=!1){if(!t)return t;if(Array.isArray(t)){const s=[];for(const o of t){const a=F(o,e,n,r);a!==void 0&&s.push(a)}return s}if(typeof t=="object"){if(!T(t,e,n,r))return;let s=!1;const o={};for(const a in t){if(a===_||a===A)continue;if(Q.has(a)){o[a]=t[a];continue}const i=F(t[a],e,n,r);if(a==="items"&&Array.isArray(i)&&i.length===0&&t[a].length!==0){s=!0;continue}i!==void 0&&(o[a]=i)}return s?void 0:o}return t}function Dt(t){return typeof t=="string"?t.split(" ").filter(Boolean):Array.isArray(t)?t.map(e=>e.toString()):[]}function gt(t,e){if(!e)return;const n=e.content;if(!n)return e;const r=Object.entries(n).flatMap(([o,a])=>o===S?[[o,a]]:[[o,a],...t.localeFolders.map(i=>[o.startsWith("/")?`/${i.toLocaleLowerCase()}${o}`:R.posix.join(t.localizationFolder,i,o),a])]),s=Object.fromEntries(r);return{...e,content:s}}async function Lt(t,e){if(!e)return{};const n={},r=new Set((await t.scan()).flatMap(({relativePath:s})=>{const{versionFolderPath:o}=M(s)||{},a=R.dirname(s);return o?[o,a]:a}));for(const s of r)n[$(s)]=s;return n}const d=t=>typeof t=="object"&&t!==null&&!Array.isArray(t);function X(t){return t?t.split("/").filter(Boolean).some(n=>n.startsWith(".")):!1}const Z=t=>{if(t&&d(t)&&("content"in t&&d(t.content)||"reunite"in t&&d(t.reunite)||"features"in t&&d(t.features)||t.teamFolders&&t.teamNamePatterns)){const e=Object.values(t.content||{});if(e.length===0)return!0;if(e.every(d))return e.every(n=>Object.values(n).every(r=>typeof r=="string"))}return!1},_t=async t=>{if(t){if(Object.keys(t).length===0)return{};if(Z(t))return q(t);await W.panicOnContentError(`You are using an incorrect format of ${U("rbac:")} configuration. See: https://redocly.com/docs/realm/access`)}},q=t=>{const e={...t};if(e.content){const n={};for(const r in e.content)if(e.content[r]!==void 0){const s=B(r);n[s]=e.content[r]}e.content=n}return e};function St(t,e){const n=t.fsPath,r=t.slug,s=[];if(v(e)&&(n||r)){const o=[n,r].filter(b),a=H(e,o);if(a){const i=e?.teamNamePatterns?.map(l=>l.replace("{teamPathSegment}",a.teamPathSegment).replace("{projectRole}","read"))??[];s.push(...i);const c=P({content:{...z(e),...e.content}},t);s.push(...D(c))}else{const i=P(e,t);s.push(...D(i))}}else{const o=P(e,t);s.push(...D(o))}return tt(e,s)}function D(t){if(!t)return[];const e=[],n=u in t?{authenticated:t[u],anonymous:t[u]}:{};for(const[r,s]of Object.entries({...n,...t}))s.toLowerCase()!=="none"&&r!==u&&e.push(r);return e}function tt(t,e){return e.map(r=>K(t,r)??{teamName:r}).map(r=>r.projectRole&&r.projectRole!=="READ"?r.teamName?.toLowerCase().replace(r.projectRole?.toLowerCase?.()??"","read")??"":r.teamName?.toLowerCase()??"")}export{j as PROJECT_ROLES_ORDERED_BY_ACCESS_LEVEL,gt as applyL10nToRbacConfig,xt as canAccessAsset,Et as canAccessFeature,T as canAccessResource,Tt as canDownloadApiDefinition,tt as expandTeamsForRead,D as extractTeamsFromScopeItems,F as filterDataByAccessDeep,Ot as getAuthDetailsFromCookies,yt as getHigherRole,St as getRbacTeamsListForResource,P as getScopeItemsForResource,Z as isRbacConfigValid,Pt as isResourcePubliclyAccessible,q as normalizeRbacConfig,_t as parseRbacConfig,Dt as parseTeamClaimToArray,Lt as resolveDirectoryHashes};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{TrieRouter as q}from"hono/router/trie-router";import{REDOCLY_ROUTE_RBAC as
|
|
1
|
+
import{TrieRouter as q}from"hono/router/trie-router";import{REDOCLY_ROUTE_RBAC as i}from"@redocly/config";import{withPathPrefix as C}from"@redocly/theme/core/utils";import{canAccessResource as L}from"../../../utils/rbac.js";import{handleUnauthorizedApiRequest as U}from"../../utils.js";import{handleApiRouteRequest as P}from"../../handle-api-route-request.js";import{sortApiFunctionRoutes as w}from"../../utils/sort-api-function-routes.js";function B(a,t){a.all("*",async(e,u)=>{const{method:m,path:o}=e.req,p=t.getAllApiRoutes(),h=w(p),c=new q;for(const n of h){const A=n.httpMethod?.toUpperCase()||"ALL",g=C(n.slug);c.add(A,g,n)}const s=c.match(m.toUpperCase(),o);if(!s||s[0].length===0)return u();const l=s[0],[r]=l[0],{isAuthenticated:R,claims:{email:f},teams:d}=e.get("auth");return L({...r,slug:o,[i]:{...r[i],slug:o}},{isAuthenticated:R,email:f,teams:d},t.config.access?.rbac,t.config.access?.requiresLogin)?P(r,e,t):U(e)})}export{B as installApiRoutes};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{CACHE_CONTROL_NO_CACHE_HEADER_VALUE as
|
|
1
|
+
import{CACHE_CONTROL_NO_CACHE_HEADER_VALUE as i}from"../../constants/common.js";import{filterDataByAccessDeep as o}from"../../utils/rbac.js";function f(a){return async e=>{const{isAuthenticated:t,teams:c,claims:{email:n}}=e.get("auth"),r=o(a.getGlobalData(),{isAuthenticated:t,email:n,teams:c},a.config.access?.rbac,a.config.access?.requiresLogin);return e.json({...r},200,{"Cache-Control":i})}}export{f as appDataHandler};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{RbacFeatures as p}from"../../../constants/common.js";import{ASK_AI_API_URL as r}from"../../constants/common.js";import{canAccessFeature as u}from"../../utils/rbac.js";import{handleUnauthorizedApiRequest as f}from"../utils.js";import{isAiSearchEnabled as h}from"../../plugins/search/utils.js";function C(a){return async e=>{if(!r)return e.newResponse(null,404);const t=a.getConfig();if(!h(t))return e.newResponse(null,403,{});const o=e.get("auth");if(!u(p.AI_SEARCH,o,t.rbac,t.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 c=await e.req.json(),s=await fetch(r,{method:"POST",body:JSON.stringify(c),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{C as askAiHandler};
|
|
1
|
+
import{RbacFeatures as p}from"../../../constants/common.js";import{ASK_AI_API_URL as r}from"../../constants/common.js";import{canAccessFeature as u}from"../../utils/rbac.js";import{handleUnauthorizedApiRequest as f}from"../utils.js";import{isAiSearchEnabled as h}from"../../plugins/search/utils.js";function C(a){return async e=>{if(!r)return e.newResponse(null,404);const t=a.getConfig();if(!h(t))return e.newResponse(null,403,{});const o=e.get("auth");if(!u(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 c=await e.req.json(),s=await fetch(r,{method:"POST",body:JSON.stringify(c),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{C as askAiHandler};
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import type { Context, Handler } from 'hono';
|
|
2
2
|
import type { Store } from '../../store.js';
|
|
3
|
+
import { ServerRoutes } from '../../../constants/common.js';
|
|
3
4
|
export declare function authorizeHandler(ctx: Context): Promise<Response>;
|
|
4
5
|
export declare function redoclyLoginCallbackHandler(): Handler;
|
|
5
6
|
export declare function oidcCallbackHandler(store: Store): Handler;
|
|
6
7
|
export declare function logoutHandler(store: Store): (ctx: Context) => Promise<Response>;
|
|
7
8
|
export declare function postLogoutHandler(store: Store): (ctx: Context) => Promise<Response>;
|
|
8
|
-
export declare function inviteHandler(store: Store): (ctx: Context) => Promise<Response>;
|
|
9
|
+
export declare function inviteHandler(store: Store): (ctx: Context<Record<string, unknown>, typeof ServerRoutes.INVITE>) => Promise<Response>;
|
|
9
10
|
export declare function idpLoginHandler(store: Store): (ctx: Context) => Promise<Response>;
|
|
10
11
|
export declare function samlCallbackHandler(store: Store): Handler;
|
|
11
12
|
export declare function redoclyTokenLoginHandler(store: Store): Handler;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{setCookie as _,deleteCookie as q}from"hono/cookie";import{AuthProviderType as W}from"@redocly/config";import{withPathPrefix as I,getPathPrefix as R}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 F,JWT_SECRET_KEY as v,ORG_SLUG as Q,ORG_ID as Z}from"../../constants/common.js";import{DEFAULT_COOKIE_EXPIRATION as B,ServerRoutes as S}from"../../../constants/common.js";import{sanitizeRedirectPathname as z}from"../../../utils/url/sanitize-redirect-pathname.js";import{telemetry as M}from"../../telemetry/index.js";import{envConfig as H}from"../../config/env-config.js";import{getAuthProviderLoginParams as x,isOidcProviderConfig as $,isSaml2ProviderConfig as ee,oidcExchangeCodeForToken as re,buildLoginUrl as oe,decodeSamlResponse as ne,extractUserClaims as te,parseSamlResponse as ie,parseOidcState as se,verifySAMLResponse as ae,getUsernameFromPayload as de,buildOidcLogoutUrl as ce,getOidcMetadata as j,getRedoclyTokenPayload as le,isRedoclySso as ue,rewritePreviewAuthRedirectUri as pe,parsePreviewBranch as N,buildOidcLoginUrl as ge,createMcpSessionResource as k}from"../auth.js";import*as O from"../jwt/jwt.js";import{AlgorithmTypes as P}from"../jwt/types.js";import{handleErrorPageRender as fe}from"../utils.js";import{encodeBase64URL as me}from"../jwt/encode.js";async function ve(i){if(H.isProductionEnv)return i.newResponse(null,404,{});const{password:e,...r}=await i.req.json(),a=await O.sign({...r,name:r.username||r.email||"Unknown"},v,P.HS256);return _(i,"authorization",a,{path:R()||"/",httpOnly:!0,secure:!0,sameSite:"none"}),i.newResponse(null,200,{})}function $e(){return async i=>{const e=i.get("logger"),r=encodeURIComponent(i.req.query("message")||"");e.error(`Login error: ${r}`);const a=`${S.LOGIN}/?error=${encodeURIComponent(r)}`;return i.newResponse(null,301,{Location:a})}}function K(i){if(!i||!i.includes(S.MCP_CALLBACK))return null;try{const e=i.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 Ue(i){return async e=>{const r=e.get("logger"),a=i.getConfig().ssoDirect,n=se(e.req.query("state")),f=n.idpId,t=n.source==="mcp"||n.redirectTo&&typeof n.redirectTo=="string"&&n.redirectTo.includes(S.MCP_CALLBACK),c=t?K(typeof n.redirectTo=="string"?n.redirectTo:void 0):null,s=a?.[f];if(!$(s))return r.error("OIDC login error: missing OIDC provider config"),e.text("Forbidden",403);const d=await j(f,s);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,l=e.req.query("code"),m=e.req.query("error");if(m)return t&&M.sendMcpAuthorizationFailedMessage([{...k(c),error:`OIDC error: ${m}`,error_details:e.req.query("error_description")||null}]),fe(e,i,{slug:"/"},403,"403OIDC");if(!l){const w="Code is expected but not present";return r.error(`OIDC login error: ${w}`),t&&M.sendMcpAuthorizationFailedMessage([{...k(c),error:w,error_details:null}]),new Response(`Forbidden: ${w}`,{status:403})}const h=e.req.header("x-forwarded-host"),g=e.req.header("x-forwarded-proto")||"https",A=t&&typeof n.redirectUri=="string"?n.redirectUri:new URL(I(S.OIDC_CALLBACK),h?`${g}://${h}`:e.req.url).toString(),C=e.get("cookies")?.code_verifier,u=await re(p,l,A,s,{...s.tokenRequestCustomParams,...C?{code_verifier:C}:{}});if(u.error)return r.error(`Error from OIDC provider: "${u.error}"`),t&&M.sendMcpAuthorizationFailedMessage([{...k(c),error:`Token exchange error: ${u.error}`,error_details:u.error_description||null}]),e.text(`Forbidden: ${u.error_description||u.error}`,403);if(!u?.id_token){const w="No id_token, please, add openid to scopes";return r.error(`OIDC login error: ${w}`),t&&M.sendMcpAuthorizationFailedMessage([{...k(c),error:w,error_details:null}]),new Response(`Forbidden: ${w}`,{status:403})}const{payload:o,header:U}=O.decode(u.id_token),J=U.alg===P.RS256;if(s.audience?.length&&![...b(o.aud||[]),...b(o[F]||[])].some(L=>s.audience?.includes(L))){const L="No valid audience found in id_token";return r.error(`OIDC login error: ${L}`),t&&M.sendMcpAuthorizationFailedMessage([{...k(c),error:L,error_details:null}]),new Response(`Forbidden: ${L}`)}const E=J?u.id_token:await O.sign({...o,idpId:f},v,P.HS256);de(o)||r.warn("To display your username, the required 'email' or 'full_profile' scope must be added to the identity provider configuration");const D=s?.tokenExpirationTime?Date.now()+s.tokenExpirationTime*1e3:o.exp*1e3||Date.now()+B*1e3;if(s.introspectEndpoint){const w=await fetch(s.introspectEndpoint,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({access_token:u.access_token})});if(w.ok){const T=(await w.json()).ext?.federatedIdentity;T&&(_(e,"federated_access_token",T.access_token||"",{path:R()||"/",httpOnly:!1,expires:new Date(D)}),_(e,"federated_id_token",T.id_token||"",{path:R()||"/",httpOnly:!1,expires:new Date(D)}))}else r.warn(`OIDC introspect error: ${w.statusText}`)}if(_(e,"authorization",E,{path:R()||"/",httpOnly:!0,expires:new Date(D)}),E!==u.id_token&&_(e,"idp_id_token",u.id_token||"",{path:R()||"/",httpOnly:!0,expires:new Date(D)}),_(e,"idp_access_token",u.access_token||"",{path:R()||"/",httpOnly:!0,expires:new Date(D)}),q(e,"code_verifier",{path:R()||"/"}),t&&n.redirectTo&&typeof n.redirectTo=="string"&&n.redirectTo.includes(S.MCP_CALLBACK)){const L=`${e.req.url.split("?")[0].replace(S.OIDC_CALLBACK,"")}${n.redirectTo}`;return e.newResponse(null,302,{Location:L})}const G=typeof n.redirectTo=="string"?n.redirectTo:void 0;let V=z(new URL(G||"/",e.req.url).pathname);const X=e.newResponse(null,302,{Location:V});return r.updateContext({email:o.email,subject:o.sub}),r.info("OIDC login successful"),X}catch(p){const l=p instanceof Error?p.message:String(p),m=p instanceof Error?p.stack:String(p);if(r.error(`OIDC login error: ${l}`),t&&M.sendMcpAuthorizationFailedMessage([{...k(c),error:l,error_details:m}]),p.error==="access_denied")return r.info("Access denied"),e.text("Forbidden",403)}const y="Something went wrong";return r.error(`OIDC login error: ${y}`),t&&M.sendMcpAuthorizationFailedMessage([{...k(c),error:y,error_details:null}]),e.text(y,500)}}function Te(i){return async e=>{const r=e.get("logger"),n=e.get("auth").claims?.idpId,t=i.getConfig().ssoDirect?.[n];if(e.req.method==="POST")return $(t)||q(e,"authorization",{path:R()||"/"}),r.info("Logout successful"),e.newResponse(null,200,{});let c;if($(t)){const s=(await j(n,t)).end_session_endpoint;if(s){const d=new URL(e.req.url),y=e.req.header("x-forwarded-proto")||d.protocol.slice(0,-1)||"https",p=e.req.header("x-forwarded-host")||d.host,l=`${y}://${p}`,m=N(l),h=m?me(JSON.stringify({branch:N(l)})):void 0,g=m?`${pe(l)}/_auth/logout`:`${l}/post-logout`;c=ce(s,g,e.get("cookies")?.idp_id_token||e.get("cookies")?.authorization||"",h)}}return r.info("Logout successful"),q(e,"authorization",{path:R()||"/"}),e.newResponse(null,302,{Location:c||I("/")})}}function qe(i){return async e=>{const r=i.getConfig().logoutReturnUrl,a=r||I("/");return e.newResponse(null,302,{Location:a})}}function be(i){return async e=>{const r=e.get("logger"),a=e.req.param("code"),n=H.BH_API_URL,f=(t,c,s)=>t&&c?`${t} ${c.charAt(0)}`:s;try{if(!n)throw new Error("BH_API_URL is not set");const t=i.getConfig().ssoDirect;if(!t||!Object.keys(t).length)return r.warn("Invite no sso configured to handle"),e.redirect(I("/"));const c=await fetch(`${n}/user-invites/public/${a}`);if(!c.ok)return c.status===404?(r.warn(`Invite ${a} not found redirect to homepage`),e.redirect(I("/"))):(r.error("Invite error",await c.text()),e.redirect(I("/")));const s=await c.json(),d=new URL(I("/invite"),e.req.url);return d.searchParams.set("code",a),d.searchParams.set("org",s.organization.name),d.searchParams.set("invitedBy",f(s.invitedBy.firstName,s.invitedBy.lastName,s.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 Ee(i){return async e=>{const r=e.get("logger"),a=i.getConfig().ssoDirect,n=new URL(e.req.url),f=e.req.query("inviteCode"),t=e.req.header("x-forwarded-proto")||n.protocol.slice(0,-1)||"https",c=e.req.header("x-forwarded-host")||n.host,s=`${t}://${c}`;let d=n.searchParams.get("idpId");const y=n.searchParams.get("redirectTo"),p=Object.keys(a||{})[0];d=d||p;const l=n.searchParams.get("mcp_redirect_uri"),m=!!l;if(!a?.[d]){const o="Invalid idpId";if(r.error(`IdP login error: ${o}`),m){const U=K(y||void 0);M.sendMcpAuthorizationFailedMessage([{...k(U),error:o,error_details:null}])}return e.text(`Forbidden: ${o}`,403)}const g=d&&a?await x(d,a[d]):void 0,A={};for(const o of Object.keys(g?.extraParams||{}))A[o]=n.searchParams.get(o)||g?.extraParams?.[o]||void 0;let C,u={};if(m&&l&&g&&g.type===W.OIDC){r.info(`Building MCP OAuth login URL with redirect_uri: ${l}`);const o=ge("",{...g,extraParams:A},y,f,{redirectUriOverride:l,sourceOverride:"mcp",branchOverride:void 0});C=o.loginUrl,u=o.cookies||{}}else if(g){const o=oe({...g,extraParams:A},s,y,f);C=o.loginUrl,u=o.cookies||{}}return Object.keys(u).forEach(o=>{_(e,o,u[o].value,u[o].options)}),r.info(`IdP login initiated for ID '${d}'`),e.newResponse(null,302,{Location:C||new URL(e.req.url).pathname})}}function Fe(i){return async e=>{const r=e.get("logger"),a=await e.req.formData(),n=a.get("SAMLResponse"),f=a.get("RelayState");if(typeof n!="string"||typeof f!="string"){const o="SAMLResponse is required";return r.error(`SAML2 login error: ${o}`),e.text(`Bad request: ${o}`,400)}const t=ne(n),{success:c,uid:s,nameFormat:d,attrs:y,issuerId:p,expiresAt:l}=ie(t),{idpId:m,redirectTo:h}=JSON.parse(f);if(!c){const o="SAML2 assertion is not successful";return r.error(`SAML2 login error: ${o}`),e.text(`Permission denied: ${o}`,401)}if(!l||Math.ceil(Date.now()/1e3)>=l){const o="SAML2 Token Expired";return r.error(`SAML2 login error: ${o}`),e.text(o,401)}const g=i.getConfig().ssoDirect?.[m];if(!g||!ee(g)){const o="Cannot find valid IdP";return r.error(`SAML2 login error: ${o}`),e.text(`Permission denied: ${o}`,401)}if(!(g.issuerId&&p&&Y(g.issuerId,p))){const o="IssuerID is misconfigured or untrusted assertions issuer received";return r.error(`SAML2 login error: ${o}`),e.text(`Permission denied: ${o}`,401)}if(!await ae(t,g.x509PublicCert)){const o="SAMLResponse signature invalid";return r.error(`SAML2 login error: ${o}`),e.text(o,401)}const C=te(s,d,y,g.teamsAttributeName);if(!C.sub){const o="The provider did not return a valid user identity.";return r.error(`SAML2 login error: ${o}`),e.text(o,400)}if(!C.email){const o="The provider did not return a valid user email.";return r.error(`SAML2 login error: ${o}`),e.text(o,400)}const u=await O.sign({...C,idpId:m},v,P.HS256);return _(e,"authorization",u,{path:R()||"/",httpOnly:!0,expires:new Date(l*1e3)}),r.updateContext({email:C.email,subject:C.sub}),r.info("SAML2 login successful"),e.newResponse(null,302,{Location:h||"/"})}}function Be(i){return async e=>{const r=e.get("logger"),a=new URL(e.req.query("redirectTo")||"/",e.req.url),n=I(z(a.pathname)),f=i.getConfig().ssoDirect,t=Object.entries(f||{}).find(([,h])=>$(h)&&ue(h));if(!(f&&t))return e.newResponse(null,302,{Location:n});const s=e.req.query("token"),d=s&&await le(s);if(!d)return e.newResponse(null,302,{Location:n});if(!b(d[F]||[]).some(h=>h===Q||h===Z))return e.newResponse(null,302,{Location:n});const l=await O.sign({...d,idpId:t?.at(0)},v,P.HS256),m=Date.now()+B*1e3;return _(e,"authorization",l,{path:R()||"/",httpOnly:!0,expires:new Date(m),sameSite:"None",secure:!0}),r.info("Token login successful"),e.newResponse(null,302,{Location:n})}}export{ve as authorizeHandler,Ee as idpLoginHandler,be as inviteHandler,Te as logoutHandler,Ue as oidcCallbackHandler,qe as postLogoutHandler,$e as redoclyLoginCallbackHandler,Be as redoclyTokenLoginHandler,Fe as samlCallbackHandler};
|
|
1
|
+
import{setCookie as _,deleteCookie as q}from"hono/cookie";import{AuthProviderType as W}from"@redocly/config";import{withPathPrefix as I,getPathPrefix as R}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 F,JWT_SECRET_KEY as v,ORG_SLUG as Q,ORG_ID as Z}from"../../constants/common.js";import{DEFAULT_COOKIE_EXPIRATION as B,ServerRoutes as S}from"../../../constants/common.js";import{sanitizeRedirectPathname as z}from"../../../utils/url/sanitize-redirect-pathname.js";import{telemetry as M}from"../../telemetry/index.js";import{envConfig as H}from"../../config/env-config.js";import{getAuthProviderLoginParams as x,isOidcProviderConfig as $,isSaml2ProviderConfig as ee,oidcExchangeCodeForToken as re,buildLoginUrl as oe,decodeSamlResponse as ne,extractUserClaims as te,parseSamlResponse as ie,parseOidcState as se,verifySAMLResponse as ae,getUsernameFromPayload as de,buildOidcLogoutUrl as ce,getOidcMetadata as j,getRedoclyTokenPayload as le,isRedoclySso as ue,rewritePreviewAuthRedirectUri as pe,parsePreviewBranch as N,buildOidcLoginUrl as ge,createMcpSessionResource as k}from"../auth.js";import*as O from"../jwt/jwt.js";import{AlgorithmTypes as P}from"../jwt/types.js";import{handleErrorPageRender as fe}from"../utils.js";import{encodeBase64URL as me}from"../jwt/encode.js";async function ve(i){if(H.isProductionEnv)return i.newResponse(null,404,{});const{password:e,...r}=await i.req.json(),a=await O.sign({...r,name:r.username||r.email||"Unknown"},v,P.HS256);return _(i,"authorization",a,{path:R()||"/",httpOnly:!0,secure:!0,sameSite:"none"}),i.newResponse(null,200,{})}function $e(){return async i=>{const e=i.get("logger"),r=encodeURIComponent(i.req.query("message")||"");e.error(`Login error: ${r}`);const a=`${S.LOGIN}/?error=${encodeURIComponent(r)}`;return i.newResponse(null,301,{Location:a})}}function K(i){if(!i||!i.includes(S.MCP_CALLBACK))return null;try{const e=i.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 Ue(i){return async e=>{const r=e.get("logger"),a=i.getConfig().ssoDirect,n=se(e.req.query("state")),f=n.idpId,t=n.source==="mcp"||n.redirectTo&&typeof n.redirectTo=="string"&&n.redirectTo.includes(S.MCP_CALLBACK),c=t?K(typeof n.redirectTo=="string"?n.redirectTo:void 0):null,s=a?.[f];if(!$(s))return r.error("OIDC login error: missing OIDC provider config"),e.text("Forbidden",403);const d=await j(f,s);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,l=e.req.query("code"),m=e.req.query("error");if(m)return t&&M.sendMcpAuthorizationFailedMessage([{...k(c),error:`OIDC error: ${m}`,error_details:e.req.query("error_description")||null}]),fe(e,i,{slug:"/"},403,"403OIDC");if(!l){const w="Code is expected but not present";return r.error(`OIDC login error: ${w}`),t&&M.sendMcpAuthorizationFailedMessage([{...k(c),error:w,error_details:null}]),new Response(`Forbidden: ${w}`,{status:403})}const h=e.req.header("x-forwarded-host"),g=e.req.header("x-forwarded-proto")||"https",A=t&&typeof n.redirectUri=="string"?n.redirectUri:new URL(I(S.OIDC_CALLBACK),h?`${g}://${h}`:e.req.url).toString(),C=e.get("cookies")?.code_verifier,u=await re(p,l,A,s,{...s.tokenRequestCustomParams,...C?{code_verifier:C}:{}});if(u.error)return r.error(`Error from OIDC provider: "${u.error}"`),t&&M.sendMcpAuthorizationFailedMessage([{...k(c),error:`Token exchange error: ${u.error}`,error_details:u.error_description||null}]),e.text(`Forbidden: ${u.error_description||u.error}`,403);if(!u?.id_token){const w="No id_token, please, add openid to scopes";return r.error(`OIDC login error: ${w}`),t&&M.sendMcpAuthorizationFailedMessage([{...k(c),error:w,error_details:null}]),new Response(`Forbidden: ${w}`,{status:403})}const{payload:o,header:U}=O.decode(u.id_token),J=U.alg===P.RS256;if(s.audience?.length&&![...b(o.aud||[]),...b(o[F]||[])].some(L=>s.audience?.includes(L))){const L="No valid audience found in id_token";return r.error(`OIDC login error: ${L}`),t&&M.sendMcpAuthorizationFailedMessage([{...k(c),error:L,error_details:null}]),new Response(`Forbidden: ${L}`)}const E=J?u.id_token:await O.sign({...o,idpId:f},v,P.HS256);de(o)||r.warn("To display your username, the required 'email' or 'full_profile' scope must be added to the identity provider configuration");const D=s?.tokenExpirationTime?Date.now()+s.tokenExpirationTime*1e3:o.exp*1e3||Date.now()+B*1e3;if(s.introspectEndpoint){const w=await fetch(s.introspectEndpoint,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({access_token:u.access_token})});if(w.ok){const T=(await w.json()).ext?.federatedIdentity;T&&(_(e,"federated_access_token",T.access_token||"",{path:R()||"/",httpOnly:!1,expires:new Date(D)}),_(e,"federated_id_token",T.id_token||"",{path:R()||"/",httpOnly:!1,expires:new Date(D)}))}else r.warn(`OIDC introspect error: ${w.statusText}`)}if(_(e,"authorization",E,{path:R()||"/",httpOnly:!0,expires:new Date(D)}),E!==u.id_token&&_(e,"idp_id_token",u.id_token||"",{path:R()||"/",httpOnly:!0,expires:new Date(D)}),_(e,"idp_access_token",u.access_token||"",{path:R()||"/",httpOnly:!0,expires:new Date(D)}),q(e,"code_verifier",{path:R()||"/"}),t&&n.redirectTo&&typeof n.redirectTo=="string"&&n.redirectTo.includes(S.MCP_CALLBACK)){const L=`${e.req.url.split("?")[0].replace(S.OIDC_CALLBACK,"")}${n.redirectTo}`;return e.newResponse(null,302,{Location:L})}const G=typeof n.redirectTo=="string"?n.redirectTo:void 0;let V=z(new URL(G||"/",e.req.url).pathname);const X=e.newResponse(null,302,{Location:V});return r.updateContext({email:o.email,subject:o.sub}),r.info("OIDC login successful"),X}catch(p){const l=p instanceof Error?p.message:String(p),m=p instanceof Error?p.stack:String(p);if(r.error(`OIDC login error: ${l}`),t&&M.sendMcpAuthorizationFailedMessage([{...k(c),error:l,error_details:m}]),p.error==="access_denied")return r.info("Access denied"),e.text("Forbidden",403)}const y="Something went wrong";return r.error(`OIDC login error: ${y}`),t&&M.sendMcpAuthorizationFailedMessage([{...k(c),error:y,error_details:null}]),e.text(y,500)}}function Te(i){return async e=>{const r=e.get("logger"),n=e.get("auth").claims?.idpId,t=i.getConfig().ssoDirect?.[n];if(e.req.method==="POST")return $(t)||q(e,"authorization",{path:R()||"/"}),r.info("Logout successful"),e.newResponse(null,200,{});let c;if($(t)){const s=(await j(n,t)).end_session_endpoint;if(s){const d=new URL(e.req.url),y=e.req.header("x-forwarded-proto")||d.protocol.slice(0,-1)||"https",p=e.req.header("x-forwarded-host")||d.host,l=`${y}://${p}`,m=N(l),h=m?me(JSON.stringify({branch:N(l)})):void 0,g=m?`${pe(l)}/_auth/logout`:`${l}/post-logout`;c=ce(s,g,e.get("cookies")?.idp_id_token||e.get("cookies")?.authorization||"",h)}}return r.info("Logout successful"),q(e,"authorization",{path:R()||"/"}),e.newResponse(null,302,{Location:c||I("/")})}}function qe(i){return async e=>{const r=i.getConfig().access?.logoutReturnUrl,a=r||I("/");return e.newResponse(null,302,{Location:a})}}function be(i){return async e=>{const r=e.get("logger"),a=e.req.param("code"),n=H.BH_API_URL,f=(t,c,s)=>t&&c?`${t} ${c.charAt(0)}`:s;try{if(!n)throw new Error("BH_API_URL is not set");const t=i.getConfig().ssoDirect;if(!t||!Object.keys(t).length)return r.warn("Invite no sso configured to handle"),e.redirect(I("/"));const c=await fetch(`${n}/user-invites/public/${a}`);if(!c.ok)return c.status===404?(r.warn(`Invite ${a} not found redirect to homepage`),e.redirect(I("/"))):(r.error("Invite error",await c.text()),e.redirect(I("/")));const s=await c.json(),d=new URL(I("/invite"),e.req.url);return d.searchParams.set("code",a),d.searchParams.set("org",s.organization.name),d.searchParams.set("invitedBy",f(s.invitedBy.firstName,s.invitedBy.lastName,s.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 Ee(i){return async e=>{const r=e.get("logger"),a=i.getConfig().ssoDirect,n=new URL(e.req.url),f=e.req.query("inviteCode"),t=e.req.header("x-forwarded-proto")||n.protocol.slice(0,-1)||"https",c=e.req.header("x-forwarded-host")||n.host,s=`${t}://${c}`;let d=n.searchParams.get("idpId");const y=n.searchParams.get("redirectTo"),p=Object.keys(a||{})[0];d=d||p;const l=n.searchParams.get("mcp_redirect_uri"),m=!!l;if(!a?.[d]){const o="Invalid idpId";if(r.error(`IdP login error: ${o}`),m){const U=K(y||void 0);M.sendMcpAuthorizationFailedMessage([{...k(U),error:o,error_details:null}])}return e.text(`Forbidden: ${o}`,403)}const g=d&&a?await x(d,a[d]):void 0,A={};for(const o of Object.keys(g?.extraParams||{}))A[o]=n.searchParams.get(o)||g?.extraParams?.[o]||void 0;let C,u={};if(m&&l&&g&&g.type===W.OIDC){r.info(`Building MCP OAuth login URL with redirect_uri: ${l}`);const o=ge("",{...g,extraParams:A},y,f,{redirectUriOverride:l,sourceOverride:"mcp",branchOverride:void 0});C=o.loginUrl,u=o.cookies||{}}else if(g){const o=oe({...g,extraParams:A},s,y,f);C=o.loginUrl,u=o.cookies||{}}return Object.keys(u).forEach(o=>{_(e,o,u[o].value,u[o].options)}),r.info(`IdP login initiated for ID '${d}'`),e.newResponse(null,302,{Location:C||new URL(e.req.url).pathname})}}function Fe(i){return async e=>{const r=e.get("logger"),a=await e.req.formData(),n=a.get("SAMLResponse"),f=a.get("RelayState");if(typeof n!="string"||typeof f!="string"){const o="SAMLResponse is required";return r.error(`SAML2 login error: ${o}`),e.text(`Bad request: ${o}`,400)}const t=ne(n),{success:c,uid:s,nameFormat:d,attrs:y,issuerId:p,expiresAt:l}=ie(t),{idpId:m,redirectTo:h}=JSON.parse(f);if(!c){const o="SAML2 assertion is not successful";return r.error(`SAML2 login error: ${o}`),e.text(`Permission denied: ${o}`,401)}if(!l||Math.ceil(Date.now()/1e3)>=l){const o="SAML2 Token Expired";return r.error(`SAML2 login error: ${o}`),e.text(o,401)}const g=i.getConfig().ssoDirect?.[m];if(!g||!ee(g)){const o="Cannot find valid IdP";return r.error(`SAML2 login error: ${o}`),e.text(`Permission denied: ${o}`,401)}if(!(g.issuerId&&p&&Y(g.issuerId,p))){const o="IssuerID is misconfigured or untrusted assertions issuer received";return r.error(`SAML2 login error: ${o}`),e.text(`Permission denied: ${o}`,401)}if(!await ae(t,g.x509PublicCert)){const o="SAMLResponse signature invalid";return r.error(`SAML2 login error: ${o}`),e.text(o,401)}const C=te(s,d,y,g.teamsAttributeName);if(!C.sub){const o="The provider did not return a valid user identity.";return r.error(`SAML2 login error: ${o}`),e.text(o,400)}if(!C.email){const o="The provider did not return a valid user email.";return r.error(`SAML2 login error: ${o}`),e.text(o,400)}const u=await O.sign({...C,idpId:m},v,P.HS256);return _(e,"authorization",u,{path:R()||"/",httpOnly:!0,expires:new Date(l*1e3)}),r.updateContext({email:C.email,subject:C.sub}),r.info("SAML2 login successful"),e.newResponse(null,302,{Location:h||"/"})}}function Be(i){return async e=>{const r=e.get("logger"),a=new URL(e.req.query("redirectTo")||"/",e.req.url),n=I(z(a.pathname)),f=i.getConfig().ssoDirect,t=Object.entries(f||{}).find(([,h])=>$(h)&&ue(h));if(!(f&&t))return e.newResponse(null,302,{Location:n});const s=e.req.query("token"),d=s&&await le(s);if(!d)return e.newResponse(null,302,{Location:n});if(!b(d[F]||[]).some(h=>h===Q||h===Z))return e.newResponse(null,302,{Location:n});const l=await O.sign({...d,idpId:t?.at(0)},v,P.HS256),m=Date.now()+B*1e3;return _(e,"authorization",l,{path:R()||"/",httpOnly:!0,expires:new Date(m),sameSite:"None",secure:!0}),r.info("Token login successful"),e.newResponse(null,302,{Location:n})}}export{ve as authorizeHandler,Ee as idpLoginHandler,be as inviteHandler,Te as logoutHandler,Ue as oidcCallbackHandler,qe as postLogoutHandler,$e as redoclyLoginCallbackHandler,Be as redoclyTokenLoginHandler,Fe as samlCallbackHandler};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{telemetryTraceStep as o}from"../../../telemetry/helpers/trace-step.js";import{CATALOG_ENTITY_KEY as d}from"../../../../constants/common.js";import{ALLOWED_CATALOG_QUERY_PARAMS as y}from"../../../constants/plugins/catalog-entities.js";import{allowlistObject as
|
|
1
|
+
import{telemetryTraceStep as o}from"../../../telemetry/helpers/trace-step.js";import{CATALOG_ENTITY_KEY as d}from"../../../../constants/common.js";import{ALLOWED_CATALOG_QUERY_PARAMS as y}from"../../../constants/plugins/catalog-entities.js";import{allowlistObject as f}from"../../../../utils/object/allowlist-object.js";import{CatalogEntitiesService as g}from"../../../plugins/catalog-entities/database/catalog-entities-service.js";import{createPaginationParamsValidator as E}from"../../../providers/database/pagination/schemas.js";import{ENTITY_RELATION_TO_DATABASE as _}from"../../../plugins/catalog-entities/database/mappers/field-transformations.js";import{getRbacRestrictionsDataForCatalog as A}from"../helpers/get-rbac-restrictions-data-for-catalog.js";const b=["id","key","title","type","summary","source","source_file","created_at","updated_at","relation_type","version","revision"],p=async({catalogEntitiesService:i,store:a,ctx:e})=>o("catalog_entities.bff.related_entities.get_related_entities",async t=>{try{const r=e.req.param(d);if(!r)return t?.error(new Error("Entity key is required")),e.json({message:"Entity key is required"},400);t?.setAttribute("pathParams",JSON.stringify({entityKey:r}));const s=e.req.query();t?.setAttribute("queryParams",JSON.stringify(f(s,y)));const m=E(b,_).parse(s),{currentRbacTeamsForRead:l,excludedTypes:c,excludedEntities:u}=A({store:a,ctx:e}),n=await i.getRelatedEntities({entityKey:r,paginationParams:m,rbacTeams:l,excludedTypes:c,excludedEntities:u});return t?.setAttribute("relatedEntitiesCount",n.items.length),e.json(n)}catch(r){return console.error(r),t?.error(r),e.json({message:r.message},500)}});function v(i){return async a=>o("catalog_entities.bff.related_entities",async e=>{e?.setAttribute("method",a.req.method);const t=await g.getInstance({baseDbDir:i.serverOutDir});return p({catalogEntitiesService:t,ctx:a,store:i})})}export{v as bffCatalogRelatedEntitiesHandler};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{telemetryTraceStep as d}from"../../../telemetry/helpers/trace-step.js";import{CATALOG_ENTITY_KEY as g}from"../../../../constants/common.js";import{ALLOWED_CATALOG_QUERY_PARAMS as p}from"../../../constants/plugins/catalog-entities.js";import{allowlistObject as E}from"../../../../utils/object/allowlist-object.js";import{CatalogEntitiesService as b}from"../../../plugins/catalog-entities/database/catalog-entities-service.js";import{createPaginationParamsValidator as v}from"../../../providers/database/pagination/schemas.js";import{isValidIsoDate as
|
|
1
|
+
import{telemetryTraceStep as d}from"../../../telemetry/helpers/trace-step.js";import{CATALOG_ENTITY_KEY as g}from"../../../../constants/common.js";import{ALLOWED_CATALOG_QUERY_PARAMS as p}from"../../../constants/plugins/catalog-entities.js";import{allowlistObject as E}from"../../../../utils/object/allowlist-object.js";import{CatalogEntitiesService as b}from"../../../plugins/catalog-entities/database/catalog-entities-service.js";import{createPaginationParamsValidator as v}from"../../../providers/database/pagination/schemas.js";import{isValidIsoDate as q}from"../../../utils/is-valid-iso-date.js";import{isValidSanitizedString as A}from"../../../utils/validate-and-sanitize-string.js";import{getRbacRestrictionsDataForCatalog as l}from"../helpers/get-rbac-restrictions-data-for-catalog.js";const _=["type","key","title","summary","tags","metadata","metadata.*","git","contact","links","id","source","source_file","version","revision","created_at","updated_at","domains","owners"],h=async({catalogEntitiesService:r,ctx:e,store:n})=>d("catalog_entities.bff.get_entities",async t=>{const i=e.req.query();t?.setAttribute("queryParams",JSON.stringify(E(i,p)));const a=v(_).parse(i),{currentRbacTeamsForRead:s,excludedTypes:o,excludedEntities:u}=l({store:n,ctx:e}),m=await r.getEntitiesWithRelations({paginationParams:a,rbacTeams:s,excludedTypes:o,excludedEntities:u});return t?.setAttribute("entitiesCount",m.items.length),e.json(m)}),w=async({catalogEntitiesService:r,ctx:e,store:n})=>d("catalog_entities.bff.get_entity",async t=>{const i=e.req.param(g);if(!i)return t?.error(new Error("Entity key is required")),e.json({message:"Entity key is required"},400);const a=e.req.query("revision");let s=null;if(a){if(!q(a))return t?.error(new Error("Invalid revision parameter")),e.json({message:"Invalid revision parameter: must be a valid ISO 8601 date-time string"},400);s=a}const o=e.req.query("version");if(!A(o,{pattern:/^[a-zA-Z0-9._-]+$/,maxLength:100,allowEmpty:!0}))return t?.error(new Error("Invalid version parameter")),e.json({message:"Invalid version parameter: version must contain only alphanumeric characters, dots, hyphens, and underscores, and must not exceed 100 characters"},400);const u=e.req.query();t?.setAttribute("queryParams",JSON.stringify(u)),t?.setAttribute("pathParams",JSON.stringify({entityKey:i}));const{currentRbacTeamsForRead:m,excludedTypes:c,excludedEntities:f}=l({store:n,ctx:e}),y=await r.getEntityWithRelationsByKey({entityKey:i,filter:{revision:s,version:o},rbacTeams:m,excludedTypes:c,excludedEntities:f});return y?(t?.setAttribute("entity",JSON.stringify(y)),e.json(y)):(t?.error(new Error("Entity not found")),e.json({message:"Entity not found"},404))});function L(r){return async e=>d("catalog_entities.bff",async n=>{n?.setAttribute("method",e.req.method);const t=await b.getInstance({baseDbDir:r.serverOutDir});return e.req.param("entityKey")?w({catalogEntitiesService:t,ctx:e,store:r}):h({catalogEntitiesService:t,ctx:e,store:r})})}export{L as bffCatalogHandler};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{getNotAccessibleCatalogResources as
|
|
1
|
+
import{getNotAccessibleCatalogResources as u}from"../../../../plugins/catalog-entities/utils/get-not-accessible-catalog-resources.js";import{getCurrentRbacTeams as f}from"../../helpers/get-current-rbac-teams.js";function g({ctx:e,store:t,accessLevel:s,entityType:c,entityKey:r}){const n=t.getConfig().access?.rbac||{},o=f(e),{types:i,entities:a}=u({rbacConfig:n,currentRbacTeams:o,accessLevel:s});return!(i.includes(c)||a.includes(r))}export{g as hasAccessToEntity};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import
|
|
1
|
+
import l from"path";import{REDOCLY_ROUTE_RBAC as y,REDOCLY_TEAMS_RBAC as I}from"@redocly/config";import{withoutPathPrefix as G,withPathPrefix as Y}from"@redocly/theme/core/utils";import{CACHE_CONTROL_NO_CACHE_HEADER_VALUE as S,DEFAULT_IMMUTABLE_CACHE_MAX_AGE as $}from"../../constants/common.js";import{removeTrailingSlash as k}from"../../../utils/url/remove-trailing-slash.js";import{findInIterable as N}from"../../../utils/collection/find-in-iterable.js";import{sanitizeRedirectPathname as W}from"../../../utils/url/sanitize-redirect-pathname.js";import{envConfig as X}from"../../config/env-config.js";import{sanitizePath as j}from"../../../utils/path/sanitize-path.js";import{normalizeRouteSlug as V}from"../../../utils/path/normalize-route-slug.js";import{isPathInFolder as Z}from"../../../utils/path/is-path-in-folder.js";import{getLlmsTxtMdPathBySlug as J}from"../../utils/llmstxt/get-llms-txt-md-path-by-slug.js";import{removeLeadingSlash as T}from"../../../utils/url/remove-leading-slash.js";import{processRedirects as K}from"./helpers/process-redirects.js";import{renderPage as Q,getServerProps as x}from"../../ssr/index.js";import{canAccessAsset as ee,canAccessResource as U}from"../../utils/rbac.js";import{handleErrorPageRender as M,handleUnauthorized as b,handleUnauthorizedAsset as q}from"../utils.js";import{DEFAULT_MAX_AGE_FOR_MIME_TYPE as te,MIME_TYPES as ne}from"../mime-types.js";import{fileExistsAsync as v}from"../../utils/index.js";import{isAiAgentRequest as oe}from"../../utils/ai-agent-detection.js";import{getRedirectRoute as re}from"../utils/legacy-openapi-redirects.js";import{telemetry as ae}from"../../../cli/telemetry/index.js";import{telemetry as ie}from"../../telemetry/index.js";function qe(e,D,O){return async n=>{const A=n.get("logger"),a=n.req,i=new URL(a.url),r=G(j(decodeURIComponent(i.pathname))),R=l.parse(r).ext===".md",C=oe({accept:a.header("accept"),signatureAgent:a.header("signature-agent"),signature:a.header("signature"),signatureInput:a.header("signature-input"),userAgent:a.header("user-agent")}),m=V(r),o=(a.method==="GET"||a.method==="HEAD")&&!R?e.getRouteBySlug(m,{followRedirect:!1})||N(e.routesBySlug?.values(),t=>t.hasClientRoutes&&(r===t.slug||r.startsWith(t.slug+"/"))):void 0,E=e.getRedirect(m);if(E){const t=K({redirect:E,reqUrlSearch:i.search});return ie.sendRedirectMessage([{object:"redirect",from:m,templateId:t.type.toString()}]),n.newResponse(null,t.type,{Location:t.location})}const f=X.isProductionEnv?301:302;if(o?.metadata?.type==="openapi"){const t=re(i.pathname);if(t)return A.info("Legacy OpenAPI docs redirect from "+i.pathname),n.newResponse(null,f,{Location:encodeURI(t)});if(i.pathname.match(/[A-Z]/))return A.warn("Redirect to lowercase route to avoid 404 error"),n.newResponse(null,f,{Location:encodeURI(i.pathname.toLowerCase())})}if(r.endsWith("/")&&r!=="/"){const t=W(new URL(m||"/",n.req.url).pathname);return n.newResponse(null,f,{Location:encodeURI(Y((t==="/"?"/":k(t))+i.search))})}const u=o&&C?J(o.slug):void 0,w=u?await v(l.resolve(e.outdir,T(u))):!1,{isAuthenticated:d,teams:g,claims:{email:p}}=n.get("auth");if(o&&!U(o,{isAuthenticated:d,email:p,teams:g},e.config.access?.rbac,e.config.access?.requiresLogin))return d?M(n,e,{slug:o.slug,[I]:o[I],[y]:o[y]},403):b(n,e,o.slug);if(o&&(!C||!w)){const t=await D(o),c=await x(o,n,t,e),{html:H,statusCode:z}=await Q(o,c,n,e,ae);return n.html(H,z,{"Cache-Control":S})}const L=u&&w?u:r,F=T(L),s=l.resolve(e.outdir,F);if(!Z(s,e.outdir))return q(n);if(R){const t=r==="index.html.md"?"/":r.replace(/\.md$/,""),c=e.getRouteBySlug(t,{followRedirect:!1});if(c&&!U(c,{isAuthenticated:d,email:p,teams:g},e.config.access?.rbac,e.config.access?.requiresLogin))return b(n,e,r)}const P=e.getGlobalConfig("access");if(!ee(L,P?.rbac||{},P?.requiresLogin||!1,e.getGlobalConfig("directoryPaths"),{isAuthenticated:d,email:p,teams:g}))return q(n);const _=ne[l.extname(s)]||"text/plain",h=s.match(/assets\/.*\.[a-f0-9]{8,}\..+/)||s.match(/runtime\/chunks\/.*/)?$:te[_],B=h?{"Cache-Control":`public, max-age=${h}, immutable`,Expires:new Date(Date.now()+h*1e3).toUTCString()}:{"Cache-Control":S};if(await v(s)){const t=a.query("download")!=null,c=await O(s);return n.newResponse(c,200,{"Content-Type":_,"Access-Control-Allow-Origin":"*",...B,...t&&{"Content-Disposition":`attachment; filename="${l.basename(s)}"`}})}else return M(n,e,{slug:m},404)}}export{qe as dynamicRouteHandler};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{FEEDBACK_API_URL as _}from"../../constants/common.js";import{MAX_CONTEXT_LENGTH as g,MAX_EMAIL_LENGTH as C,MAX_LANG_LENGTH as j,MAX_PATH_LENGTH as E,MAX_REASONS_COUNT as N}from"../../constants/feedback.js";import{mapObject as T}from"../../../utils/object/map-object.js";import{getClientIp as q}from"../utils/get-client-ip.js";import{canAccessResource as w}from"../../utils/rbac.js";function a(e,n){if(e!=null)return String(e).replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g,"").trim().slice(0,n)||void 0}function S(e){if(!e)return e;const n=["userAgent","firstName","lastName","auth_time","platform","id","email","ipAddress"];return T(e,(o,r)=>n.includes(r)?o:"*****")}function L({component:e,path:n,location:o,lang:r,score:u,max:
|
|
1
|
+
import{FEEDBACK_API_URL as _}from"../../constants/common.js";import{MAX_CONTEXT_LENGTH as g,MAX_EMAIL_LENGTH as C,MAX_LANG_LENGTH as j,MAX_PATH_LENGTH as E,MAX_REASONS_COUNT as N}from"../../constants/feedback.js";import{mapObject as T}from"../../../utils/object/map-object.js";import{getClientIp as q}from"../utils/get-client-ip.js";import{canAccessResource as w}from"../../utils/rbac.js";function a(e,n){if(e!=null)return String(e).replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g,"").trim().slice(0,n)||void 0}function S(e){if(!e)return e;const n=["userAgent","firstName","lastName","auth_time","platform","id","email","ipAddress"];return T(e,(o,r)=>n.includes(r)?o:"*****")}function L({component:e,path:n,location:o,lang:r,score:u,max:s,reasons:i,comment:m,metadata:t,email:l}){const c=Array.isArray(i)?i.map(d=>a(String(d),g)).filter(d=>!!d).slice(0,N):void 0;return{feedbackComponent:e.toUpperCase(),path:a(n,E),location:a(o,g),lang:a(r,j),score:typeof u=="number"?u:void 0,maxScore:typeof s=="number"?s:void 0,reasons:c?.length?c:void 0,comment:a(m,g),email:a(l,C),metadata:S(t)}}async function R(e,n){return(await fetch(_,{method:"POST",body:JSON.stringify(L(e)),headers:n})).json()}function G(e){return async n=>{const o=n.get("logger"),r=await n.req.json(),u=n.req.header("user-agent"),s=q(n.req.raw),i=n.req.header("Sec-Ch-Ua-Platform"),m={...r.metadata,userAgent:u,ipAddress:s,platform:i?i.replace(/"/g,""):"unknown"};o.info("Feedback IP diagnostics",I(n,s??void 0));const t=[];(!r.path||r.path==="")&&t.push("`path` is required");const l=["sentiment","rating","comment","problem","mood","scale"];if(l.includes(r.component)||t.push(`\`component\` field should be one of ${l.join(", ")}.`),t.length)return n.json({errors:t},400);const{claims:c,isAuthenticated:d,teams:A}=n.get("auth"),k={isAuthenticated:d,email:c?.email,teams:A};if(Object.keys(e.config.access?.rbac||{}).length>0){const f=r.path,F=new URL(f).pathname,b=e.getRouteBySlug(F);if(!b)return n.json({errors:["Resource not found"]},404);if(!w(b,k,e.config.access?.rbac,e.config.access?.requiresLogin))return n.json({errors:["Forbidden: no permission to send feedback for resource"]},403)}const y={"Content-Type":"application/json"},h=c?.email||r?.email||m?.email;try{const f=await R({...r,email:h,metadata:{email:h,...m}},y);return n.json({message:"Thanks for your feedback",...f},200,{})}catch(f){return n.json({errors:["Failed to send feedback",f.message]},500)}}}function I(e,n){return{extractedIpAddress:n,xForwardedFor:p(e.req.header("x-forwarded-for")),xRealIp:p(e.req.header("x-real-ip")),trueClientIp:p(e.req.header("true-client-ip")),cfConnectingIp:p(e.req.header("cf-connecting-ip"))}}function p(e){if(e)return e.slice(0,256)}export{G as feedbackHandler,S as normalizeFeedbackMetadata};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{getNotAccessibleCatalogResources as n}from"../../../plugins/catalog-entities/utils/get-not-accessible-catalog-resources.js";import{getCurrentRbacTeams as i}from"./get-current-rbac-teams.js";import{expandTeamsForRead as m}from"../../../utils/rbac.js";function b({store:o,ctx:r}){const e=o.getConfig().rbac||{},t=i(r),
|
|
1
|
+
import{getNotAccessibleCatalogResources as n}from"../../../plugins/catalog-entities/utils/get-not-accessible-catalog-resources.js";import{getCurrentRbacTeams as i}from"./get-current-rbac-teams.js";import{expandTeamsForRead as m}from"../../../utils/rbac.js";function b({store:o,ctx:r}){const e=o.getConfig().access?.rbac||{},t=i(r),c=m(e,t),{types:a,entities:s}=n({rbacConfig:e,currentRbacTeams:t});return{currentRbacTeamsForRead:c,excludedTypes:a,excludedEntities:s}}export{b as getRbacRestrictionsDataForCatalog};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{DEV_LOGIN_SLUG as U,ServerRoutes as $}from"../../../constants/common.js";import{CACHE_CONTROL_NO_CACHE_HEADER_VALUE as a,DEFAULT_TITLE as F}from"../../constants/common.js";import{findInIterable as O}from"../../../utils/collection/find-in-iterable.js";import{removeTrailingSlash as N}from"../../../utils/url/remove-trailing-slash.js";import{envConfig as b}from"../../config/env-config.js";import{canAccessResource as q,filterDataByAccessDeep as j,isResourcePubliclyAccessible as B}from"../../utils/rbac.js";import{getServerProps as H}from"../../ssr/index.js";import{readSharedData as G}from"../../utils/index.js";import{getRedirectLoginUrl as M}from"../utils/get-redirect-login-url.js";import{processRedirects as V}from"./helpers/process-redirects.js";import{removeErrorDetails as k}from"../utils/remove-error-details.js";import{telemetry as K}from"../../telemetry/index.js";function ae(e,s){return async(t,p)=>{const l=t.get("logger"),{req:u}=t,{pathname:d}=new URL(u.url),{seo:f,ssoDirect:h}=e.getConfig(),i=f?.title||F;if(e?.compilationErrors?.length&&b.isDevelopMode)return t.json({templateId:"compilation-error",props:{compilationErrors:e?.compilationErrors},sharedDataIds:{}},500,{"Cache-Control":a});const g=d.match(/page-data(.*)data.json$/);if(!g)return p();const c=decodeURI(g[1]),n=c==="/index/"?"/":N(c),o=e.getRouteBySlug(n,{followRedirect:!1})||O(e.routesBySlug.values(),r=>r.hasClientRoutes&&c.startsWith(r.slug));if(c===$.OIDC_CALLBACK+"/")return t.json({templateId:"403OIDC",sharedDataIds:{},props:{seo:{title:`${i} - Forbidden`}}},200,{"Cache-Control":a});const{isAuthenticated:C,teams:D,claims:{name:v,picture:A,email:I}}=t.get("auth"),R={isAuthenticated:C,email:I,teams:D},m={isAuthenticated:C,name:v,picture:A,email:I,teams:D},L=e.getRedirect(n);if(L){const r=V({redirect:L}).location;return K.sendRedirectMessage([{object:"redirect",from:n,templateId:"404"}]),t.json({templateId:"404",redirectTo:r,sharedDataIds:{},props:{}},301,{"Cache-Control":a})}if(!o){const r=e.getRouteBySlug(n,{followRedirect:!0});return l.error(`Page not found: ${d}`),t.json({templateId:"404",redirectTo:r?.slug,sharedDataIds:{},props:{seo:{title:`${i} - Not Found`}},userData:m},404,{"Cache-Control":a})}if(l.verbose(`Page viewed: ${o.slug}`),!q(o,R,e.config.rbac,e.config.requiresLogin)&&o.slug!==U){if(C)return t.json({templateId:"403",sharedDataIds:{},props:{seo:{title:`${i} - Forbidden`}},userData:m},403,{"Cache-Control":a});const r=Object.keys(h||{}).length>0;return t.json({templateId:"404",sharedDataIds:{},props:{seo:{title:`${i} - Not Found`}},userData:m,...r?{redirectTo:M(e,o.slug)}:{}},r?401:404,{"Cache-Control":a})}const S=j(o.versions,R,e.config.rbac,e.config.requiresLogin),P=e.routesSharedData.get(o.slug)||{},T=await s(o),y=await H(o,t,T,e),{sharedDataIds:_,...E}=y,w={templateId:o.templateId,versions:S,sharedDataIds:{...P,..._||{}},props:b.isProductionEnv?k(E):E,slug:o.slug,userData:m,isPublic:B(o,e.config)};return t.json(w,200,{"Cache-Control":a})}}function se(e){return async(s,t)=>{const p=s.get("logger"),{req:l}=s,{pathname:u}=new URL(l.url),d=u.match(/\/page-data\/shared\/(.*)\.json/);if(!d)return t();const f=decodeURIComponent(d[1]),h=await G(f,e.outdir),{isAuthenticated:i,teams:g,claims:{email:c}}=s.get("auth"),n=j(h,{isAuthenticated:i,email:c,teams:g},e.config.rbac,e.config.requiresLogin);return n?s.json(n,200,{"Cache-Control":a}):(p.error(`Shared data not found: ${u}`),s.text("Not Found",404,{"Cache-Control":a}))}}export{ae as pageDataHandler,se as sharedPageDataHandler};
|
|
1
|
+
import{DEV_LOGIN_SLUG as U,ServerRoutes as $}from"../../../constants/common.js";import{CACHE_CONTROL_NO_CACHE_HEADER_VALUE as a,DEFAULT_TITLE as F}from"../../constants/common.js";import{findInIterable as O}from"../../../utils/collection/find-in-iterable.js";import{removeTrailingSlash as N}from"../../../utils/url/remove-trailing-slash.js";import{envConfig as b}from"../../config/env-config.js";import{canAccessResource as q,filterDataByAccessDeep as j,isResourcePubliclyAccessible as B}from"../../utils/rbac.js";import{getServerProps as H}from"../../ssr/index.js";import{readSharedData as G}from"../../utils/index.js";import{getRedirectLoginUrl as M}from"../utils/get-redirect-login-url.js";import{processRedirects as V}from"./helpers/process-redirects.js";import{removeErrorDetails as k}from"../utils/remove-error-details.js";import{telemetry as K}from"../../telemetry/index.js";function ae(e,s){return async(t,p)=>{const l=t.get("logger"),{req:u}=t,{pathname:d}=new URL(u.url),{seo:f,ssoDirect:h}=e.getConfig(),i=f?.title||F;if(e?.compilationErrors?.length&&b.isDevelopMode)return t.json({templateId:"compilation-error",props:{compilationErrors:e?.compilationErrors},sharedDataIds:{}},500,{"Cache-Control":a});const g=d.match(/page-data(.*)data.json$/);if(!g)return p();const c=decodeURI(g[1]),n=c==="/index/"?"/":N(c),o=e.getRouteBySlug(n,{followRedirect:!1})||O(e.routesBySlug.values(),r=>r.hasClientRoutes&&c.startsWith(r.slug));if(c===$.OIDC_CALLBACK+"/")return t.json({templateId:"403OIDC",sharedDataIds:{},props:{seo:{title:`${i} - Forbidden`}}},200,{"Cache-Control":a});const{isAuthenticated:C,teams:D,claims:{name:v,picture:A,email:I}}=t.get("auth"),R={isAuthenticated:C,email:I,teams:D},m={isAuthenticated:C,name:v,picture:A,email:I,teams:D},L=e.getRedirect(n);if(L){const r=V({redirect:L}).location;return K.sendRedirectMessage([{object:"redirect",from:n,templateId:"404"}]),t.json({templateId:"404",redirectTo:r,sharedDataIds:{},props:{}},301,{"Cache-Control":a})}if(!o){const r=e.getRouteBySlug(n,{followRedirect:!0});return l.error(`Page not found: ${d}`),t.json({templateId:"404",redirectTo:r?.slug,sharedDataIds:{},props:{seo:{title:`${i} - Not Found`}},userData:m},404,{"Cache-Control":a})}if(l.verbose(`Page viewed: ${o.slug}`),!q(o,R,e.config.access?.rbac,e.config.access?.requiresLogin)&&o.slug!==U){if(C)return t.json({templateId:"403",sharedDataIds:{},props:{seo:{title:`${i} - Forbidden`}},userData:m},403,{"Cache-Control":a});const r=Object.keys(h||{}).length>0;return t.json({templateId:"404",sharedDataIds:{},props:{seo:{title:`${i} - Not Found`}},userData:m,...r?{redirectTo:M(e,o.slug)}:{}},r?401:404,{"Cache-Control":a})}const S=j(o.versions,R,e.config.access?.rbac,e.config.access?.requiresLogin),P=e.routesSharedData.get(o.slug)||{},T=await s(o),y=await H(o,t,T,e),{sharedDataIds:_,...E}=y,w={templateId:o.templateId,versions:S,sharedDataIds:{...P,..._||{}},props:b.isProductionEnv?k(E):E,slug:o.slug,userData:m,isPublic:B(o,e.config)};return t.json(w,200,{"Cache-Control":a})}}function se(e){return async(s,t)=>{const p=s.get("logger"),{req:l}=s,{pathname:u}=new URL(l.url),d=u.match(/\/page-data\/shared\/(.*)\.json/);if(!d)return t();const f=decodeURIComponent(d[1]),h=await G(f,e.outdir),{isAuthenticated:i,teams:g,claims:{email:c}}=s.get("auth"),n=j(h,{isAuthenticated:i,email:c,teams:g},e.config.access?.rbac,e.config.access?.requiresLogin);return n?s.json(n,200,{"Cache-Control":a}):(p.error(`Shared data not found: ${u}`),s.text("Not Found",404,{"Cache-Control":a}))}}export{ae as pageDataHandler,se as sharedPageDataHandler};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{telemetryTraceStep as d}from"../../telemetry/helpers/trace-step.js";import{expandTeamsForRead as p}from"../../utils/rbac.js";function C(e){return async t=>await d("search",async s=>{const u=t.get("logger"),o=t.get("auth"),y=u.startTiming(),a=e.getConfig().requiresLogin&&!o.isAuthenticated,r={...await t.req.json(),auth:{...o,teams:p(e.config.rbac,o.teams)}};s?.setAttribute("engine",e?.searchEngine?.type),s?.setAttribute("query",r.query||""),s?.setAttribute("user",r.auth.claims.email??"anonymous"),s?.setAttribute("noAccess",a);const g=e.getSearchFacets(),i=a?{}:e.searchEngine?await e.searchEngine.search(r,g):{};let f=0;if(Object.keys(i).length){const h=i.documents;for(const[c,n]of Object.entries(h))f+=n.length}return u.infoTime(y,`Search with query "${r.query||""}". Total results: ${f}`),s?.setAttribute("resultsCount",f),t.json(i)})}function F(e){return async t=>await d("search.facets",async s=>{const u=t.get("logger"),o=t.get("auth"),m=e.getConfig().requiresLogin&&!o.isAuthenticated,a={...await t.req.json(),auth:o};s?.setAttribute("engine",e?.searchEngine?.type),s?.setAttribute("user",a.auth.claims.email??"anonymous"),s?.setAttribute("noAccess",m);const r=u.startTiming(),g=e.getSearchFacets(),i=m?{}:e.searchEngine?await e.searchEngine.countFacets(a,g):{},f=!!a.field;let h=[];if(f){const c=a.field,n=c&&g.get(c);if(n){const l={...n};l.values=i?.[c]||[],h.push(l)}}else{const c=new Map;for(const[n,l]of g){const A=i?.[n],b={...l};b.values=A||l.values.map(T=>({value:T,count:0})),c.set(n,b)}h=Array.from(c,([,n])=>n)}return u.verboseTime(r,"Search facets"),t.json(h)})}export{F as searchFacetsHandler,C as searchHandler};
|
|
1
|
+
import{telemetryTraceStep as d}from"../../telemetry/helpers/trace-step.js";import{expandTeamsForRead as p}from"../../utils/rbac.js";function C(e){return async t=>await d("search",async s=>{const u=t.get("logger"),o=t.get("auth"),y=u.startTiming(),a=e.getConfig().access?.requiresLogin&&!o.isAuthenticated,r={...await t.req.json(),auth:{...o,teams:p(e.config.access?.rbac,o.teams)}};s?.setAttribute("engine",e?.searchEngine?.type),s?.setAttribute("query",r.query||""),s?.setAttribute("user",r.auth.claims.email??"anonymous"),s?.setAttribute("noAccess",a);const g=e.getSearchFacets(),i=a?{}:e.searchEngine?await e.searchEngine.search(r,g):{};let f=0;if(Object.keys(i).length){const h=i.documents;for(const[c,n]of Object.entries(h))f+=n.length}return u.infoTime(y,`Search with query "${r.query||""}". Total results: ${f}`),s?.setAttribute("resultsCount",f),t.json(i)})}function F(e){return async t=>await d("search.facets",async s=>{const u=t.get("logger"),o=t.get("auth"),m=e.getConfig().access?.requiresLogin&&!o.isAuthenticated,a={...await t.req.json(),auth:o};s?.setAttribute("engine",e?.searchEngine?.type),s?.setAttribute("user",a.auth.claims.email??"anonymous"),s?.setAttribute("noAccess",m);const r=u.startTiming(),g=e.getSearchFacets(),i=m?{}:e.searchEngine?await e.searchEngine.countFacets(a,g):{},f=!!a.field;let h=[];if(f){const c=a.field,n=c&&g.get(c);if(n){const l={...n};l.values=i?.[c]||[],h.push(l)}}else{const c=new Map;for(const[n,l]of g){const A=i?.[n],b={...l};b.values=A||l.values.map(T=>({value:T,count:0})),c.set(n,b)}h=Array.from(c,([,n])=>n)}return u.verboseTime(r,"Search facets"),t.json(h)})}export{F as searchFacetsHandler,C as searchHandler};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import s from"path";import{REDOCLY_ROUTE_RBAC as C}from"@redocly/config";import{PUBLIC_STATIC_FOLDER as r}from"../../constants/common.js";import{isPathInFolder as g}from"../../../utils/path/is-path-in-folder.js";import{fileExistsAsync as h}from"../../utils/index.js";import{handleUnauthorizedAsset as w}from"../utils.js";import{MIME_TYPES as E}from"../mime-types.js";import{canAccessResource as R}from"../../utils/rbac.js";const O=async(t,n,o,
|
|
1
|
+
import s from"path";import{REDOCLY_ROUTE_RBAC as C}from"@redocly/config";import{PUBLIC_STATIC_FOLDER as r}from"../../constants/common.js";import{isPathInFolder as g}from"../../../utils/path/is-path-in-folder.js";import{fileExistsAsync as h}from"../../utils/index.js";import{handleUnauthorizedAsset as w}from"../utils.js";import{MIME_TYPES as E}from"../mime-types.js";import{canAccessResource as R}from"../../utils/rbac.js";const O=async(t,n,o,c)=>{const a=n.req,{isAuthenticated:m,teams:l,claims:{email:u}}=n.get("auth"),i=s.join(r,r);t.startsWith(i)&&(t=t.replace(i,r));const e=s.resolve(o.outdir,t);if(!g(e,o.outdir))return null;if(await h(e)){const p={[C]:{slug:t,fsPath:e},slug:t};if(!R(p,{isAuthenticated:m,email:u,teams:l},o.config.access?.rbac,o.config.access?.requiresLogin))return w(n);const f=a.query("download")!=null,d=E[s.extname(e)]||"text/plain",A=await c(e);return n.newResponse(A,200,{"Content-Type":d,"Access-Control-Allow-Origin":"*",...f&&{"Content-Disposition":`attachment; filename="${s.basename(e)}"`}})}else return null};export{O as staticContentHandler};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@redocly/reef",
|
|
3
|
-
"version": "0.132.0-next.
|
|
3
|
+
"version": "0.132.0-next.2",
|
|
4
4
|
"description": "",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"@opentelemetry/sdk-trace-web": "2.0.1",
|
|
31
31
|
"@opentelemetry/semantic-conventions": "1.34.0",
|
|
32
32
|
"@redocly/ajv": "8.18.0",
|
|
33
|
-
"@redocly/openapi-core": "2.
|
|
33
|
+
"@redocly/openapi-core": "2.24.0",
|
|
34
34
|
"@shikijs/transformers": "3.21.0",
|
|
35
35
|
"@tanstack/react-query": "5.62.3",
|
|
36
36
|
"@tanstack/react-table": "8.21.3",
|
|
@@ -54,13 +54,13 @@
|
|
|
54
54
|
"flexsearch": "0.7.43",
|
|
55
55
|
"graphql": "16.12.0",
|
|
56
56
|
"gray-matter": "4.0.3",
|
|
57
|
-
"hono": "4.
|
|
57
|
+
"hono": "4.12.8",
|
|
58
58
|
"htmlparser2": "8.0.2",
|
|
59
59
|
"i18next": "22.4.15",
|
|
60
60
|
"is-glob": "4.0.3",
|
|
61
61
|
"js-yaml": "4.1.1",
|
|
62
62
|
"lru-cache": "11.1.0",
|
|
63
|
-
"minimatch": "10.2.
|
|
63
|
+
"minimatch": "10.2.4",
|
|
64
64
|
"mri": "1.2.0",
|
|
65
65
|
"nanoid": "5.0.9",
|
|
66
66
|
"node-fetch": "3.3.1",
|
|
@@ -92,14 +92,14 @@
|
|
|
92
92
|
"xpath": "0.0.34",
|
|
93
93
|
"yaml-ast-parser": "0.0.43",
|
|
94
94
|
"zod": "^3.25.76",
|
|
95
|
-
"@redocly/asyncapi-docs": "1.9.0-next.
|
|
96
|
-
"@redocly/config": "0.44.
|
|
97
|
-
"@redocly/graphql-docs": "1.9.0-next.
|
|
98
|
-
"@redocly/openapi-docs": "3.20.0-next.
|
|
95
|
+
"@redocly/asyncapi-docs": "1.9.0-next.2",
|
|
96
|
+
"@redocly/config": "0.44.2",
|
|
97
|
+
"@redocly/graphql-docs": "1.9.0-next.2",
|
|
98
|
+
"@redocly/openapi-docs": "3.20.0-next.2",
|
|
99
99
|
"@redocly/portal-legacy-ui": "0.15.0-next.0",
|
|
100
|
-
"@redocly/portal-plugin-mock-server": "0.17.0-next.
|
|
100
|
+
"@redocly/portal-plugin-mock-server": "0.17.0-next.2",
|
|
101
101
|
"@redocly/realm-asyncapi-sdk": "0.10.0-next.0",
|
|
102
|
-
"@redocly/theme": "0.64.0-next.
|
|
102
|
+
"@redocly/theme": "0.64.0-next.2"
|
|
103
103
|
},
|
|
104
104
|
"peerDependencies": {
|
|
105
105
|
"react": "^19.2.4",
|