@redocly/reef 0.141.0-next.1 → 0.141.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 CHANGED
@@ -1,5 +1,16 @@
1
1
  # @redocly/reef
2
2
 
3
+ ## 0.141.0-next.2
4
+
5
+ ### Patch Changes
6
+
7
+ - 929e0c5c7a7: Improved warnings for the deprecated `reunite` option in `redocly.yaml` to show where it is set. Added a warning for the deprecated `cms` RBAC scope.
8
+ - 9d1266260aa: Fixed "Last updated" dates that showed the build time instead of the date of the last change.
9
+ - 929e0c5c7a7: Updated `@redocly/openapi-core` to version `2.75.0`.
10
+ - Updated dependencies [929e0c5c7a7]
11
+ - @redocly/api-docs@0.6.0-next.2
12
+ - @redocly/portal-plugin-mock-server@0.26.0-next.0
13
+
3
14
  ## 0.141.0-next.1
4
15
 
5
16
  ### Minor Changes
@@ -117,6 +117,8 @@ export declare const FEATURE: {
117
117
  readonly cookieConsent: 'cookieConsent';
118
118
  readonly sdkGeneration: 'sdkGeneration';
119
119
  readonly customPackages: 'customPackages';
120
+ readonly customMarkdocTags: 'customMarkdocTags';
121
+ readonly customMcpTools: 'customMcpTools';
120
122
  };
121
123
  export declare const GATEWAY_FETCH_LIMIT_DEFAULTS: {
122
124
  readonly ratePerMin: 60;
@@ -1 +1 @@
1
- const s={AUTHORIZATION:"authorization",IDP_ID_TOKEN:"idp_id_token",IDP_ACCESS_TOKEN:"idp_access_token",IDP_REFRESH_TOKEN:"idp_refresh_token",FEDERATED_ACCESS_TOKEN:"federated_access_token",FEDERATED_ID_TOKEN:"federated_id_token"},n="post_logout",_="openapi_docs",E="asyncapi_docs",p="graphql_docs",i="api_docs",A="/_spec-gql",S="markdoc",d="tags",a="*",T={[a]:"read"},L=["openid","email"],I=1440*60,R=720*60*60,O="anonymous",P="authenticated",l="**",C="Reunite",x="translations.yaml",D="redocly.yaml",u="@redocly/theme",m="@theme",g="@skills",M="SKILL.md",N="/.well-known/agent-skills",U="/.well-known/agent-card.json",F="/a2a",h="/.well-known/mcp/server-card.json",k="/app-data.json",y="/eject-component";var t;(function(e){e.BUILD="build",e.DEVELOP="develop",e.PREPARE="prepare"})(t||(t={}));var o;(function(e){e.RATING="rating",e.SENTIMENT="sentiment",e.COMMENT="comment",e.MOOD="mood",e.PROBLEM="problem",e.SCALE="scale"})(o||(o={}));var r;(function(e){e.AI_SEARCH="aiSearch",e.MCP="mcp"})(r||(r={}));const G="/login",b="/invite",v={AUTH0_PASS:"/auth/auth0-pass"},H={NotExist:"ENOENT"},w="default_locale",K="sidebar-",B="PUBLIC_",q="branch.",f=["BROKEN_LINK","MARKDOC","RESOLVE"],V=["logo","navbar","products","footer","sidebar","scripts","links","feedback","search","aiAssistant","colorMode","palette","navigation","codeSnippet","markdown","openapi","graphql","analytics","consent","userMenu","versionPicker","breadcrumbs","catalog","entitiesCatalog","scorecard","scorecards","scorecardClassic","mcp","banner"],c="redocly_category",Q="redocly_product",j="redocly_version",X="redocly_teams",W=c,z={asyncapi:"asyncapi",apiFunctions:"apiFunctions",reactPages:"reactPages",catalog:"catalog",catalogClassic:"catalogClassic",lint:"lint",scorecard:"scorecard",scorecards:"scorecards",l10n:"l10n",openapi:"openapi",graphql:"graphql",markdown:"markdown",devOnboarding:"devOnboarding",seo:"seo",redirects:"redirects",customPlugins:"customPlugins",themeEjecting:"themeEjecting",products:"products",breadcrumbs:"breadcrumbs",mockServer:"mockServer",sso:"sso",rbac:"rbac",analytics:"analytics",removeAttribution:"removeAttribution",advancedSearch:"advancedSearch",soap:"soap",ssoDirect:"ssoDirect",codeWalkthrough:"codeWalkthrough",aiSearchLimit:"aiSearchLimit",kvStorageLimit:"kvStorageLimit",mcp:"mcp",mcpGateway:"mcpGateway",mcpMode:"mcpMode",gatewayFetchRatePerMin:"gatewayFetchRatePerMin",gatewayFetchQuotaPerDay:"gatewayFetchQuotaPerDay",gatewayFetchBudgetPerExec:"gatewayFetchBudgetPerExec",mcpRequestRatePerMin:"mcpRequestRatePerMin",mcpRequestQuotaPerDay:"mcpRequestQuotaPerDay",banner:"banner",cookieConsent:"cookieConsent",sdkGeneration:"sdkGeneration",customPackages:"customPackages"},J={ratePerMin:60,quotaPerDay:2e3,budgetPerExec:25},Y={ratePerMin:600,quotaPerDay:2e4};export{F as A2A_SLUG,U as AGENT_CARD_SLUG,N as AGENT_SKILLS_BASE,i as API_DOCS_TEMPLATE_ID,E as ASYNC_API_DOCS_TEMPLATE_ID,s as AuthCookieNames,q as BRANCH_ENV_PREFIX,D as CONFIG_FILE_NAME,S as CUSTOM_MARKDOC_OPTIONS_PATH,d as CUSTOM_MARKDOC_TAGS_PATH,O as DEFAULT_ANONYMOUS_VISITOR_TEAM,P as DEFAULT_AUTHENTICATED_TEAM,I as DEFAULT_COOKIE_EXPIRATION,w as DEFAULT_LOCALE_PLACEHOLDER,l as DEFAULT_RBAC_SCOPE,C as DEFAULT_SSO_IDP_TITLE,u as DEFAULT_THEME_NAME,G as DEV_LOGIN_SLUG,y as EJECT_COMPONENT_URL,v as ExternalRoutes,z as FEATURE,o as FEEDBACK_TYPES,H as FsErrors,J as GATEWAY_FETCH_LIMIT_DEFAULTS,k as GLOBAL_DATA_URL,A as GRAPHQL_SPEC_SLUG,p as GRAPHQL_TEMPLATE_ID,b as INVITE_SLUG,f as MARKDOC_ERROR_TYPES,Y as MCP_REQUEST_LIMIT_DEFAULTS,h as MCP_SERVER_CARD_SLUG,_ as OPENAPI_DOCS_TEMPLATE_ID,R as POST_LOGOUT_COOKIE_EXPIRATION,n as POST_LOGOUT_COOKIE_NAME,B as PUBLIC_ENV_PREFIX,T as PUBLIC_RBAC_SCOPE_ITEM,a as RBAC_ALL_OTHER_TEAMS,L as REQUIRED_OIDC_SCOPES,r as RbacFeatures,c as SEARCH_CATEGORY_FIELD,W as SEARCH_GROUP_FACET_FIELD,Q as SEARCH_PRODUCT_FIELD,X as SEARCH_RBAC_FIELD,j as SEARCH_VERSION_FIELD,K as SIDEBAR_PREFIX,x as TRANSLATIONS_FILE_NAME,V as UI_ACCESSIBLE_CONFIG_PROPS,g as USER_SKILLS_ALIAS,M as USER_SKILL_FILENAME,m as USER_THEME_ALIAS,t as cliCommandNames};
1
+ const s={AUTHORIZATION:"authorization",IDP_ID_TOKEN:"idp_id_token",IDP_ACCESS_TOKEN:"idp_access_token",IDP_REFRESH_TOKEN:"idp_refresh_token",FEDERATED_ACCESS_TOKEN:"federated_access_token",FEDERATED_ID_TOKEN:"federated_id_token"},n="post_logout",_="openapi_docs",E="asyncapi_docs",p="graphql_docs",i="api_docs",A="/_spec-gql",T="markdoc",d="tags",r="*",S={[r]:"read"},L=["openid","email"],I=1440*60,R=720*60*60,O="anonymous",P="authenticated",l="**",C="Reunite",x="translations.yaml",u="redocly.yaml",D="@redocly/theme",m="@theme",M="@skills",g="SKILL.md",N="/.well-known/agent-skills",U="/.well-known/agent-card.json",F="/a2a",k="/.well-known/mcp/server-card.json",h="/app-data.json",y="/eject-component";var t;(function(e){e.BUILD="build",e.DEVELOP="develop",e.PREPARE="prepare"})(t||(t={}));var o;(function(e){e.RATING="rating",e.SENTIMENT="sentiment",e.COMMENT="comment",e.MOOD="mood",e.PROBLEM="problem",e.SCALE="scale"})(o||(o={}));var c;(function(e){e.AI_SEARCH="aiSearch",e.MCP="mcp"})(c||(c={}));const G="/login",b="/invite",v={AUTH0_PASS:"/auth/auth0-pass"},H={NotExist:"ENOENT"},w="default_locale",K="sidebar-",B="PUBLIC_",q="branch.",f=["BROKEN_LINK","MARKDOC","RESOLVE"],V=["logo","navbar","products","footer","sidebar","scripts","links","feedback","search","aiAssistant","colorMode","palette","navigation","codeSnippet","markdown","openapi","graphql","analytics","consent","userMenu","versionPicker","breadcrumbs","catalog","entitiesCatalog","scorecard","scorecards","scorecardClassic","mcp","banner"],a="redocly_category",Q="redocly_product",j="redocly_version",X="redocly_teams",W=a,z={asyncapi:"asyncapi",apiFunctions:"apiFunctions",reactPages:"reactPages",catalog:"catalog",catalogClassic:"catalogClassic",lint:"lint",scorecard:"scorecard",scorecards:"scorecards",l10n:"l10n",openapi:"openapi",graphql:"graphql",markdown:"markdown",devOnboarding:"devOnboarding",seo:"seo",redirects:"redirects",customPlugins:"customPlugins",themeEjecting:"themeEjecting",products:"products",breadcrumbs:"breadcrumbs",mockServer:"mockServer",sso:"sso",rbac:"rbac",analytics:"analytics",removeAttribution:"removeAttribution",advancedSearch:"advancedSearch",soap:"soap",ssoDirect:"ssoDirect",codeWalkthrough:"codeWalkthrough",aiSearchLimit:"aiSearchLimit",kvStorageLimit:"kvStorageLimit",mcp:"mcp",mcpGateway:"mcpGateway",mcpMode:"mcpMode",gatewayFetchRatePerMin:"gatewayFetchRatePerMin",gatewayFetchQuotaPerDay:"gatewayFetchQuotaPerDay",gatewayFetchBudgetPerExec:"gatewayFetchBudgetPerExec",mcpRequestRatePerMin:"mcpRequestRatePerMin",mcpRequestQuotaPerDay:"mcpRequestQuotaPerDay",banner:"banner",cookieConsent:"cookieConsent",sdkGeneration:"sdkGeneration",customPackages:"customPackages",customMarkdocTags:"customMarkdocTags",customMcpTools:"customMcpTools"},J={ratePerMin:60,quotaPerDay:2e3,budgetPerExec:25},Y={ratePerMin:600,quotaPerDay:2e4};export{F as A2A_SLUG,U as AGENT_CARD_SLUG,N as AGENT_SKILLS_BASE,i as API_DOCS_TEMPLATE_ID,E as ASYNC_API_DOCS_TEMPLATE_ID,s as AuthCookieNames,q as BRANCH_ENV_PREFIX,u as CONFIG_FILE_NAME,T as CUSTOM_MARKDOC_OPTIONS_PATH,d as CUSTOM_MARKDOC_TAGS_PATH,O as DEFAULT_ANONYMOUS_VISITOR_TEAM,P as DEFAULT_AUTHENTICATED_TEAM,I as DEFAULT_COOKIE_EXPIRATION,w as DEFAULT_LOCALE_PLACEHOLDER,l as DEFAULT_RBAC_SCOPE,C as DEFAULT_SSO_IDP_TITLE,D as DEFAULT_THEME_NAME,G as DEV_LOGIN_SLUG,y as EJECT_COMPONENT_URL,v as ExternalRoutes,z as FEATURE,o as FEEDBACK_TYPES,H as FsErrors,J as GATEWAY_FETCH_LIMIT_DEFAULTS,h as GLOBAL_DATA_URL,A as GRAPHQL_SPEC_SLUG,p as GRAPHQL_TEMPLATE_ID,b as INVITE_SLUG,f as MARKDOC_ERROR_TYPES,Y as MCP_REQUEST_LIMIT_DEFAULTS,k as MCP_SERVER_CARD_SLUG,_ as OPENAPI_DOCS_TEMPLATE_ID,R as POST_LOGOUT_COOKIE_EXPIRATION,n as POST_LOGOUT_COOKIE_NAME,B as PUBLIC_ENV_PREFIX,S as PUBLIC_RBAC_SCOPE_ITEM,r as RBAC_ALL_OTHER_TEAMS,L as REQUIRED_OIDC_SCOPES,c as RbacFeatures,a as SEARCH_CATEGORY_FIELD,W as SEARCH_GROUP_FACET_FIELD,Q as SEARCH_PRODUCT_FIELD,X as SEARCH_RBAC_FIELD,j as SEARCH_VERSION_FIELD,K as SIDEBAR_PREFIX,x as TRANSLATIONS_FILE_NAME,V as UI_ACCESSIBLE_CONFIG_PROPS,M as USER_SKILLS_ALIAS,g as USER_SKILL_FILENAME,m as USER_THEME_ALIAS,t as cliCommandNames};
@@ -1 +1 @@
1
- import{GATEWAY_FETCH_LIMIT_DEFAULTS as e,MCP_REQUEST_LIMIT_DEFAULTS as t}from"../../constants/common.js";const a=["@redocly/*","react","react-dom","react-is","react-router","react-router-dom","styled-components","@markdoc/markdoc","js-yaml","graphql","zod","hono","buffer","i18next","nanoid","picomatch","prismjs","react-countup","styled-system","polished","clsx","react-icons","lucide-react","framer-motion","react-helmet","react-select","react-markdown","remark-gfm","unist-util-visit","marked","highlight-words-core","axios","lodash","lodash-es","lodash.throttle"],o={pro:{pricingTier:"pro",rbac:!1,sso:!1,cookieConsent:!1,analytics:!0,removeAttribution:!1,advancedSearch:!1,ssoDirect:!1,aiSearchLimit:750,kvStorageLimit:.5,mcp:!0,mcpGateway:!1,sdkGeneration:!1,mcpMode:"tools",gatewayFetchRatePerMin:e.ratePerMin,gatewayFetchQuotaPerDay:e.quotaPerDay,gatewayFetchBudgetPerExec:e.budgetPerExec,mcpRequestRatePerMin:t.ratePerMin,mcpRequestQuotaPerDay:t.quotaPerDay,customPackages:!1,allowedPackages:a},scale:{pricingTier:"scale",rbac:!1,sso:!0,cookieConsent:!0,analytics:!0,removeAttribution:!0,advancedSearch:!0,ssoDirect:!0,aiSearchLimit:750,kvStorageLimit:5,mcp:!0,mcpGateway:!1,sdkGeneration:!0,mcpMode:"tools",gatewayFetchRatePerMin:e.ratePerMin,gatewayFetchQuotaPerDay:e.quotaPerDay,gatewayFetchBudgetPerExec:e.budgetPerExec,mcpRequestRatePerMin:t.ratePerMin,mcpRequestQuotaPerDay:t.quotaPerDay,customPackages:!0},enterprise:{pricingTier:"enterprise",rbac:!0,sso:!0,cookieConsent:!0,analytics:!0,removeAttribution:!0,advancedSearch:!0,ssoDirect:!1,aiSearchLimit:750,kvStorageLimit:5,mcp:!0,mcpGateway:!0,sdkGeneration:!0,mcpMode:"code",gatewayFetchRatePerMin:e.ratePerMin,gatewayFetchQuotaPerDay:e.quotaPerDay,gatewayFetchBudgetPerExec:e.budgetPerExec,mcpRequestRatePerMin:t.ratePerMin,mcpRequestQuotaPerDay:t.quotaPerDay,customPackages:!0}},c=["@redocly/portal-plugin-async-api/plugin.js","@redocly/portal-plugin-mock-server/plugin.js","@redocly/portal-plugin-soap-api/plugin.js"],s={"code-walkthrough":"codeWalkthrough",step:"codeWalkthrough",toggle:"codeWalkthrough",input:"codeWalkthrough"};export{s as GATED_MARKDOC_TAGS,c as GATED_PLUGINS,o as PLAN_GATES_DEFAULTS};
1
+ import{GATEWAY_FETCH_LIMIT_DEFAULTS as e,MCP_REQUEST_LIMIT_DEFAULTS as t}from"../../constants/common.js";const a=["@redocly/*","react","react-dom","react-is","react-router","react-router-dom","styled-components","@markdoc/markdoc","js-yaml","graphql","zod","hono","buffer","i18next","nanoid","picomatch","prismjs","react-countup","styled-system","polished","clsx","react-icons","lucide-react","framer-motion","react-helmet","react-select","react-markdown","remark-gfm","unist-util-visit","marked","highlight-words-core","axios","lodash","lodash-es","lodash.throttle"],o={pro:{pricingTier:"pro",rbac:!1,sso:!1,cookieConsent:!1,analytics:!0,removeAttribution:!1,advancedSearch:!1,ssoDirect:!1,aiSearchLimit:750,kvStorageLimit:.5,mcp:!0,mcpGateway:!1,sdkGeneration:!1,mcpMode:"tools",gatewayFetchRatePerMin:e.ratePerMin,gatewayFetchQuotaPerDay:e.quotaPerDay,gatewayFetchBudgetPerExec:e.budgetPerExec,mcpRequestRatePerMin:t.ratePerMin,mcpRequestQuotaPerDay:t.quotaPerDay,customPackages:!1,customMarkdocTags:!1,customMcpTools:!1,allowedPackages:a},scale:{pricingTier:"scale",rbac:!1,sso:!0,cookieConsent:!0,analytics:!0,removeAttribution:!0,advancedSearch:!0,ssoDirect:!0,aiSearchLimit:750,kvStorageLimit:5,mcp:!0,mcpGateway:!1,sdkGeneration:!0,mcpMode:"tools",gatewayFetchRatePerMin:e.ratePerMin,gatewayFetchQuotaPerDay:e.quotaPerDay,gatewayFetchBudgetPerExec:e.budgetPerExec,mcpRequestRatePerMin:t.ratePerMin,mcpRequestQuotaPerDay:t.quotaPerDay,customPackages:!0,customMarkdocTags:!0,customMcpTools:!0},enterprise:{pricingTier:"enterprise",rbac:!0,sso:!0,cookieConsent:!0,analytics:!0,removeAttribution:!0,advancedSearch:!0,ssoDirect:!1,aiSearchLimit:750,kvStorageLimit:5,mcp:!0,mcpGateway:!0,sdkGeneration:!0,mcpMode:"code",gatewayFetchRatePerMin:e.ratePerMin,gatewayFetchQuotaPerDay:e.quotaPerDay,gatewayFetchBudgetPerExec:e.budgetPerExec,mcpRequestRatePerMin:t.ratePerMin,mcpRequestQuotaPerDay:t.quotaPerDay,customPackages:!0,customMarkdocTags:!0,customMcpTools:!0}},c=["@redocly/portal-plugin-async-api/plugin.js","@redocly/portal-plugin-mock-server/plugin.js","@redocly/portal-plugin-soap-api/plugin.js"],s={"code-walkthrough":"codeWalkthrough",step:"codeWalkthrough",toggle:"codeWalkthrough",input:"codeWalkthrough"};export{s as GATED_MARKDOC_TAGS,c as GATED_PLUGINS,o as PLAN_GATES_DEFAULTS};
@@ -14,6 +14,10 @@ export declare class EntitlementsProvider {
14
14
  canAccessFeature: (key: Feature) => boolean | null;
15
15
  /** Whether the project may declare any npm package; true unless the plan sets `customPackages` to false. */
16
16
  canUseAnyPackage: () => boolean;
17
+ /** Whether pages may use the tags of `@theme/markdoc/schema.ts`; true unless the plan sets `customMarkdocTags` to false. */
18
+ canUseCustomMarkdocTags: () => boolean;
19
+ /** Whether `@mcp` folders register MCP tools; true unless the plan sets `customMcpTools` to false. */
20
+ canUseCustomMcpTools: () => boolean;
17
21
  /** The npm packages the plan allows when `canUseAnyPackage()` is false; `[]` when the token has no valid list. */
18
22
  getAllowedPackages: () => string[];
19
23
  getPackageEjectIgnore(): Promise<string[]>;
@@ -1 +1 @@
1
- import{ENTITLEMENTS_JWKS_URL as c}from"../constants/common.js";import{PLAN_GATES_DEFAULTS as l}from"../constants/entitlements.js";import{envConfig as s}from"../config/env-config.js";import{logger as r}from"../tools/notifiers/logger.js";import{reporter as i}from"../tools/notifiers/reporter.js";import{PACKAGE_NAME as p,PRODUCT_GATES as g}from"../../config/product-gates.js";import{EJECT_IGNORE_CONFIG as m}from"../../config/eject-ignore.js";import*as o from"../web-server/jwt/jwt.js";import{AlgorithmTypes as f}from"../web-server/jwt/types.js";const h="default",u="@redocly/framework";class a{static#t;#n=null;#e={};constructor(){}static instance(){return a.#t||(a.#t=new a),a.#t}get entitlements(){return this.#n}get pricingTier(){return this.#n?.pricingTier??null}async init(e={}){this.#e=e;try{await this.#o()}catch(t){r.warn("Failed to process entitlements information: "+t.message),r.verbose(t.message)}}canAccessFeature=e=>e?this.entitlements&&!!this.entitlements[e]:!0;canUseAnyPackage=()=>this.entitlements?.customPackages!==!1;getAllowedPackages=()=>{const e=this.entitlements?.allowedPackages;return Array.isArray(e)&&e.every(t=>typeof t=="string")?e:[]};async getPackageEjectIgnore(){const e=[];for(const[t,n]of Object.entries(m))this.canAccessFeature(t)&&e.push(...n);return e}#r(){return s.PLAN_GATES||""}async#a(){let e;try{e=await fetch(c).then(t=>t.json())}catch(t){return r.warn("Failed to get JWKS information: "+t.message),!1}try{const t=e.keys&&e.keys.length>0?e.keys[0]:null,n=this.#r();return t&&n?await o.verify(n,t,f.RS256,this.#e.ignoreTokenExpiration):!1}catch(t){return r.warn("Failed to verify plan gates token: "+t.message),!1}}async#s(){if(await this.#a()){const{payload:e}=o.decode(this.#r());if(e){if(!s.REDOCLY_ENV&&e.exp){const t=e.exp*1e3,n=new Date(t);r.info(`Entitlements token expires on ${n.toISOString()} (in ${Math.ceil((t-new Date().getTime())/(1440*60*1e3))} days)`)}return await this.#i(e),e}}await i.panicOnContentError("Plan gates token is not valid or empty.")}async#i(e){p===u&&(e.pricingTier||e.subscriptionId===h||await i.panicOnContentError("@redocly/framework requires the Pro, Scale, or Enterprise plan. This organization is on an earlier plan: keep building with its product package, such as @redocly/realm."))}async#o(){const e=this.#e.developModePlan&&!this.#r()?l[this.#e.developModePlan]:await this.#s();this.#n={...g,...e}}}export{a as EntitlementsProvider};
1
+ import{ENTITLEMENTS_JWKS_URL as c}from"../constants/common.js";import{PLAN_GATES_DEFAULTS as l}from"../constants/entitlements.js";import{envConfig as a}from"../config/env-config.js";import{logger as r}from"../tools/notifiers/logger.js";import{reporter as i}from"../tools/notifiers/reporter.js";import{PACKAGE_NAME as p,PRODUCT_GATES as m}from"../../config/product-gates.js";import{EJECT_IGNORE_CONFIG as g}from"../../config/eject-ignore.js";import*as o from"../web-server/jwt/jwt.js";import{AlgorithmTypes as f}from"../web-server/jwt/types.js";const u="default",h="@redocly/framework";class s{static#t;#n=null;#e={};constructor(){}static instance(){return s.#t||(s.#t=new s),s.#t}get entitlements(){return this.#n}get pricingTier(){return this.#n?.pricingTier??null}async init(e={}){this.#e=e;try{await this.#c()}catch(t){r.warn("Failed to process entitlements information: "+t.message),r.verbose(t.message)}}canAccessFeature=e=>e?this.entitlements&&!!this.entitlements[e]:!0;canUseAnyPackage=()=>this.#r("customPackages");canUseCustomMarkdocTags=()=>this.#r("customMarkdocTags");canUseCustomMcpTools=()=>this.#r("customMcpTools");#r(e){return this.entitlements?.[e]!==!1}getAllowedPackages=()=>{const e=this.entitlements?.allowedPackages;return Array.isArray(e)&&e.every(t=>typeof t=="string")?e:[]};async getPackageEjectIgnore(){const e=[];for(const[t,n]of Object.entries(g))this.canAccessFeature(t)&&e.push(...n);return e}#s(){return a.PLAN_GATES||""}async#a(){let e;try{e=await fetch(c).then(t=>t.json())}catch(t){return r.warn("Failed to get JWKS information: "+t.message),!1}try{const t=e.keys&&e.keys.length>0?e.keys[0]:null,n=this.#s();return t&&n?await o.verify(n,t,f.RS256,this.#e.ignoreTokenExpiration):!1}catch(t){return r.warn("Failed to verify plan gates token: "+t.message),!1}}async#i(){if(await this.#a()){const{payload:e}=o.decode(this.#s());if(e){if(!a.REDOCLY_ENV&&e.exp){const t=e.exp*1e3,n=new Date(t);r.info(`Entitlements token expires on ${n.toISOString()} (in ${Math.ceil((t-new Date().getTime())/(1440*60*1e3))} days)`)}return await this.#o(e),e}}await i.panicOnContentError("Plan gates token is not valid or empty.")}async#o(e){p===h&&(e.pricingTier||e.subscriptionId===u||await i.panicOnContentError("@redocly/framework requires the Pro, Scale, or Enterprise plan. This organization is on an earlier plan: keep building with its product package, such as @redocly/realm."))}async#c(){const e=this.#e.developModePlan&&!this.#s()?l[this.#e.developModePlan]:await this.#i();this.#n={...m,...e}}}export{s as EntitlementsProvider};
@@ -0,0 +1,6 @@
1
+ /**
2
+ * The Markdoc tags the plan lacks, each with the message a page shows in place of the tag:
3
+ * `userTagNames` when custom Markdoc tags are off, and the product-gated tags of a missing gate.
4
+ */
5
+ export declare function getPlanDeniedMarkdocTags(userTagNames: readonly string[]): Record<string, string>;
6
+ //# sourceMappingURL=plan-denied-markdoc-tags.d.ts.map
@@ -0,0 +1 @@
1
+ import{GATED_MARKDOC_TAGS as s}from"../constants/entitlements.js";import{EntitlementsProvider as i}from"./entitlements-provider.js";function d(n){const e=i.instance(),o={};if(!e.canUseCustomMarkdocTags())for(const t of n)o[t]=`Custom Markdoc tags are not in this project's plan, so \`${t}\` is ignored.`;for(const[t,r]of Object.entries(s))e.canAccessFeature(r)||(o[t]=`\`${t}\` is not in this project's plan and is ignored.`);return o}export{d as getPlanDeniedMarkdocTags};
@@ -1,3 +1,3 @@
1
- import{spawn as w}from"child_process";import h from"path";async function v(a,l){if(!l)return new Map;let i,c;try{const t=await l.revparse(["--show-toplevel"]);i=new Set((await l.raw("ls-files",a)).split(`
2
- `).map(s=>s.trim()));const e=t&&h.relative(t,a);c=e&&e.length&&e.length+1||0}catch(t){if(t.message.includes("not a git repository"))return new Map;throw t}return new Promise(t=>{const e=new Map;let s=0;const o=w("git",["log","--raw","--no-merges","--pretty=%at","--",a],{stdio:"pipe"});let p="";function m(f){p+=String(f);const u=p.split(`
3
- `);p=u.pop()||"",u.forEach(r=>{if(r=r.trim(),!!r){if(r.startsWith(":")){const n=r.split(" ").slice(-1)[0].slice(c);if(e.has(n))return;i.has(n)&&i.delete(n),e.set(n,new Date(s*1e3).toISOString())}else s=Number(r);i.size===0&&(o.kill(),t(e))}})}o.stdout.on("data",f=>{m(f)}),o.stdout.on("end",()=>{m(""),o.kill(),t(e)})})}export{v as fastMtime};
1
+ import{spawn as w}from"child_process";import g from"path";import{logger as h}from"../tools/notifiers/logger.js";async function M(l,p){if(!p)return new Map;let i,m;try{const t=await p.revparse(["--show-toplevel"]);i=new Set((await p.raw("ls-files",l)).split(`
2
+ `).map(n=>n.trim()));const e=t&&g.relative(t,l);m=e&&e.length&&e.length+1||0}catch(t){if(t.message.includes("not a git repository"))return new Map;throw t}return new Promise(t=>{const e=new Map;let n=0;const o=w("git",["log","--raw","--no-renames","--no-merges","--pretty=%at","--","."],{cwd:g.resolve(l),stdio:"pipe"});let c="";o.stderr.on("data",r=>{c+=String(r)}),o.on("close",r=>{r&&h.warn(`Could not read the full git history, some last updated dates can be wrong: ${c.trim()}`)});let f="";function u(r){f+=String(r);const d=f.split(`
3
+ `);f=d.pop()||"",d.forEach(s=>{if(s=s.trim(),!!s){if(s.startsWith(":")){const a=s.split(" ").slice(-1)[0].slice(m);if(e.has(a))return;i.has(a)&&i.delete(a),e.set(a,new Date(n*1e3).toISOString())}else n=Number(s);i.size===0&&(o.kill(),t(e))}})}o.stdout.on("data",r=>{u(r)}),o.stdout.on("end",()=>{u(""),o.kill(),t(e)})})}export{M as fastMtime};
@@ -1,4 +1,4 @@
1
- import{getLineColLocation as u,isAbsoluteUrl as g,getCodeframe as l}from"@redocly/openapi-core";import m from"node:path";import{gray as i}from"../../tools/notifiers/helpers/colors.js";function L(a,s){return`Config validation error:
1
+ import{getLineColLocation as u,isAbsoluteUrl as g,getCodeframe as l}from"@redocly/openapi-core";import m from"node:path";import{gray as i}from"../../tools/notifiers/helpers/colors.js";function v(a,s){return`Config validation ${a.severity==="warn"?"warning":"error"}:
2
2
 
3
3
  `+c(a);function c(o){const t=o.location[0];if(!t)return o.message;if(!t.source){const n=t.pointer??"";return`${o.message}${n?` at ${n}`:""}`}const e=t.source?.absoluteRef,r=e&&g(e)?e:e?m.relative(s,e):"config";try{if(typeof t.source.getAst!="function"){const $=t.pointer?i(`at ${t.pointer}`):"";return`${r} ${$}
4
4
 
@@ -14,4 +14,4 @@ ${o.message}
14
14
 
15
15
  ${o.message}
16
16
 
17
- `}}}export{L as formatConfigProblem};
17
+ `}}}export{v as formatConfigProblem};
@@ -1 +1 @@
1
- import R from"path";import{lintConfig as j,loadConfig as E,createConfigTypes as L}from"@redocly/openapi-core";import{findEmptyAgentSection as S,rbacConfigSchema as q,rootRedoclyConfigSchema as x,withPlatformSection as B}from"@redocly/config";import{deepMerge as k}from"../../../../../utils/object/deep-merge.js";import{isPlainObject as v}from"../../../../../utils/guards/is-plain-object.js";import{logger as p}from"../../../../tools/notifiers/logger.js";import{BRANCH_ENV_PREFIX as I}from"../../../../../constants/common.js";import{sanitizeBranchName as M}from"../../../../utils/envs/sanitize-branch-name.js";import{envConfig as C}from"../../../../config/env-config.js";import{ajv as N,safeParsePartial as _}from"../../safe-parse.js";import{formatConfigProblem as D}from"../../format-error.js";import{ExternalResolver as F}from"../../../../fs/utils/external-ref-resolver.js";import{resolveMutuallyExclusiveProps as G}from"../../resolve-mutual-exclusion.js";function y(e,s,t,n){s in e&&e[s]&&typeof e[s]=="string"&&(/^https?:\/\/.*/.test(e[s])||n(new Error(`Invalid ${t} URL: "${e[s]}". ${t} must start with "http://" or "https://".`)))}function z(e,s){if("access"in e&&e.access&&typeof e.access=="object"){const t=e.access;y(t,"logoutReturnUrl","access.logoutReturnUrl",s),y(t,"residency","access.residency",s);const n=["requiresLogin","logoutReturnUrl","residency","sso","rbac"];for(const r of n)r in t&&t[r]!==void 0&&r in e&&e[r]!==void 0&&s(new Error(`Property '${r}' is defined both at root level and in 'access' object. Please use 'access.${r}' to define this configuration.`))}}function V(e){return N.compile(x.properties.graphql.properties.servers.items.properties.url)(e)}function A(e,s,t){if(v(e)&&Array.isArray(e.servers))for(const n of e.servers){const r=v(n)?n.url:void 0;if(typeof r=="string"&&!V(r)){const a=e.servers.indexOf(n),c=`${s}.servers[${a}].url`;t(new Error(`Invalid ${c}: "${r}". It must be an absolute http:// or https:// URL.`))}}}function Y(e,s){if(A(e.graphql,"graphql",s),!!v(e.apis))for(const[t,n]of Object.entries(e.apis))v(n)&&A(n.graphql,`apis.${t}.graphql`,s)}function H(e,s){const t=[["",e],...Object.entries(e.env??{}).map(([n,r])=>[`env.${n}.`,r])];for(const[n,r]of t){const a=S(r);a&&s(new Error(`Invalid ${n}${a}.agent: it must set at least one option.`))}}async function me(e,s,t,n){const a=s.getFileInfo(e)?.realRelativePath||e;async function c(){const f=new F(s),m=R.join(s.cwd,a),d=await E({configPath:m,externalRefResolver:f}),h=await n(d.resolvedConfig);if(h===void 0)return d.resolvedConfig;const g=d.document?.source,P=[...g?await j({config:d,externalConfigTypes:L(h,d)}):[],...g?G(d.resolvedConfig,g):[]];if(P.length>0)for(const U of P)t(new Error(D(U,s.cwd)));return d.resolvedConfig}const o=s.exists(e)?await c():{},l=Q(o),w=await n(o);y(o,"residency","Residency",t),y(o,"logoutReturnUrl","Logout return URL",t),z(o,t),Y(o,t),H(o,t);let u=w?_(w,o):o;u=W(u),u=J(u,t);const{env:b}=u;if(b){const f=C.REDOCLY_ENV,m=b[f]||{},d=C.PUBLIC_REDOCLY_BRANCH_NAME||"",h=d?M(d):"",g=h&&b[`${I}${h}`]||{};u=k(u,g,m)}const i=Z(u,l);if(i.imports&&i.imports.length>0){p.warn("The 'imports' property is deprecated. Please use 'plugins' property instead.");const f=new Set([...i.plugins||[],...i.imports.map(m=>R.posix.join(m,"plugin.js"))]);i.plugins=Array.from(f),delete i.imports}if(i.catalog&&(p.warn("The 'catalog' property is deprecated. Please use 'catalogClassic' property instead."),i.catalogClassic={...i.catalog},delete i.catalog),i.scorecard&&(p.warn("The 'scorecard' property is deprecated. Please use 'scorecardClassic' property instead."),i.scorecardClassic=i.scorecard,delete i.scorecard),i.search?.ai){p.warn("The 'search.ai' property is deprecated. Please use 'aiAssistant' property instead.");const f={...i.search?.ai,...i.aiAssistant,suggestions:i.aiAssistant?.suggestions?.length?i.aiAssistant.suggestions:i.search?.ai.suggestions||[]};i.aiAssistant=f,delete i.search.ai}return K(i)}function K(e){const s={...e},n={..."access"in e&&e.access&&typeof e.access=="object"?e.access:{}},r=["requiresLogin","logoutReturnUrl","residency","sso","idps","rbac"],a=[];for(const c of r){const o=s[c];o!==void 0&&(a.push(c),c==="requiresLogin"&&n.requiresLogin===void 0&&(n.requiresLogin=o),c==="logoutReturnUrl"&&n.logoutReturnUrl===void 0&&(n.logoutReturnUrl=o),c==="residency"&&n.residency===void 0&&(n.residency=o),c==="sso"&&n.sso===void 0&&(n.sso=o),c==="idps"&&n.idps===void 0&&(n.idps=o),c==="rbac"&&n.rbac===void 0&&(n.rbac=o),delete s[c])}return a.length>0&&p.warn(`The following properties at root level are deprecated: ${a.join(", ")}. Please move them to the 'access' object.`),Object.keys(n).length>0&&(s.access=n),s}function W(e){const s=Object.entries(e.env??{});[e,...s.map(([,r])=>r)].some(r=>r?.mcp?.docs)&&p.warn("The 'mcp.docs' property is deprecated. Please use the 'mcp' properties instead.");const t=e.mcp?{...e,mcp:$(e.mcp)}:e;if(!e.env)return t;const n=s.map(([r,a])=>[r,a?.mcp?{...a,mcp:$(a.mcp)}:a]);return{...t,env:Object.fromEntries(n)}}function $(e){const s=e.docs??{},t={};(e.hide??s.hide)!==void 0&&(t.hide=e.hide===!0||s.hide===!0);const n=e.name??s.name;n!==void 0&&(t.name=n);const r=e.ignore??s.ignore;r!==void 0&&(t.ignore=r);const a=e.publicEndpoint??s.publicEndpoint;return a!==void 0&&(t.publicEndpoint=a),{...e,...t,docs:{...s,...t}}}function X(e){if(!v(e)||e.platform===void 0)return!1;const s=Object.keys(e).filter(t=>t!=="platform");return s.length>0&&s.every(t=>!Object.hasOwn(q.properties,t))}function J(e,s){const t=Object.entries(e.env??{}),n=new Set;let r=!1;for(const o of[e,...t.map(([,l])=>l)])o?.reunite!==void 0&&n.add("The 'reunite' property is deprecated. Please use 'platform' property instead."),o?.reunite!==void 0&&o?.platform!==void 0&&n.add("Both 'platform' and 'reunite' are set. 'reunite' is ignored, so remove it."),[o?.rbac,o?.access?.rbac].some(l=>l?.reunite!==void 0)&&n.add("The 'access.rbac.reunite' property is deprecated. Please use 'access.rbac.platform' property instead."),[o?.rbac,o?.access?.rbac].some(X)&&(r=!0);for(const o of n)p.warn(o);r&&s(new Error("You are using an incorrect format of 'rbac:' configuration. See: https://redocly.com/docs/realm/access"));const a=T(e);if(!e.env)return a;const c=t.map(([o,l])=>[o,l&&T(l)]);return{...a,env:Object.fromEntries(c)}}function T(e){const s=B(e),t=e.rbac?{...s,rbac:O(e.rbac)}:s;return e.access?.rbac?{...t,access:{...e.access,rbac:O(e.access.rbac)}}:t}function O(e){const{reunite:s,...t}=e;return s===void 0?t:{...t,platform:e.platform??s}}function Q(e){if(!e.theme)return[];p.warn("The 'theme' property in redocly.yaml is deprecated. Please move all of the properties from 'theme' to the root of the config.");const s=[];for(const t of Object.keys(e.theme))e[t]==null?s.push(t):p.warn(`Detected both '${t}' and 'theme.${t}' properties in redocly.yaml. The 'theme.${t}' property will be ignored and needs to be removed or merged into the '${t}'.`);return s}function Z(e,s){if(!e.theme||s.length===0)return e;const t={...e};for(const n of s)t[n]=e.theme[n];return delete t.theme,t}export{K as ensureAccessBackwardsCompatibility,me as readAndValidateConfig};
1
+ import C from"path";import{lintConfig as E,loadConfig as L,createConfigTypes as S}from"@redocly/openapi-core";import{findEmptyAgentSection as q,rbacConfigSchema as x,rootRedoclyConfigSchema as B,withPlatformSection as k}from"@redocly/config";import{deepMerge as I}from"../../../../../utils/object/deep-merge.js";import{isPlainObject as v}from"../../../../../utils/guards/is-plain-object.js";import{logger as d}from"../../../../tools/notifiers/logger.js";import{BRANCH_ENV_PREFIX as M}from"../../../../../constants/common.js";import{sanitizeBranchName as N}from"../../../../utils/envs/sanitize-branch-name.js";import{envConfig as A}from"../../../../config/env-config.js";import{ajv as _,safeParsePartial as D}from"../../safe-parse.js";import{formatConfigProblem as F}from"../../format-error.js";import{ExternalResolver as G}from"../../../../fs/utils/external-ref-resolver.js";import{resolveMutuallyExclusiveProps as z}from"../../resolve-mutual-exclusion.js";function y(e,s,t,n){s in e&&e[s]&&typeof e[s]=="string"&&(/^https?:\/\/.*/.test(e[s])||n(new Error(`Invalid ${t} URL: "${e[s]}". ${t} must start with "http://" or "https://".`)))}function V(e,s){if("access"in e&&e.access&&typeof e.access=="object"){const t=e.access;y(t,"logoutReturnUrl","access.logoutReturnUrl",s),y(t,"residency","access.residency",s);const n=["requiresLogin","logoutReturnUrl","residency","sso","rbac"];for(const r of n)r in t&&t[r]!==void 0&&r in e&&e[r]!==void 0&&s(new Error(`Property '${r}' is defined both at root level and in 'access' object. Please use 'access.${r}' to define this configuration.`))}}function Y(e){return _.compile(B.properties.graphql.properties.servers.items.properties.url)(e)}function $(e,s,t){if(v(e)&&Array.isArray(e.servers))for(const n of e.servers){const r=v(n)?n.url:void 0;if(typeof r=="string"&&!Y(r)){const a=e.servers.indexOf(n),c=`${s}.servers[${a}].url`;t(new Error(`Invalid ${c}: "${r}". It must be an absolute http:// or https:// URL.`))}}}function H(e,s){if($(e.graphql,"graphql",s),!!v(e.apis))for(const[t,n]of Object.entries(e.apis))v(n)&&$(n.graphql,`apis.${t}.graphql`,s)}function K(e,s){const t=[["",e],...Object.entries(e.env??{}).map(([n,r])=>[`env.${n}.`,r])];for(const[n,r]of t){const a=q(r);a&&s(new Error(`Invalid ${n}${a}.agent: it must set at least one option.`))}}async function he(e,s,t,n){const a=s.getFileInfo(e)?.realRelativePath||e;async function c(){const f=new G(s),m=C.join(s.cwd,a),l=await L({configPath:m,externalRefResolver:f}),h=await n(l.resolvedConfig);if(h===void 0)return l.resolvedConfig;const g=l.document?.source,j=[...g?await E({config:l,externalConfigTypes:S(h,l)}):[],...g?z(l.resolvedConfig,g):[]];for(const P of j){const R=F(P,s.cwd);P.severity==="warn"?d.warn(R):t(new Error(R))}return l.resolvedConfig}const o=s.exists(e)?await c():{},u=Z(o),w=await n(o);y(o,"residency","Residency",t),y(o,"logoutReturnUrl","Logout return URL",t),V(o,t),H(o,t),K(o,t);let p=w?D(w,o):o;p=X(p),p=Q(p,t);const{env:b}=p;if(b){const f=A.REDOCLY_ENV,m=b[f]||{},l=A.PUBLIC_REDOCLY_BRANCH_NAME||"",h=l?N(l):"",g=h&&b[`${M}${h}`]||{};p=I(p,g,m)}const i=ee(p,u);if(i.imports&&i.imports.length>0){d.warn("The 'imports' property is deprecated. Please use 'plugins' property instead.");const f=new Set([...i.plugins||[],...i.imports.map(m=>C.posix.join(m,"plugin.js"))]);i.plugins=Array.from(f),delete i.imports}if(i.catalog&&(d.warn("The 'catalog' property is deprecated. Please use 'catalogClassic' property instead."),i.catalogClassic={...i.catalog},delete i.catalog),i.scorecard&&(d.warn("The 'scorecard' property is deprecated. Please use 'scorecardClassic' property instead."),i.scorecardClassic=i.scorecard,delete i.scorecard),i.search?.ai){d.warn("The 'search.ai' property is deprecated. Please use 'aiAssistant' property instead.");const f={...i.search?.ai,...i.aiAssistant,suggestions:i.aiAssistant?.suggestions?.length?i.aiAssistant.suggestions:i.search?.ai.suggestions||[]};i.aiAssistant=f,delete i.search.ai}return W(i)}function W(e){const s={...e},n={..."access"in e&&e.access&&typeof e.access=="object"?e.access:{}},r=["requiresLogin","logoutReturnUrl","residency","sso","idps","rbac"],a=[];for(const c of r){const o=s[c];o!==void 0&&(a.push(c),c==="requiresLogin"&&n.requiresLogin===void 0&&(n.requiresLogin=o),c==="logoutReturnUrl"&&n.logoutReturnUrl===void 0&&(n.logoutReturnUrl=o),c==="residency"&&n.residency===void 0&&(n.residency=o),c==="sso"&&n.sso===void 0&&(n.sso=o),c==="idps"&&n.idps===void 0&&(n.idps=o),c==="rbac"&&n.rbac===void 0&&(n.rbac=o),delete s[c])}return a.length>0&&d.warn(`The following properties at root level are deprecated: ${a.join(", ")}. Please move them to the 'access' object.`),Object.keys(n).length>0&&(s.access=n),s}function X(e){const s=Object.entries(e.env??{});[e,...s.map(([,r])=>r)].some(r=>r?.mcp?.docs)&&d.warn("The 'mcp.docs' property is deprecated. Please use the 'mcp' properties instead.");const t=e.mcp?{...e,mcp:O(e.mcp)}:e;if(!e.env)return t;const n=s.map(([r,a])=>[r,a?.mcp?{...a,mcp:O(a.mcp)}:a]);return{...t,env:Object.fromEntries(n)}}function O(e){const s=e.docs??{},t={};(e.hide??s.hide)!==void 0&&(t.hide=e.hide===!0||s.hide===!0);const n=e.name??s.name;n!==void 0&&(t.name=n);const r=e.ignore??s.ignore;r!==void 0&&(t.ignore=r);const a=e.publicEndpoint??s.publicEndpoint;return a!==void 0&&(t.publicEndpoint=a),{...e,...t,docs:{...s,...t}}}function J(e){if(!v(e)||e.platform===void 0)return!1;const s=Object.keys(e).filter(t=>t!=="platform");return s.length>0&&s.every(t=>!Object.hasOwn(x.properties,t))}function Q(e,s){const t=Object.entries(e.env??{}),n=new Set;let r=!1;for(const o of[e,...t.map(([,u])=>u)])o?.reunite!==void 0&&o?.platform!==void 0&&n.add("Both 'platform' and 'reunite' are set. 'reunite' is ignored, so remove it."),[o?.rbac,o?.access?.rbac].some(J)&&(r=!0);for(const o of n)d.warn(o);r&&s(new Error("You are using an incorrect format of 'rbac:' configuration. See: https://redocly.com/docs/realm/access"));const a=T(e);if(!e.env)return a;const c=t.map(([o,u])=>[o,u&&T(u)]);return{...a,env:Object.fromEntries(c)}}function T(e){const s=k(e),t=e.rbac?{...s,rbac:U(e.rbac)}:s;return e.access?.rbac?{...t,access:{...e.access,rbac:U(e.access.rbac)}}:t}function U(e){const{reunite:s,...t}=e;return s===void 0?t:{...t,platform:e.platform??s}}function Z(e){if(!e.theme)return[];d.warn("The 'theme' property in redocly.yaml is deprecated. Please move all of the properties from 'theme' to the root of the config.");const s=[];for(const t of Object.keys(e.theme))e[t]==null?s.push(t):d.warn(`Detected both '${t}' and 'theme.${t}' properties in redocly.yaml. The 'theme.${t}' property will be ignored and needs to be removed or merged into the '${t}'.`);return s}function ee(e,s){if(!e.theme||s.length===0)return e;const t={...e};for(const n of s)t[n]=e.theme[n];return delete t.theme,t}export{W as ensureAccessBackwardsCompatibility,he as readAndValidateConfig};
@@ -1,6 +1,6 @@
1
1
  import type { Config, Node, ValidationType } from '@redocly/markdoc';
2
2
  import type { Store } from '../../store.js';
3
- import type { LifecycleContext, MarkdownParseInput, MarkdocResolveContext } from '../../types';
3
+ import type { LifecycleContext, MarkdownParseInput, MarkdocOptions, MarkdocResolveContext } from '../../types';
4
4
  import type { MarkdocError } from '../../../types/index.js';
5
5
  export type ResolvableType = ValidationType & {
6
6
  resolver?: string;
@@ -31,11 +31,11 @@ type MarkdocInfo = {
31
31
  codeSnippetLanguages?: Record<string, number>;
32
32
  codeWalkthroughLanguages?: Record<string, number>;
33
33
  };
34
- export declare function resolveAndValidateMarkdoc(parsedAstChunk: ParsedAstChunk, markdocOpts: Config | undefined, context: MarkdocResolveContext): Promise<MarkdocInfo>;
34
+ export declare function resolveAndValidateMarkdoc(parsedAstChunk: ParsedAstChunk, markdocOpts: MarkdocOptions | undefined, context: MarkdocResolveContext): Promise<MarkdocInfo>;
35
35
  export declare function getAst(relativePath: string, rawContent: string): ParsedAstChunk;
36
36
  export declare function extractMdFirstHeading(relativePath: string, context: LifecycleContext): Promise<string | undefined>;
37
37
  export declare function validateAllMarkdowns(store: Store, context?: LifecycleContext): Promise<void>;
38
- export declare function parseAndResolveMarkdoc(input: MarkdownParseInput, markdocOpts: Config | undefined, rootContext: MarkdocResolveContext, resource?: string): Promise<import("../../types").LoadResult<{
38
+ export declare function parseAndResolveMarkdoc(input: MarkdownParseInput, markdocOpts: MarkdocOptions | undefined, rootContext: MarkdocResolveContext, resource?: string): Promise<import("../../types").LoadResult<{
39
39
  ast: Node;
40
40
  info: MarkdocInfo;
41
41
  }>>;
@@ -1 +1 @@
1
- import N from"@redocly/markdoc";import{htmlTags as B}from"@redocly/markdoc/html";import*as M from"path";import{convertGithubAlertToAdmonition as H}from"@redocly/theme/markdoc/tags/admonition";import{GATED_MARKDOC_TAGS as F}from"../../constants/entitlements.js";import{logger as G}from"../../tools/notifiers/logger.js";import{reporter as K}from"../../tools/notifiers/reporter.js";import{sha1 as V}from"../../utils/crypto/sha1.js";import{formatMarkdocError as U}from"./errors.js";import{extractFirstHeading as q,SKIP as j,visit as $}from"./markdoc/plugins/utils.js";import{isPromptNode as z}from"../../../markdoc/helpers/guards/is-prompt-node.js";import{attributeResolvers as E}from"./attribute-resolvers/index.js";import{MdResolveError as J}from"./attribute-resolvers/md-resolve-error.js";import{normalizeHtmlHeadings as Q}from"./html/normalize-html-headings.js";import{resolveRawPartials as X}from"./markdoc/resolve-raw-partials.js";import{exampleContentTrees as Z,reparseExampleFences as tt}from"./markdoc/reparse-example-fences.js";import{EntitlementsProvider as at}from"../../entitlements/entitlements-provider.js";import{MARKDOC_PARTIALS_DEPS_KEY as rt}from"../../constants/common.js";import{getLinkOriginalAttrName as et}from"./attribute-resolvers/utils.js";import{createSourceLinesReader as ot}from"./create-source-lines-reader.js";const it="EMPTY";async function st(a,r,e){const f=at.instance(),{actions:n}=e,{relativePath:c,resolveErrors:S}=a,w={...e,readSourceLines:ot(a.rawContent)},g=new Set,u=new Set,l=new Set,b=new Set,s={},D=new Set,L={},_={};function P(t,o){const k=o||it;t[k]=(t[k]||0)+1}const T=[];a.resolveErrors.length=0;const A=Z(a.ast),I=t=>{H(t);const o=k();T.push(o.then(y=>{y?.sharedDataIds&&y.sharedDataIds.forEach(d=>g.add(d))}).catch(Y(t)));async function k(){const y=[];switch(t.type){case"fence":P(L,t.attributes.language);break;case"link":case"image":await E.nativeMdLink(t,t.type==="link"?"href":"src",c,w);break;case"tag":{if(!t.tag)break;const d=r?.tags?.[t.tag];if(!d){F[t.tag]&&!f.canAccessFeature(F[t.tag])&&(t.addError({level:"warning",id:"invalid-tag",message:`Undefined tag: ${t.tag}`}),t.tag="",t.type="error",t.attributes={});break}const v=t.tag==="html"?t.attributes.name:t.tag;if((t.tag==="html"?D:b).add(v),s[v]=(s[v]||0)+1,v==="code-snippet"&&P(L,t.attributes.language),d.attributes?.__idx&&(t.attributes.__idx=s[t.tag]),d.dynamicComponentLib&&u.add(d.dynamicComponentLib),!d.attributes)break;if(v==="partial"&&t.attributes?.file){const i=et("file"),m=t[i]||t.attributes.file,h=m.startsWith("/")?m.slice(1):M.posix.normalize(M.posix.join(M.posix.dirname(c),m));l.add(h);const p=(n.getGlobalConfig(rt)||{})[h];if(p?.dynamicComponents)for(const R of p.dynamicComponents)u.add(R);if(p?.sharedDataDeps)for(const R of p.sharedDataDeps)g.add(R)}for(const[i,m]of Object.entries(d.attributes)){const h=m.type;if(h&&(h.resolver||m.resolver)){const x=E[h.resolver||m.resolver],p=await x?.(t,i,c,w);p?.sharedDataId&&y.push(p.sharedDataId)}}if(v==="code-walkthrough")for(const i of t.attributes.resolvedFilesets||[])for(const m of i.files||[])P(_,m.language);const O=t.attributes?.attrs;if(O&&t.tag==="html")for(const i of Object.keys(O))i==="src"||i==="srcSet"?await E.htmlSourceAttribute(t,i,c,w):i==="href"&&await E.htmlHref(t,i,c,w);break}}return{sharedDataIds:y}}};function Y(t){return async o=>{if(!(o instanceof J)){await K.panicOnBuild(o.message);return}S.push(U({type:"resolve_link",meta:{...o.meta,link:o.meta.link??o.meta.rawLink},lines:t.location?[t.location.start.line,t.location.end.line]:[],location:t.location,error:{id:"",level:"error",message:o.message,location:t.location}},a.relativePath,a.rawContent))}}$(a.ast,t=>(I(t),z(t)?j:void 0));for(const t of A)$(t,o=>(H(o),o.type==="tag"&&I(o),z(o)?j:void 0));return await Promise.all(T),a.sharedDataDeps=g,a.dynamicMarkdocComponents=u,a.validatedAtRevision<n.buildRevision&&(a.markdocErrors=[a.ast,...A].flatMap(t=>N.validate(t,r)).map(t=>U(t,c,a.rawContent)),a.validatedAtRevision=n.buildRevision),{sharedDataDeps:a.sharedDataDeps,dynamicMarkdocComponents:Array.from(a.dynamicMarkdocComponents?.values()??[]),partials:Array.from(l),tagList:Array.from(b),htmlTagsList:Array.from(D),tagOccurrence:s,codeSnippetLanguages:L,codeWalkthroughLanguages:_}}const C="unclosed-html",nt={html:B({errorTag:C}),allowIndentation:!0,allowComments:!0};function W(a,r){const e=N.parse(a,{...nt,...r});return ct(e),Q(e),e}function ct(a){for(const r of a.walk())r.type!=="tag"||r.tag!==C||(r.type="error",r.errors.push({id:"parse-error",level:"critical",message:String(r.attributes.message),location:r.location}))}function lt(a,r){const e=W(r,{file:a,slots:!0});return tt(e,n=>W(n,{file:a})),{ast:e,rawContent:r,resolveErrors:[],markdocErrors:[],relativePath:a,sharedDataDeps:void 0,validatedAtRevision:-1}}async function Tt(a,r){const{data:e}=await r.cache.load(a,"markdown-ast");return q(e.ast)}async function At(a,r){K.clearMarkdocProblems();const e=a.getAllRoutes();let f=0;const n=G.isInteractive();for(const c of e)await a.resolveRouteStaticData(c,r,!0),f++,n&&f%100===0&&G.logInFooter("validate",` \u{1F50D} Status: validating markdoc (${f}/${e.length})`)}async function It(a,r,e,f){const n=a.content?V(a.content):"";return await e.context.cache.load(f||a.relativePath,{loader:S,name:"markdown-inline-parser"},[n,String(e.actions.buildRevision)]);async function S(w,g,u){let l;if(a.content){const s=await g.getConfig(),D=await X(a.content,a.relativePath,s.markdown?.partialsFolders,g);l=lt(a.relativePath,D)}else l=(await g.cache.load(a.relativePath,"markdown-ast")).data;let b={};if(e.actions.buildRevision!==0&&(b=await st(l,r,e)),!a.isVirtual){for(const s of l.markdocErrors)u(s);for(const s of l.resolveErrors)u(s)}return{ast:l.ast,info:b}}}export{Tt as extractMdFirstHeading,lt as getAst,It as parseAndResolveMarkdoc,st as resolveAndValidateMarkdoc,At as validateAllMarkdowns};
1
+ import N from"@redocly/markdoc";import{htmlTags as $}from"@redocly/markdoc/html";import*as P from"path";import{convertGithubAlertToAdmonition as A}from"@redocly/theme/markdoc/tags/admonition";import{logger as H}from"../../tools/notifiers/logger.js";import{reporter as F}from"../../tools/notifiers/reporter.js";import{sha1 as B}from"../../utils/crypto/sha1.js";import{formatMarkdocError as G}from"./errors.js";import{extractFirstHeading as C,SKIP as j,visit as K}from"./markdoc/plugins/utils.js";import{isPromptNode as U}from"../../../markdoc/helpers/guards/is-prompt-node.js";import{attributeResolvers as L}from"./attribute-resolvers/index.js";import{MdResolveError as V}from"./attribute-resolvers/md-resolve-error.js";import{normalizeHtmlHeadings as q}from"./html/normalize-html-headings.js";import{resolveRawPartials as J}from"./markdoc/resolve-raw-partials.js";import{exampleContentTrees as Q,reparseExampleFences as X}from"./markdoc/reparse-example-fences.js";import{MARKDOC_PARTIALS_DEPS_KEY as Z}from"../../constants/common.js";import{getLinkOriginalAttrName as tt}from"./attribute-resolvers/utils.js";import{createSourceLinesReader as at}from"./create-source-lines-reader.js";const et="EMPTY";async function rt(a,e,r){const{actions:n}=r,{relativePath:s,resolveErrors:D}=a,u={...r,readSourceLines:at(a.rawContent)},k=new Set,d=new Set,w=new Set,c=new Set,g={},m=new Set,b={},M={};function S(t,o){const E=o||et;t[E]=(t[E]||0)+1}const _=[];a.resolveErrors.length=0;const T=Q(a.ast),I=t=>{A(t);const o=E();_.push(o.then(y=>{y?.sharedDataIds&&y.sharedDataIds.forEach(f=>k.add(f))}).catch(Y(t)));async function E(){const y=[];switch(t.type){case"fence":S(b,t.attributes.language);break;case"link":case"image":await L.nativeMdLink(t,t.type==="link"?"href":"src",s,u);break;case"tag":{if(!t.tag)break;const f=e?.tags?.[t.tag];if(!f){const i=e?.planDeniedTags?.[t.tag];i&&(t.addError({level:"warning",id:"invalid-tag",message:i}),t.tag="",t.type="error",t.attributes={});break}const v=t.tag==="html"?t.attributes.name:t.tag;if((t.tag==="html"?m:c).add(v),g[v]=(g[v]||0)+1,v==="code-snippet"&&S(b,t.attributes.language),f.attributes?.__idx&&(t.attributes.__idx=g[t.tag]),f.dynamicComponentLib&&d.add(f.dynamicComponentLib),!f.attributes)break;if(v==="partial"&&t.attributes?.file){const i=tt("file"),l=t[i]||t.attributes.file,h=l.startsWith("/")?l.slice(1):P.posix.normalize(P.posix.join(P.posix.dirname(s),l));w.add(h);const p=(n.getGlobalConfig(Z)||{})[h];if(p?.dynamicComponents)for(const R of p.dynamicComponents)d.add(R);if(p?.sharedDataDeps)for(const R of p.sharedDataDeps)k.add(R)}for(const[i,l]of Object.entries(f.attributes)){const h=l.type;if(h&&(h.resolver||l.resolver)){const O=L[h.resolver||l.resolver],p=await O?.(t,i,s,u);p?.sharedDataId&&y.push(p.sharedDataId)}}if(v==="code-walkthrough")for(const i of t.attributes.resolvedFilesets||[])for(const l of i.files||[])S(M,l.language);const x=t.attributes?.attrs;if(x&&t.tag==="html")for(const i of Object.keys(x))i==="src"||i==="srcSet"?await L.htmlSourceAttribute(t,i,s,u):i==="href"&&await L.htmlHref(t,i,s,u);break}}return{sharedDataIds:y}}};function Y(t){return async o=>{if(!(o instanceof V)){await F.panicOnBuild(o.message);return}D.push(G({type:"resolve_link",meta:{...o.meta,link:o.meta.link??o.meta.rawLink},lines:t.location?[t.location.start.line,t.location.end.line]:[],location:t.location,error:{id:"",level:"error",message:o.message,location:t.location}},a.relativePath,a.rawContent))}}K(a.ast,t=>(I(t),U(t)?j:void 0));for(const t of T)K(t,o=>(A(o),o.type==="tag"&&I(o),U(o)?j:void 0));return await Promise.all(_),a.sharedDataDeps=k,a.dynamicMarkdocComponents=d,a.validatedAtRevision<n.buildRevision&&(a.markdocErrors=[a.ast,...T].flatMap(t=>N.validate(t,e)).map(t=>G(t,s,a.rawContent)),a.validatedAtRevision=n.buildRevision),{sharedDataDeps:a.sharedDataDeps,dynamicMarkdocComponents:Array.from(a.dynamicMarkdocComponents?.values()??[]),partials:Array.from(w),tagList:Array.from(c),htmlTagsList:Array.from(m),tagOccurrence:g,codeSnippetLanguages:b,codeWalkthroughLanguages:M}}const z="unclosed-html",ot={html:$({errorTag:z}),allowIndentation:!0,allowComments:!0};function W(a,e){const r=N.parse(a,{...ot,...e});return it(r),q(r),r}function it(a){for(const e of a.walk())e.type!=="tag"||e.tag!==z||(e.type="error",e.errors.push({id:"parse-error",level:"critical",message:String(e.attributes.message),location:e.location}))}function st(a,e){const r=W(e,{file:a,slots:!0});return X(r,s=>W(s,{file:a})),{ast:r,rawContent:e,resolveErrors:[],markdocErrors:[],relativePath:a,sharedDataDeps:void 0,validatedAtRevision:-1}}async function St(a,e){const{data:r}=await e.cache.load(a,"markdown-ast");return C(r.ast)}async function Rt(a,e){F.clearMarkdocProblems();const r=a.getAllRoutes();let n=0;const s=H.isInteractive();for(const D of r)await a.resolveRouteStaticData(D,e,!0),n++,s&&n%100===0&&H.logInFooter("validate",` \u{1F50D} Status: validating markdoc (${n}/${r.length})`)}async function Pt(a,e,r,n){const s=a.content?B(a.content):"";return await r.context.cache.load(n||a.relativePath,{loader:u,name:"markdown-inline-parser"},[s,String(r.actions.buildRevision)]);async function u(k,d,w){let c;if(a.content){const m=await d.getConfig(),b=await J(a.content,a.relativePath,m.markdown?.partialsFolders,d);c=st(a.relativePath,b)}else c=(await d.cache.load(a.relativePath,"markdown-ast")).data;let g={};if(r.actions.buildRevision!==0&&(g=await rt(c,e,r)),!a.isVirtual){for(const m of c.markdocErrors)w(m);for(const m of c.resolveErrors)w(m)}return{ast:c.ast,info:g}}}export{St as extractMdFirstHeading,st as getAst,Pt as parseAndResolveMarkdoc,rt as resolveAndValidateMarkdoc,Rt as validateAllMarkdowns};
@@ -50,5 +50,7 @@ export declare function getMarkdocOptions(serverOutDir?: string, _templateId?: s
50
50
  }): string;
51
51
  };
52
52
  };
53
+ /** The tags the project schema defines, under the names pages use them by; built-in names included. */
54
+ userTagNames: string[];
53
55
  }>;
54
56
  //# sourceMappingURL=markdoc-options.d.ts.map
@@ -1 +1 @@
1
- import f from"@redocly/markdoc";import*as p from"@redocly/theme/markdoc/default";import{reporter as g}from"../../../tools/notifiers/reporter.js";import*as u from"../../../../markdoc/nodes/index.js";import d from"../../../../markdoc/tags/index.js";import{normalizeCustomTags as l}from"../../../../markdoc/helpers/normalize-custom-tags.js";import{includes as h}from"./functions/includes.js";import{importUserTags as O}from"./import-user-tags.js";import{concat as y}from"./functions/concat.js";const T=p.tags;function b(s){const{tags:c,functions:e={},...r}=s,n={...c,...r},a=Object.entries(n),o=[],t=[];for(const[i,m]of a)i in f.nodes?o.push([i,m]):t.push([i,m]);return{nodes:Object.fromEntries(o),tags:Object.fromEntries(t),functions:e}}async function _(s="../../../esbuild/cache/server/",c=""){let e;try{e=(await O(s)).schema}catch(t){throw t.code==="ERR_MODULE_NOT_FOUND"?(g.printErrors(),new Error("Please fix the errors above and try again.")):t}const{tags:r={},nodes:n={},functions:a={}}=b(e),o={tags:{schemaDefinition:{render:"SchemaDefinition",attributes:{schemaRef:{type:String},exampleRef:{type:String},showReadOnly:{type:Boolean},showWriteOnly:{type:Boolean}}}}};return{nodes:{...u,...n},tags:{...d,...T,...l(r),...o.tags},functions:{...f.functions,...a,includes:h,concat:y}}}export{_ as getMarkdocOptions};
1
+ import f from"@redocly/markdoc";import*as g from"@redocly/theme/markdoc/default";import{reporter as p}from"../../../tools/notifiers/reporter.js";import*as u from"../../../../markdoc/nodes/index.js";import d from"../../../../markdoc/tags/index.js";import{normalizeCustomTags as l}from"../../../../markdoc/helpers/normalize-custom-tags.js";import{includes as h}from"./functions/includes.js";import{importUserTags as O}from"./import-user-tags.js";import{concat as y}from"./functions/concat.js";const T=g.tags;function b(r){const{tags:c,functions:o={},...n}=r,a={...c,...n},i=Object.entries(a),t=[],s=[];for(const[e,m]of i)e in f.nodes?t.push([e,m]):s.push([e,m]);return{nodes:Object.fromEntries(t),tags:Object.fromEntries(s),functions:o}}async function S(r="../../../esbuild/cache/server/",c=""){let o;try{o=(await O(r)).schema}catch(e){throw e.code==="ERR_MODULE_NOT_FOUND"?(p.printErrors(),new Error("Please fix the errors above and try again.")):e}const{tags:n={},nodes:a={},functions:i={}}=b(o),t=l(n),s={tags:{schemaDefinition:{render:"SchemaDefinition",attributes:{schemaRef:{type:String},exampleRef:{type:String},showReadOnly:{type:Boolean},showWriteOnly:{type:Boolean}}}}};return{nodes:{...u,...a},tags:{...d,...T,...t,...s.tags},functions:{...f.functions,...i,includes:h,concat:y},userTagNames:Object.keys(t)}}export{S as getMarkdocOptions};
@@ -1,6 +1,9 @@
1
1
  import type { LifecycleContext, ProcessContentActions } from '../../../types';
2
2
  import type { CustomMcpToolsState } from '../types.js';
3
- /** Registers every file in an `@mcp` folder as one MCP tool, named after the file. */
3
+ /**
4
+ * Registers every file in an `@mcp` folder as one MCP tool, named after the file. Without custom
5
+ * MCP tools in the plan, each file is a warning and no tool.
6
+ */
4
7
  export declare function scanCustomMcpTools(actions: ProcessContentActions, context: LifecycleContext, state: CustomMcpToolsState): Promise<number>;
5
8
  export declare function resetCustomMcpTools(actions: Pick<ProcessContentActions, 'removeMcpTools'>, state: CustomMcpToolsState): void;
6
9
  //# sourceMappingURL=scan-custom-tools.d.ts.map
@@ -1 +1 @@
1
- import{basename as d,join as p}from"node:path";import{logger as f}from"../../../tools/notifiers/logger.js";import{reporter as s}from"../../../tools/notifiers/reporter.js";import{CODE_MODE_TOOL_NAMES as h}from"../codemode/constants.js";import{ALL_DEFAULT_TOOL_NAMES as O}from"../docs-mcp/tool-schemas.js";import{extractToolDefinition as T}from"./extract-tool-definition.js";const E=/(^|\/)@mcp\/.*\.(ts|js)$/,M=/^[a-zA-Z0-9_-]{1,64}$/,C=new Set([...h,...O]);async function g(o,a,n){_(o,n);const u=new Set(o.getMcpTools().map(r=>r.name)),l=new Map;for(const r of a.fs.scan(E)){if(r.isVirtual||r.relativePath.endsWith(".d.ts"))continue;const{relativePath:t}=r,e=d(t).replace(/\.(ts|js)$/,"");if(!M.test(e)){await s.panicOnBuildContentError(`Invalid MCP tool file "${t}": the tool name "${e}" is derived from the file name and may only contain letters, numbers, hyphens, and underscores (max 64 characters). Rename the file.`);continue}const c=l.get(e);if(c){await s.panicOnBuildContentError(`Duplicate MCP tool name "${e}": defined by both "${c}" and "${t}". Tool names are file names, so each file name must be unique across @mcp folders.`);continue}if(C.has(e)||u.has(e)){await s.panicOnBuildContentError(`Invalid MCP tool file "${t}": the tool name "${e}" is already used by a built-in MCP tool. Rename the file.`);continue}l.set(e,t);const m=p(o.contentDir,t),i=await T({toolName:e,absoluteSourcePath:m,contentDir:o.contentDir,serverOutDir:o.serverOutDir});if(!i.ok){await s.panicOnBuildContentError(`Invalid MCP tool file "${t}": ${i.errors.join(" ")}`);continue}!i.schema.outputSchema&&!n.warnedNoOutputSchemaTools.has(e)&&(n.warnedNoOutputSchemaTools.add(e),f.warn(`MCP tool "${e}" in %rp declares no \`outputSchema\`. Add one that describes the returned value.`,t)),o.addMcpTools(m,[i.schema]),n.registeredToolNames.push(e)}return n.registeredToolNames.length}function _(o,a){o.removeMcpTools(a.registeredToolNames),a.registeredToolNames=[]}export{_ as resetCustomMcpTools,g as scanCustomMcpTools};
1
+ import{basename as p,join as f}from"node:path";import{logger as d}from"../../../tools/notifiers/logger.js";import{reporter as i}from"../../../tools/notifiers/reporter.js";import{EntitlementsProvider as h}from"../../../entitlements/entitlements-provider.js";import{CODE_MODE_TOOL_NAMES as T}from"../codemode/constants.js";import{ALL_DEFAULT_TOOL_NAMES as M}from"../docs-mcp/tool-schemas.js";import{extractToolDefinition as O}from"./extract-tool-definition.js";const E=/(^|\/)@mcp\/.*\.(ts|js)$/,C=/^[a-zA-Z0-9_-]{1,64}$/,P=new Set([...T,...M]);async function b(t,r,n){_(t,n);const s=r.fs.scan(E).filter(e=>!e.isVirtual&&!e.relativePath.endsWith(".d.ts")).map(e=>e.relativePath);if(!h.instance().canUseCustomMcpTools()){for(const e of s)n.warnedPlanIgnoredFiles.has(e)||(n.warnedPlanIgnoredFiles.add(e),d.warn("Custom MCP tools are not in this project's plan, so %rp is ignored.",e));return 0}const u=new Set(t.getMcpTools().map(e=>e.name)),l=new Map;for(const e of s){const o=p(e).replace(/\.(ts|js)$/,"");if(!C.test(o)){await i.panicOnBuildContentError(`Invalid MCP tool file "${e}": the tool name "${o}" is derived from the file name and may only contain letters, numbers, hyphens, and underscores (max 64 characters). Rename the file.`);continue}const c=l.get(o);if(c){await i.panicOnBuildContentError(`Duplicate MCP tool name "${o}": defined by both "${c}" and "${e}". Tool names are file names, so each file name must be unique across @mcp folders.`);continue}if(P.has(o)||u.has(o)){await i.panicOnBuildContentError(`Invalid MCP tool file "${e}": the tool name "${o}" is already used by a built-in MCP tool. Rename the file.`);continue}l.set(o,e);const m=f(t.contentDir,e),a=await O({toolName:o,absoluteSourcePath:m,contentDir:t.contentDir,serverOutDir:t.serverOutDir});if(!a.ok){await i.panicOnBuildContentError(`Invalid MCP tool file "${e}": ${a.errors.join(" ")}`);continue}!a.schema.outputSchema&&!n.warnedNoOutputSchemaTools.has(o)&&(n.warnedNoOutputSchemaTools.add(o),d.warn(`MCP tool "${o}" in %rp declares no \`outputSchema\`. Add one that describes the returned value.`,e)),t.addMcpTools(m,[a.schema]),n.registeredToolNames.push(o)}return n.registeredToolNames.length}function _(t,r){t.removeMcpTools(r.registeredToolNames),r.registeredToolNames=[]}export{_ as resetCustomMcpTools,b as scanCustomMcpTools};
@@ -1 +1 @@
1
- import{fileURLToPath as U}from"node:url";import{dirname as $,join as D}from"node:path";import{MCP_ROUTE as k,PUBLIC_MCP_ROUTE as M}from"@redocly/theme/core/constants/mcp";import{logger as p}from"../../tools/notifiers/logger.js";import{reporter as F}from"../../tools/notifiers/reporter.js";import{isDefined as B}from"../../../utils/guards/is-defined.js";import{MCP_CREDENTIALS_HANDLER_ID as A,MCP_CREDENTIALS_ROUTE as V,MCP_DOCS_SERVER_HANDLER_ID as T,MCP_NOT_ALLOWED_TEMPLATE_ID as x}from"../../constants/mcp.js";import{bundledOpenApiDocumentsToMcpOpenApi as J,bundledGraphqlDocumentsToMcpOpenApi as W,buildGraphqlDescriptions as X,collectIgnoredRoutes as z,filterIgnoredApiDescriptions as P,getCleanedUpApiDescriptions as K,isMcpInRedirects as Q}from"./utils.js";import{getMcpMode as R,isMcpElicitationEnabled as Y,isMcpGatewayEnabled as Z}from"./utils/mode.js";import{getPublicMcpEndpointStatus as _}from"./utils/public-endpoint.js";import{findGatedToolNames as ee}from"./utils/find-gated-tool-names.js";import{getDefaultToolSchemas as oe}from"./docs-mcp/tool-schemas.js";import{EXECUTE_TOOL_SCHEMA as te}from"./codemode/tools/execute-schema.js";import{isGatewayCapabilityEnabled as ie,isGatewayEligible as re}from"./gateway-mcp/eligibility.js";import{resolveGatewayFetchLimits as se}from"./gateway-mcp/rate-limit/fetch-limiter/fetch-limits.js";import{resetCustomMcpTools as ne,scanCustomMcpTools as ae}from"./custom-tools/scan-custom-tools.js";import{resolveSiteBranding as ce}from"./handlers/credentials-page/site-branding.js";import{telemetryTraceStep as pe}from"../../../cli/telemetry/helpers/trace-step.js";import{DEFAULT_DOCS_MCP_SERVER_NAME as S}from"./constants.js";const b=$(U(import.meta.url));async function de(){let i;const m={registeredToolNames:[],warnedNoOutputSchemaTools:new Set};let u=0,f=!1;return{id:"mcp",async processContent(e,a){await pe("com.redocly.build.plugin.mcp",async s=>{const t=await a.getConfig(),{mcp:r,redirects:g}=t;if(s?.setAttribute("config",JSON.stringify(r||{})),s?.setAttribute("mcpMode",R()),s?.setAttribute("mcpGateway",String(Z())),r?.hide||r?.docs?.hide){ne(e,m);return}Q(g)&&await F.panicOnBuildContentError('The reserved route "/mcp" cannot be used in redirect configuration. Please remove any redirects involving "/mcp" from your redocly.yaml config.'),e.createTemplate(x,"@redocly/theme/layouts/McpNotAllowed");const l=!!t?.access?.requiresLogin,C=t?.access?.rbac||{},d=R(),c=Y(),{budgetPerExec:h}=se();if(!i){p.info("Configuring MCP servers...");const w=J(await e.loadApiDocuments(a)),O=W(await e.loadApiDocuments(a)),v=r?.docs?.ignore||[],L=K(P(w,v)),q=ie(r),E=new Map;for(const o of L){const H=o.definition.info?.title||"",j=o.definition.info?.version||"";E.set(o.relativePath,{name:H,description:typeof o.definition.info?.description=="string"?o.definition.info.description:"",version:j,servers:o.definition.servers||[],relativePath:o.relativePath,...q&&re(o.definition.info)?{fetchEligible:!0}:{}})}const y=X(P(O,v)),G=Object.values(t.products||{}).map(o=>o?.name).filter(B),I=t.l10n?.locales?.map(o=>o.code)??a.fs.localeFolders,N=oe({products:G,locales:I,requiresLogin:l,rbac:C,hasGraphqlApis:y.length>0,elicitationEnabled:c,hasCallableApis:E.values().some(o=>o.fetchEligible),feedbackHidden:t.feedback?.hide===!0});e.addMcpTools(D(b,"./docs-mcp/tools/index.js"),N),d==="code"&&e.addMcpTools(D(b,"./codemode/tools/execute.js"),[te]),i={apiDescriptionsMap:Object.fromEntries(E),graphqlDescriptions:y}}const n=await ae(e,a,m);s?.setAttribute("customToolsCount",String(n)),n!==u&&(u=n,n>0&&p.info(`Registered ${n} custom MCP tool${n===1?"":"s"} from @mcp folders`)),await le({actions:e,handlerPath:D(b,"./handlers/docs-mcp-handler.js"),apiDescriptionsMap:i.apiDescriptionsMap,graphqlDescriptions:i.graphqlDescriptions,mcpConfig:r,mcpMode:d,elicitationEnabled:c,gatewayFetchBudgetPerExec:h,publicEndpointStatus:_(t)}),f||(p.info("Registered Docs MCP Server endpoint at /mcp"),f=!0)})},async afterRoutesCreated(e,a){const s=await a.getConfig(),{mcp:t}=s,r=!t?.hide&&!t?.docs?.hide;e.markGatedMcpTools(await ee(e.getMcpTools())),e.setGlobalData({mcpData:{docs:{enabled:r,name:t?.docs?.name||S,publicEndpoint:_(s)==="served"}}})}}}var Oe=de;async function le({actions:i,handlerPath:m,apiDescriptionsMap:u,graphqlDescriptions:f,mcpConfig:e,mcpMode:a,elicitationEnabled:s,gatewayFetchBudgetPerExec:t,publicEndpointStatus:r}){i.createRequestHandler(T,m);const g=l=>async(C,d)=>{const c=z(d.getAllRoutes(),e?.docs?.ignore||[]);return c.length>0&&p.verbose(`mcp.docs.ignore: hiding ${c.length} page routes from MCP search`),{props:{config:{apiDescriptionsMap:u,graphqlDescriptions:f,mcpDocsServerName:e?.docs?.name||S,mcpMode:a,elicitationEnabled:s,gatewayFetchBudgetPerExec:t,searchIgnoredRoutes:c,...l?{isPublicEndpoint:l}:{}},serverOutDir:i.serverOutDir,tools:i.getMcpTools().map(({importPath:h,...n})=>n)}}};if(i.addApiRoute({slug:k,requestHandlerId:T,httpMethod:"all",getStaticData:g(!1)}),r==="no-protected-content"?p.info(`mcp.docs.publicEndpoint is enabled, but the project has no protected content - /mcp already serves anonymous users, skipping ${M}.`):r==="anonymous-denied"?p.info(`mcp.docs.publicEndpoint is enabled, but anonymous users are denied the MCP feature (rbac.features.mcp or requiresLogin) - skipping ${M}.`):r==="served"&&(i.addApiRoute({slug:M,requestHandlerId:T,httpMethod:"all",getStaticData:g(!0)}),p.verbose(`Registered public Docs MCP Server endpoint at ${M}`)),s){const l=D(b,"./handlers/mcp-credentials-handler.js");i.createRequestHandler(A,l),i.addApiRoute({slug:V,requestHandlerId:A,httpMethod:"all",getStaticData:async(C,d)=>{const{seo:c,colorMode:h}=d.getConfig(),{logo:n}=d.getGlobalData();return{props:{branding:ce({seo:c,logo:n,colorMode:h})}}}}),p.verbose("Registered MCP credentials endpoint at /mcp/credentials")}}export{Oe as default,de as mcpServerPlugin};
1
+ import{fileURLToPath as U}from"node:url";import{dirname as F,join as D}from"node:path";import{MCP_ROUTE as $,PUBLIC_MCP_ROUTE as M}from"@redocly/theme/core/constants/mcp";import{logger as p}from"../../tools/notifiers/logger.js";import{reporter as k}from"../../tools/notifiers/reporter.js";import{isDefined as B}from"../../../utils/guards/is-defined.js";import{MCP_CREDENTIALS_HANDLER_ID as P,MCP_CREDENTIALS_ROUTE as V,MCP_DOCS_SERVER_HANDLER_ID as T,MCP_NOT_ALLOWED_TEMPLATE_ID as x}from"../../constants/mcp.js";import{bundledOpenApiDocumentsToMcpOpenApi as J,bundledGraphqlDocumentsToMcpOpenApi as W,buildGraphqlDescriptions as X,collectIgnoredRoutes as z,filterIgnoredApiDescriptions as A,getCleanedUpApiDescriptions as K,isMcpInRedirects as Q}from"./utils.js";import{getMcpMode as R,isMcpElicitationEnabled as Y,isMcpGatewayEnabled as Z}from"./utils/mode.js";import{getPublicMcpEndpointStatus as S}from"./utils/public-endpoint.js";import{findGatedToolNames as ee}from"./utils/find-gated-tool-names.js";import{getDefaultToolSchemas as oe}from"./docs-mcp/tool-schemas.js";import{EXECUTE_TOOL_SCHEMA as te}from"./codemode/tools/execute-schema.js";import{isGatewayCapabilityEnabled as ie,isGatewayEligible as re}from"./gateway-mcp/eligibility.js";import{resolveGatewayFetchLimits as se}from"./gateway-mcp/rate-limit/fetch-limiter/fetch-limits.js";import{resetCustomMcpTools as ne,scanCustomMcpTools as ae}from"./custom-tools/scan-custom-tools.js";import{resolveSiteBranding as ce}from"./handlers/credentials-page/site-branding.js";import{telemetryTraceStep as pe}from"../../../cli/telemetry/helpers/trace-step.js";import{DEFAULT_DOCS_MCP_SERVER_NAME as _}from"./constants.js";const b=F(U(import.meta.url));async function de(){let i;const m={registeredToolNames:[],warnedNoOutputSchemaTools:new Set,warnedPlanIgnoredFiles:new Set};let u=0,f=!1;return{id:"mcp",async processContent(e,a){await pe("com.redocly.build.plugin.mcp",async s=>{const t=await a.getConfig(),{mcp:r,redirects:g}=t;if(s?.setAttribute("config",JSON.stringify(r||{})),s?.setAttribute("mcpMode",R()),s?.setAttribute("mcpGateway",String(Z())),r?.hide||r?.docs?.hide){ne(e,m);return}Q(g)&&await k.panicOnBuildContentError('The reserved route "/mcp" cannot be used in redirect configuration. Please remove any redirects involving "/mcp" from your redocly.yaml config.'),e.createTemplate(x,"@redocly/theme/layouts/McpNotAllowed");const l=!!t?.access?.requiresLogin,C=t?.access?.rbac||{},d=R(),c=Y(),{budgetPerExec:h}=se();if(!i){p.info("Configuring MCP servers...");const w=J(await e.loadApiDocuments(a)),O=W(await e.loadApiDocuments(a)),v=r?.docs?.ignore||[],L=K(A(w,v)),q=ie(r),E=new Map;for(const o of L){const H=o.definition.info?.title||"",j=o.definition.info?.version||"";E.set(o.relativePath,{name:H,description:typeof o.definition.info?.description=="string"?o.definition.info.description:"",version:j,servers:o.definition.servers||[],relativePath:o.relativePath,...q&&re(o.definition.info)?{fetchEligible:!0}:{}})}const y=X(A(O,v)),I=Object.values(t.products||{}).map(o=>o?.name).filter(B),G=t.l10n?.locales?.map(o=>o.code)??a.fs.localeFolders,N=oe({products:I,locales:G,requiresLogin:l,rbac:C,hasGraphqlApis:y.length>0,elicitationEnabled:c,hasCallableApis:E.values().some(o=>o.fetchEligible),feedbackHidden:t.feedback?.hide===!0});e.addMcpTools(D(b,"./docs-mcp/tools/index.js"),N),d==="code"&&e.addMcpTools(D(b,"./codemode/tools/execute.js"),[te]),i={apiDescriptionsMap:Object.fromEntries(E),graphqlDescriptions:y}}const n=await ae(e,a,m);s?.setAttribute("customToolsCount",String(n)),n!==u&&(u=n,n>0&&p.info(`Registered ${n} custom MCP tool${n===1?"":"s"} from @mcp folders`)),await le({actions:e,handlerPath:D(b,"./handlers/docs-mcp-handler.js"),apiDescriptionsMap:i.apiDescriptionsMap,graphqlDescriptions:i.graphqlDescriptions,mcpConfig:r,mcpMode:d,elicitationEnabled:c,gatewayFetchBudgetPerExec:h,publicEndpointStatus:S(t)}),f||(p.info("Registered Docs MCP Server endpoint at /mcp"),f=!0)})},async afterRoutesCreated(e,a){const s=await a.getConfig(),{mcp:t}=s,r=!t?.hide&&!t?.docs?.hide;e.markGatedMcpTools(await ee(e.getMcpTools())),e.setGlobalData({mcpData:{docs:{enabled:r,name:t?.docs?.name||_,publicEndpoint:S(s)==="served"}}})}}}var Oe=de;async function le({actions:i,handlerPath:m,apiDescriptionsMap:u,graphqlDescriptions:f,mcpConfig:e,mcpMode:a,elicitationEnabled:s,gatewayFetchBudgetPerExec:t,publicEndpointStatus:r}){i.createRequestHandler(T,m);const g=l=>async(C,d)=>{const c=z(d.getAllRoutes(),e?.docs?.ignore||[]);return c.length>0&&p.verbose(`mcp.docs.ignore: hiding ${c.length} page routes from MCP search`),{props:{config:{apiDescriptionsMap:u,graphqlDescriptions:f,mcpDocsServerName:e?.docs?.name||_,mcpMode:a,elicitationEnabled:s,gatewayFetchBudgetPerExec:t,searchIgnoredRoutes:c,...l?{isPublicEndpoint:l}:{}},serverOutDir:i.serverOutDir,tools:i.getMcpTools().map(({importPath:h,...n})=>n)}}};if(i.addApiRoute({slug:$,requestHandlerId:T,httpMethod:"all",getStaticData:g(!1)}),r==="no-protected-content"?p.info(`mcp.docs.publicEndpoint is enabled, but the project has no protected content - /mcp already serves anonymous users, skipping ${M}.`):r==="anonymous-denied"?p.info(`mcp.docs.publicEndpoint is enabled, but anonymous users are denied the MCP feature (rbac.features.mcp or requiresLogin) - skipping ${M}.`):r==="served"&&(i.addApiRoute({slug:M,requestHandlerId:T,httpMethod:"all",getStaticData:g(!0)}),p.verbose(`Registered public Docs MCP Server endpoint at ${M}`)),s){const l=D(b,"./handlers/mcp-credentials-handler.js");i.createRequestHandler(P,l),i.addApiRoute({slug:V,requestHandlerId:P,httpMethod:"all",getStaticData:async(C,d)=>{const{seo:c,colorMode:h}=d.getConfig(),{logo:n}=d.getGlobalData();return{props:{branding:ce({seo:c,logo:n,colorMode:h})}}}}),p.verbose("Registered MCP credentials endpoint at /mcp/credentials")}}export{Oe as default,de as mcpServerPlugin};
@@ -143,6 +143,7 @@ export type McpToolWorkerParams = Omit<McpToolExecutionParams, 'context'> & {
143
143
  export type CustomMcpToolsState = {
144
144
  registeredToolNames: string[];
145
145
  warnedNoOutputSchemaTools: Set<string>;
146
+ warnedPlanIgnoredFiles: Set<string>;
146
147
  };
147
148
  export type ToolDefinitionValidationResult = {
148
149
  ok: true;
@@ -1 +1 @@
1
- import k from"@redocly/markdoc";import{writeFileSync as D}from"node:fs";import{readFile as R}from"node:fs/promises";import{join as g}from"node:path";import{parseAndResolveMarkdoc as F}from"./plugins/markdown/compiler.js";import{getPathnameForLocale as L}from"@redocly/theme/core/utils";import{DEFAULT_LOCALE_PLACEHOLDER as m}from"../constants/common.js";import{DEFAULT_TITLE as H,MARKDOC_PARTIALS_DATA_KEY as y,MARKDOC_PARTIALS_DEPS_KEY as G}from"./constants/common.js";import{GATED_MARKDOC_TAGS as S}from"./constants/entitlements.js";import{isObject as _}from"../utils/guards/is-object.js";import{mapObject as N}from"../utils/object/map-object.js";import{getValueDeep as v}from"../utils/object/get-value-deep.js";import{removeTrailingSlash as B}from"../utils/url/remove-trailing-slash.js";import{normalizeRouteSlug as d}from"../utils/path/normalize-route-slug.js";import{isLocalLink as E}from"../utils/path/is-local-link.js";import{reporter as C}from"./tools/notifiers/reporter.js";import{logger as u}from"./tools/notifiers/logger.js";import{sha1 as I}from"./utils/crypto/sha1.js";import{FileNotFoundError as j}from"./utils/fs.js";import{resolveAssetPath as V}from"./utils/resolve-asset-path.js";import{envConfig as q,setEnv as J}from"./config/env-config.js";import{KvService as U}from"./persistence/kv/services/kv-service.js";import{SandboxContext as x}from"./utils/sandbox-context.js";import{isAllowedEnv as K}from"./utils/envs/get-api-route-allowed-env-variables.js";import{ensureDir as $,writeSharedData as W}from"./utils/index.js";import{renderComponents as z}from"./ssr/render.js";import{readStaticData as Y,writeStaticData as Z}from"./utils/static-data.js";import{getMarkdocOptions as Q}from"./plugins/markdown/markdoc/markdoc-options.js";import{EntitlementsProvider as P}from"./entitlements/entitlements-provider.js";import{isRouteReserved as X}from"./plugins/get-reserved-routes.js";import{isL10nPath as ee}from"./fs/utils/is-l10n-path.js";import{resolveGlobMapValue as te}from"./utils/globs.js";import{createDefaultStoreConfig as se,resolveConfigEntries as re,resolveStoreConfig as oe}from"./store-config.js";import{findRedirect as ae}from"./utils/redirects/find-redirect.js";import{followRedirectChain as ie}from"./utils/redirects/follow-redirect-chain.js";import{addWildcardRedirectToTree as ne}from"./utils/redirects/add-wildcard-redirect-to-tree.js";import{telemetryTraceStep as ce}from"../cli/telemetry/helpers/trace-step.js";const A={routesBySlug:"map",staticFilePaths:"object",apiRoutes:"object",middleware:"object",routesByFsPath:"map",routesSharedData:"map",globalData:"object",ssr:"object",searchFacets:"map",routesPartials:"map",mcpToolHandlers:"map",skills:"map",devLogin:"object"},b="store.json",O="store-config.json",T="PLAN_GATES",le=["OAUTH_CLIENT_ID","OAUTH_CLIENT_SECRET","ORGANIZATION_SLUG","ORGANIZATION_ID","ORG_ID"],We="userDefinedApiFunctions";class w{routesBySlug=new Map;routeAliases=new Map;staticFilePaths={};replacedEnvVars={};unsetEnvVars=new Set;lifecycleContext;newRoutes=[];#t={};routesByFsPath=new Map;apiRoutes=[];middleware=[];routesSharedData=new Map;sharedDataDeps=new Map;sharedDataMarkdocComponents=new Map;routesDynamicComponents=new Map;routesPartials=new Map;ssr={preBodyTags:[],postBodyTags:[],headTags:[]};searchFacets=new Map;searchEngine;templates=new Map;browserPlugins=new Set;apiRoutesRequestHandlers=new Map;mcpToolHandlers=new Map;skills=new Map;serverPropsGetters=new Map;pagePropsGetters=new Map;listeners=new Map;globalData={};devLogin=!1;#a=void 0;config=se();configFile;#i;serverMode;serverOutDir;outdir;buildRevision=0;hasSitemap=!1;compilationErrors=[];#n;userCodeReady;#s=Promise.resolve();#c;#l=Promise.resolve();#d;#h=Promise.resolve();#u;#e=!1;#r=0;#f=0;#o=new Map;constructor({outdir:e,contentDir:t,serverMode:s=!1,serverOutDir:r}){this.#i=t,this.outdir=e,this.serverMode=s,this.serverOutDir=r,x.register({serverOutDir:r,readRoots:[e,process.cwd()]}),this.userCodeReady=new Promise(o=>{this.#n=o})}on(e,t){const s=this.listeners.get(e);s?s.add(t):this.listeners.set(e,new Set([t]))}queueEvent=(e,t,...s)=>{this.#o.set(e+String(t),[e,t,...s])};runListeners=(e,t,...s)=>{for(const r of this.listeners.get(e)||new Set)t?r(t,...s):r(...s)};startPluginsRun(){this.clear(),this.#s=new Promise(e=>{this.#c=e})}waitForPluginsLifecycle(){return Promise.all([this.#s,this.#l,this.#h])}waitForPluginsRun(){return this.#s}finishPluginsRun(){this.#c?.();for(const e of this.#o.values())this.runListeners(...e);this.#o.clear()}startEsbuildRun(){this.#l=new Promise(e=>{this.#d=e})}finishEsbuildRun(){this.#d?.()}markRequestHandlersEntryOutdated(){this.#r++,!this.#e&&(this.#e=!0,this.#h=new Promise(e=>{this.#u=e}))}noteRequestHandlersEntryBuildStart(){this.#f=this.#r}markRequestHandlersEntryUpdated(){this.#e&&(this.#r>this.#f||(this.#e=!1,this.#u?.()))}get contentDir(){if(this.serverMode)throw new Error("contentDir should not be used in server mode");return this.#i}markUserCodeReady(){this.#n?.(!0)}async reloadMarkdocOptions(){await ce("com.redocly.build.reloadMarkdocOptions",async()=>{const e=P.instance(),t=await Q(this.serverOutDir),s=Object.fromEntries(Object.entries(t.tags).filter(([r])=>S[r]!=null?e.canAccessFeature(S[r]):!0));this.#a={...t,tags:s}})}get markdocOptions(){return{...this.#a,partials:this.getGlobalConfig(y),themeConfig:this.config.markdown}}setGlobalData=e=>{const t=this.globalData,s={...this.globalData,...e};this.globalData=s,JSON.stringify(s)!==JSON.stringify(t)&&this.queueEvent("global-data-updated",void 0,s)};getGlobalData=()=>this.globalData;getKv=async()=>U.getInstance({baseDbDir:this.serverOutDir});parseMarkdoc=async({input:e,context:t,deps:s,resource:r})=>{const{data:{info:o,ast:a},compoundHash:c}=await F(e,this.markdocOptions,{actions:this,context:t},r);for(const i of o.sharedDataDeps||[]){for(const n of s?.routeSlugs||[])this.addRouteSharedData(n,i,i);for(const n of s?.sharedDataIds||[]){const l=this.sharedDataDeps.get(n)||new Set;l.add(i),this.sharedDataDeps.set(n,l)}}for(const i of o.dynamicMarkdocComponents||[]){for(const n of s?.routeSlugs||[]){const l=this.routesDynamicComponents.get(n)||new Set;l.add(i),this.routesDynamicComponents.set(n,l)}for(const n of s?.sharedDataIds||[]){const l=this.sharedDataMarkdocComponents.get(n)||new Set;l.add(i),this.sharedDataMarkdocComponents.set(n,l)}}if(s?.routeSlugs&&o.partials?.length)for(const i of s.routeSlugs){const n=this.routesPartials.get(i)||[];for(const l of o.partials)n.includes(l)||n.push(l);this.routesPartials.set(i,n)}return{info:o,ast:a,compoundHash:c}};async loadApiDocuments(e){return(await e.cache.load(".","api-docs")).data}setSearchEngine(e){this.searchEngine=e}setSearchFacets=e=>{this.searchFacets=e};setStaticFilePaths=e=>{this.staticFilePaths=e};setGlobalConfig=e=>{const t=Object.keys(e);for(const a of t)for(const c in this.replacedEnvVars)if(c===a||c.startsWith(`${a}:`)){const i=c.split(":"),{error:n,value:l}=v(e,i);(n||l!==this.replacedEnvVars[c].replaced)&&delete this.replacedEnvVars[c]}const{config:s,unsetEnvVars:r,replacedValues:o}=re(e);for(const a of r)this.unsetEnvVars.add(a);Object.assign(this.replacedEnvVars,o),Object.assign(this.config,s)};getConfig=()=>this.config;getGlobalConfig=e=>this.config[e];getSearchFacets=()=>this.searchFacets;addRedirect=(e,t,s={})=>{if(!P.instance().canAccessFeature("redirects")&&e!=="/")return;this.config.redirects||(this.config.redirects={});const a=d(e).toLowerCase();this.config.redirects[a]=t;const{trackOriginalSource:c=!0}=s,i=this.getGlobalConfig("originalRedirectSources");c&&Array.isArray(i)&&!i.includes(a)&&i.push(a),a.endsWith("*")&&ne(this.config.wildcardRedirectsTree,a)};getRedirect=e=>{const t=d(e).toLowerCase(),s=ae(t,this.config.redirects,this.config.wildcardRedirectsTree,this.staticFilePaths);if(!s)return null;if(E(s.to)){const r=d(s.to).toLowerCase();if(!r.endsWith("*")&&ie(r,[t],this.config.redirects,this.config.wildcardRedirectsTree).type==="cycle")return null}return{to:s.to,type:s.type}};createSharedData=async(e,t,s)=>{if(s&&this.#t[e]===s)return e;const r=JSON.stringify(t),o=s??I(r);return this.#t[e]===o||(this.#t[e]=o,await W(e,r,this.outdir),this.queueEvent("shared-data-updated",e)),e};addRouteSharedData=(e,t,s)=>{const r=B(e),o=this.routesSharedData.get(r)||{};o[t]=s,this.routesSharedData.set(r,o),u.verbose(`Adding shared data to ${e}, ${t}, ${s}`)};getRouteSharedDataByFsPath=e=>{const t=this.routesByFsPath.get(e);return t?this.routesSharedData.get(t)||{}:{}};getPartialsForRoute=e=>{const t=this.getGlobalConfig(y)||{},s=this.routesPartials.get(e);if(!s||s.length===0)return{};const r=this.getGlobalConfig(G)||{},o=new Set(s),a=Array.from(s);for(let i=0;i<a.length;i++){const n=a[i],l=r[n]?.partials??[];for(const h of l)o.has(h)||(o.add(h),a.push(h))}const c={};for(const i of o)t[i]&&(c[i]=t[i]);return c};addRoute=e=>{const s={...te(e.fsPath,this.config.metadataGlobs),...e.metadata||{}};this.newRoutes.push({...e,metadata:s}),u.verbose("Created route %s",e.slug)};addRouteSharedDataToAllLocales=(e,t,s)=>{const r=[m,...this.lifecycleContext?.fs.localeFolders||[]].map(o=>({code:o,name:o}));for(const o of r){const a=L(e,m,o.code,r);this.addRouteSharedData(a,t,s)}};addApiRoute=e=>{this.apiRoutes.push(e),u.verbose("Created API route %s",e.slug)};addMcpTools=(e,t)=>{for(const s of t){const r=this.mcpToolHandlers.get(s.name);r&&r.importPath!==e&&u.warn('MCP tool "%s" from %s overwrites the tool registered from %s',s.name,e,r.importPath);const o=s.hasAvailabilityGate??(r?.importPath===e?r.hasAvailabilityGate:void 0);this.mcpToolHandlers.set(s.name,{...s,importPath:e,hasAvailabilityGate:o}),u.verbose("Created MCP tool %s",s.name)}};getMcpTools=()=>Array.from(this.mcpToolHandlers.values());markGatedMcpTools=e=>{for(const t of e){const s=this.mcpToolHandlers.get(t);s&&this.mcpToolHandlers.set(t,{...s,hasAvailabilityGate:!0})}};addSkills=e=>{for(const t of e)this.skills.set(t.slug,t),u.verbose("Discovered skill %s",t.slug)};getSkills=()=>Array.from(this.skills.values());removeMcpTools=e=>{for(const t of e)this.mcpToolHandlers.delete(t)};addMiddleware=e=>{this.middleware.push(e),u.verbose("Created middleware %s",e.id)};setResourceResponseHeaders=(e,t)=>{this.config.responseHeaders||(this.config.responseHeaders={});const s=new Set(t.map(a=>a.name.toLowerCase())),o=[...(this.config.responseHeaders[e]??[]).filter(a=>!s.has(a.name.toLowerCase())),...t];this.config.responseHeaders[e]=o};getRouteByFsPath=e=>{const t=this.routesByFsPath.get(e);return t?this.getRouteBySlug(t):void 0};getRouteBySlug=(e,t={})=>{const{followRedirect:s=!0}=t,r=this.getRedirect(e);if(s&&r)return this.routesBySlug.get(d(r.to));const o=s?this.routeAliases.get(d(e).toLowerCase()):void 0;return this.routesBySlug.get(o??e)};addRouteAlias=(e,t)=>{this.routeAliases.set(d(e).toLowerCase(),d(t))};hasRouteOrRedirectBySlug=e=>{if(this.routesBySlug.has(e)||this.routeAliases.has(d(e).toLowerCase())||X(e,this.getConfig()))return!0;const t=this.getRedirect(e);if(!t)return!1;if(!E(t.to))return!0;const s=d(t.to);return this.routesBySlug.has(s)};getRoutesByTemplateId=e=>this.newRoutes.filter(t=>t.templateId===e);getAllRoutesForLocale=(e=m)=>{const t=Array.from(this.routesBySlug.values()),s=e.toLowerCase();return t.filter(r=>e===m?!ee(r.fsPath):r.slug.startsWith(`/${s}`))};getAllRoutes=()=>Array.from(this.routesBySlug.values());getAllApiRoutes=()=>this.apiRoutes;getAllMiddleware=()=>this.middleware;getTemplate=e=>this.templates.get(e);getRequestHandler=e=>this.apiRoutesRequestHandlers.get(e);createTemplate=(e,t)=>(this.templates.set(e,t),e);addBrowserPlugin=e=>{this.browserPlugins.add(e)};copyAsset=async(e,t)=>{const s=this.lifecycleContext?.fs;if(!s)throw new Error(`Cannot copy asset ${e}: the content file system is not ready`);try{const r=await V(e,s,{fromFileRelativePath:t,contentDir:this.contentDir,outdir:this.outdir});if(!r)throw new Error(`Cannot copy asset ${e}`);return r}catch(r){if(r instanceof j)return null;throw r}};createRequestHandler=(e,t)=>(this.apiRoutesRequestHandlers.set(e,t),e);clearRequestHandlersByPrefix=e=>{for(const t of this.apiRoutesRequestHandlers.keys())t.startsWith(e)&&this.apiRoutesRequestHandlers.delete(t)};registerServerPropsGetter=(e,t)=>(this.serverPropsGetters.set(e,t),e);registerPagePropsGetter=(e,t)=>{this.pagePropsGetters.set(e,t)};async writeRouteStaticData(e,t){const s=await this.resolveRouteStaticData(e,t,!1);s&&Z(e.slug,s,this.outdir)}async resolveRouteStaticData(e,t,s){if(this.serverMode)return Y(e.slug,this.outdir);const r={...this,contentDir:this.contentDir,parseMarkdoc:({input:l,context:h,resource:f})=>this.parseMarkdoc({input:l,context:h,deps:{routeSlugs:[e.slug]},resource:f})},o=await e.getStaticData?.(e,r)||{},a=new Set(this.routesDynamicComponents.get(e.slug)),c=this.routesSharedData.get(e.slug)||{};for(const l of Object.values(c)){const h=this.sharedDataMarkdocComponents.get(l);h&&h.forEach(p=>a.add(p));const f=this.sharedDataDeps.get(l);f&&f.forEach(p=>this.addRouteSharedData(e.slug,p,p))}const i=this.getGlobalConfig("seo"),n=o?.frontmatter||{};return{...o,frontmatter:{...n,seo:{...n?.seo,title:n?.seo?.title||await e.getNavText?.()}},props:{...o.props,dynamicMarkdocComponents:Array.from(a),metadata:{...o?.props?.metadata,...e.metadata},seo:{title:H,...i,...o.props?.seo,siteUrl:i?.siteUrl},compilationErrors:this.compilationErrors},lastModified:s||!e.fsPath?null:await this.lifecycleContext?.fs.getLastModified(e.fsPath)}}addSsrComponents(e,t){if(!e?.length)return;const s=typeof e[0]=="string"?e.join(""):z(e);s&&(t==="head"?this.ssr.headTags.push(s):t==="preBody"?this.ssr.preBodyTags.push(s):this.ssr.postBodyTags.push(s))}clear=()=>{this.routesByFsPath.clear(),this.templates.clear(),this.newRoutes=[],this.routesBySlug.clear(),this.routeAliases.clear(),this.apiRoutes=[],this.middleware=[],this.routesSharedData.clear(),this.sharedDataDeps.clear(),this.sharedDataMarkdocComponents.clear(),this.routesDynamicComponents.clear(),this.routesPartials.clear(),this.skills.clear(),this.config.redirects={},this.config.wildcardRedirectsTree={},this.config.directoryPermissions={},this.ssr={preBodyTags:[],postBodyTags:[],headTags:[]}};#p(){const e=[];for(const[s,r]of Object.entries(A))switch(r){case"map":{const o=Array.from(this[s].entries());e.push([s,o]);break}case"object":e.push([s,this[s]]);break;default:throw new Error("Invalid format")}const t=Object.fromEntries(e);return t[T]=q.PLAN_GATES,t}static#g(e,t){const s=new w(t);for(const[o,a]of Object.entries(A))switch(a){case"map":s[o]=new Map(e[o]);break;case"object":s[o]=e[o];break;default:throw new Error("Invalid format")}const r=e[T];return r&&J("PLAN_GATES",r),s}async writeServerFiles(){$(this.serverOutDir),D(g(this.serverOutDir,b),JSON.stringify(this.#p())),D(g(this.serverOutDir,O),JSON.stringify(await this.getConfigWithEnvPlaceholders()))}static async fromServerFiles(e){const t=g(e.serverOutDir,O),{config:s,env:r}=oe(JSON.parse(await R(t,"utf8")));s[y]=de(s[y]);const o=JSON.parse(await R(g(e.serverOutDir,b),"utf8")),a=w.#g(o,e);a.config=s;const c=Object.fromEntries(Object.entries(r).filter(([i])=>K(i)));return a.configFile={path:t,env:c,config:{...s}},a}async getConfigWithEnvPlaceholders(){const e=JSON.parse(JSON.stringify(this.config));for(const t in this.replacedEnvVars){const{original:s}=this.replacedEnvVars[t],r=t.split(":"),o=r.pop(),{error:a,value:c}=v(e,r);if(a||!_(c)&&!Array.isArray(c)){await C.panicOnBuild(`Failed to replace env var with env name for ${t}`);continue}c[o]=s}return e}async reportUnsetEnvVars(){if(this.unsetEnvVars.size===0)return;const e=Array.from(this.unsetEnvVars).filter(s=>!le.includes(s));if(e.length===0)return;const t=`Failed to resolve config. The following environment variables are not set: ${e.join(", ")}`;await C.panicOnBuildContentError(t)}}function de(M){return N(M,e=>k.Ast.fromJSON(JSON.stringify(e)))}export{w as Store,We as USER_DEFINED_API_FUNCTIONS_COUNTER_KEY};
1
+ import T from"@redocly/markdoc";import{writeFileSync as w}from"node:fs";import{readFile as R}from"node:fs/promises";import{join as g}from"node:path";import{parseAndResolveMarkdoc as M}from"./plugins/markdown/compiler.js";import{getPathnameForLocale as k}from"@redocly/theme/core/utils";import{DEFAULT_LOCALE_PLACEHOLDER as m}from"../constants/common.js";import{DEFAULT_TITLE as F,MARKDOC_PARTIALS_DATA_KEY as y,MARKDOC_PARTIALS_DEPS_KEY as L}from"./constants/common.js";import{isObject as H}from"../utils/guards/is-object.js";import{mapObject as N}from"../utils/object/map-object.js";import{getValueDeep as S}from"../utils/object/get-value-deep.js";import{removeTrailingSlash as G}from"../utils/url/remove-trailing-slash.js";import{normalizeRouteSlug as d}from"../utils/path/normalize-route-slug.js";import{isLocalLink as v}from"../utils/path/is-local-link.js";import{reporter as E}from"./tools/notifiers/reporter.js";import{logger as u}from"./tools/notifiers/logger.js";import{sha1 as _}from"./utils/crypto/sha1.js";import{FileNotFoundError as B}from"./utils/fs.js";import{resolveAssetPath as I}from"./utils/resolve-asset-path.js";import{envConfig as j,setEnv as V}from"./config/env-config.js";import{KvService as q}from"./persistence/kv/services/kv-service.js";import{SandboxContext as J}from"./utils/sandbox-context.js";import{isAllowedEnv as U}from"./utils/envs/get-api-route-allowed-env-variables.js";import{ensureDir as x,writeSharedData as K}from"./utils/index.js";import{renderComponents as $}from"./ssr/render.js";import{readStaticData as W,writeStaticData as z}from"./utils/static-data.js";import{getMarkdocOptions as Y}from"./plugins/markdown/markdoc/markdoc-options.js";import{EntitlementsProvider as Z}from"./entitlements/entitlements-provider.js";import{getPlanDeniedMarkdocTags as Q}from"./entitlements/plan-denied-markdoc-tags.js";import{isRouteReserved as X}from"./plugins/get-reserved-routes.js";import{isL10nPath as ee}from"./fs/utils/is-l10n-path.js";import{resolveGlobMapValue as te}from"./utils/globs.js";import{createDefaultStoreConfig as se,resolveConfigEntries as re,resolveStoreConfig as oe}from"./store-config.js";import{findRedirect as ae}from"./utils/redirects/find-redirect.js";import{followRedirectChain as ie}from"./utils/redirects/follow-redirect-chain.js";import{addWildcardRedirectToTree as ne}from"./utils/redirects/add-wildcard-redirect-to-tree.js";import{telemetryTraceStep as le}from"../cli/telemetry/helpers/trace-step.js";const P={routesBySlug:"map",staticFilePaths:"object",apiRoutes:"object",middleware:"object",routesByFsPath:"map",routesSharedData:"map",globalData:"object",ssr:"object",searchFacets:"map",routesPartials:"map",mcpToolHandlers:"map",skills:"map",devLogin:"object"},C="store.json",A="store-config.json",b="PLAN_GATES",ce=["OAUTH_CLIENT_ID","OAUTH_CLIENT_SECRET","ORGANIZATION_SLUG","ORGANIZATION_ID","ORG_ID"],We="userDefinedApiFunctions";class D{routesBySlug=new Map;routeAliases=new Map;staticFilePaths={};replacedEnvVars={};unsetEnvVars=new Set;lifecycleContext;newRoutes=[];#t={};routesByFsPath=new Map;apiRoutes=[];middleware=[];routesSharedData=new Map;sharedDataDeps=new Map;sharedDataMarkdocComponents=new Map;routesDynamicComponents=new Map;routesPartials=new Map;ssr={preBodyTags:[],postBodyTags:[],headTags:[]};searchFacets=new Map;searchEngine;templates=new Map;browserPlugins=new Set;apiRoutesRequestHandlers=new Map;mcpToolHandlers=new Map;skills=new Map;serverPropsGetters=new Map;pagePropsGetters=new Map;listeners=new Map;globalData={};devLogin=!1;#a=void 0;#i={};config=se();configFile;#n;serverMode;serverOutDir;outdir;buildRevision=0;hasSitemap=!1;compilationErrors=[];#l;userCodeReady;#s=Promise.resolve();#c;#d=Promise.resolve();#h;#u=Promise.resolve();#f;#e=!1;#r=0;#p=0;#o=new Map;constructor({outdir:e,contentDir:t,serverMode:s=!1,serverOutDir:r}){this.#n=t,this.outdir=e,this.serverMode=s,this.serverOutDir=r,J.register({serverOutDir:r,readRoots:[e,process.cwd()]}),this.userCodeReady=new Promise(o=>{this.#l=o})}on(e,t){const s=this.listeners.get(e);s?s.add(t):this.listeners.set(e,new Set([t]))}queueEvent=(e,t,...s)=>{this.#o.set(e+String(t),[e,t,...s])};runListeners=(e,t,...s)=>{for(const r of this.listeners.get(e)||new Set)t?r(t,...s):r(...s)};startPluginsRun(){this.clear(),this.#s=new Promise(e=>{this.#c=e})}waitForPluginsLifecycle(){return Promise.all([this.#s,this.#d,this.#u])}waitForPluginsRun(){return this.#s}finishPluginsRun(){this.#c?.();for(const e of this.#o.values())this.runListeners(...e);this.#o.clear()}startEsbuildRun(){this.#d=new Promise(e=>{this.#h=e})}finishEsbuildRun(){this.#h?.()}markRequestHandlersEntryOutdated(){this.#r++,!this.#e&&(this.#e=!0,this.#u=new Promise(e=>{this.#f=e}))}noteRequestHandlersEntryBuildStart(){this.#p=this.#r}markRequestHandlersEntryUpdated(){this.#e&&(this.#r>this.#p||(this.#e=!1,this.#f?.()))}get contentDir(){if(this.serverMode)throw new Error("contentDir should not be used in server mode");return this.#n}markUserCodeReady(){this.#l?.(!0)}async reloadMarkdocOptions(){await le("com.redocly.build.reloadMarkdocOptions",async()=>{const{userTagNames:e,...t}=await Y(this.serverOutDir),s=Q(e),r=Object.fromEntries(Object.entries(t.tags).filter(([o])=>!(o in s)));this.#a={...t,tags:r},this.#i=s})}get markdocOptions(){return{...this.#a,partials:this.getGlobalConfig(y),themeConfig:this.config.markdown,planDeniedTags:this.#i}}setGlobalData=e=>{const t=this.globalData,s={...this.globalData,...e};this.globalData=s,JSON.stringify(s)!==JSON.stringify(t)&&this.queueEvent("global-data-updated",void 0,s)};getGlobalData=()=>this.globalData;getKv=async()=>q.getInstance({baseDbDir:this.serverOutDir});parseMarkdoc=async({input:e,context:t,deps:s,resource:r})=>{const{data:{info:o,ast:a},compoundHash:l}=await M(e,this.markdocOptions,{actions:this,context:t},r);for(const i of o.sharedDataDeps||[]){for(const n of s?.routeSlugs||[])this.addRouteSharedData(n,i,i);for(const n of s?.sharedDataIds||[]){const c=this.sharedDataDeps.get(n)||new Set;c.add(i),this.sharedDataDeps.set(n,c)}}for(const i of o.dynamicMarkdocComponents||[]){for(const n of s?.routeSlugs||[]){const c=this.routesDynamicComponents.get(n)||new Set;c.add(i),this.routesDynamicComponents.set(n,c)}for(const n of s?.sharedDataIds||[]){const c=this.sharedDataMarkdocComponents.get(n)||new Set;c.add(i),this.sharedDataMarkdocComponents.set(n,c)}}if(s?.routeSlugs&&o.partials?.length)for(const i of s.routeSlugs){const n=this.routesPartials.get(i)||[];for(const c of o.partials)n.includes(c)||n.push(c);this.routesPartials.set(i,n)}return{info:o,ast:a,compoundHash:l}};async loadApiDocuments(e){return(await e.cache.load(".","api-docs")).data}setSearchEngine(e){this.searchEngine=e}setSearchFacets=e=>{this.searchFacets=e};setStaticFilePaths=e=>{this.staticFilePaths=e};setGlobalConfig=e=>{const t=Object.keys(e);for(const a of t)for(const l in this.replacedEnvVars)if(l===a||l.startsWith(`${a}:`)){const i=l.split(":"),{error:n,value:c}=S(e,i);(n||c!==this.replacedEnvVars[l].replaced)&&delete this.replacedEnvVars[l]}const{config:s,unsetEnvVars:r,replacedValues:o}=re(e);for(const a of r)this.unsetEnvVars.add(a);Object.assign(this.replacedEnvVars,o),Object.assign(this.config,s)};getConfig=()=>this.config;getGlobalConfig=e=>this.config[e];getSearchFacets=()=>this.searchFacets;addRedirect=(e,t,s={})=>{if(!Z.instance().canAccessFeature("redirects")&&e!=="/")return;this.config.redirects||(this.config.redirects={});const a=d(e).toLowerCase();this.config.redirects[a]=t;const{trackOriginalSource:l=!0}=s,i=this.getGlobalConfig("originalRedirectSources");l&&Array.isArray(i)&&!i.includes(a)&&i.push(a),a.endsWith("*")&&ne(this.config.wildcardRedirectsTree,a)};getRedirect=e=>{const t=d(e).toLowerCase(),s=ae(t,this.config.redirects,this.config.wildcardRedirectsTree,this.staticFilePaths);if(!s)return null;if(v(s.to)){const r=d(s.to).toLowerCase();if(!r.endsWith("*")&&ie(r,[t],this.config.redirects,this.config.wildcardRedirectsTree).type==="cycle")return null}return{to:s.to,type:s.type}};createSharedData=async(e,t,s)=>{if(s&&this.#t[e]===s)return e;const r=JSON.stringify(t),o=s??_(r);return this.#t[e]===o||(this.#t[e]=o,await K(e,r,this.outdir),this.queueEvent("shared-data-updated",e)),e};addRouteSharedData=(e,t,s)=>{const r=G(e),o=this.routesSharedData.get(r)||{};o[t]=s,this.routesSharedData.set(r,o),u.verbose(`Adding shared data to ${e}, ${t}, ${s}`)};getRouteSharedDataByFsPath=e=>{const t=this.routesByFsPath.get(e);return t?this.routesSharedData.get(t)||{}:{}};getPartialsForRoute=e=>{const t=this.getGlobalConfig(y)||{},s=this.routesPartials.get(e);if(!s||s.length===0)return{};const r=this.getGlobalConfig(L)||{},o=new Set(s),a=Array.from(s);for(let i=0;i<a.length;i++){const n=a[i],c=r[n]?.partials??[];for(const h of c)o.has(h)||(o.add(h),a.push(h))}const l={};for(const i of o)t[i]&&(l[i]=t[i]);return l};addRoute=e=>{const s={...te(e.fsPath,this.config.metadataGlobs),...e.metadata||{}};this.newRoutes.push({...e,metadata:s}),u.verbose("Created route %s",e.slug)};addRouteSharedDataToAllLocales=(e,t,s)=>{const r=[m,...this.lifecycleContext?.fs.localeFolders||[]].map(o=>({code:o,name:o}));for(const o of r){const a=k(e,m,o.code,r);this.addRouteSharedData(a,t,s)}};addApiRoute=e=>{this.apiRoutes.push(e),u.verbose("Created API route %s",e.slug)};addMcpTools=(e,t)=>{for(const s of t){const r=this.mcpToolHandlers.get(s.name);r&&r.importPath!==e&&u.warn('MCP tool "%s" from %s overwrites the tool registered from %s',s.name,e,r.importPath);const o=s.hasAvailabilityGate??(r?.importPath===e?r.hasAvailabilityGate:void 0);this.mcpToolHandlers.set(s.name,{...s,importPath:e,hasAvailabilityGate:o}),u.verbose("Created MCP tool %s",s.name)}};getMcpTools=()=>Array.from(this.mcpToolHandlers.values());markGatedMcpTools=e=>{for(const t of e){const s=this.mcpToolHandlers.get(t);s&&this.mcpToolHandlers.set(t,{...s,hasAvailabilityGate:!0})}};addSkills=e=>{for(const t of e)this.skills.set(t.slug,t),u.verbose("Discovered skill %s",t.slug)};getSkills=()=>Array.from(this.skills.values());removeMcpTools=e=>{for(const t of e)this.mcpToolHandlers.delete(t)};addMiddleware=e=>{this.middleware.push(e),u.verbose("Created middleware %s",e.id)};setResourceResponseHeaders=(e,t)=>{this.config.responseHeaders||(this.config.responseHeaders={});const s=new Set(t.map(a=>a.name.toLowerCase())),o=[...(this.config.responseHeaders[e]??[]).filter(a=>!s.has(a.name.toLowerCase())),...t];this.config.responseHeaders[e]=o};getRouteByFsPath=e=>{const t=this.routesByFsPath.get(e);return t?this.getRouteBySlug(t):void 0};getRouteBySlug=(e,t={})=>{const{followRedirect:s=!0}=t,r=this.getRedirect(e);if(s&&r)return this.routesBySlug.get(d(r.to));const o=s?this.routeAliases.get(d(e).toLowerCase()):void 0;return this.routesBySlug.get(o??e)};addRouteAlias=(e,t)=>{this.routeAliases.set(d(e).toLowerCase(),d(t))};hasRouteOrRedirectBySlug=e=>{if(this.routesBySlug.has(e)||this.routeAliases.has(d(e).toLowerCase())||X(e,this.getConfig()))return!0;const t=this.getRedirect(e);if(!t)return!1;if(!v(t.to))return!0;const s=d(t.to);return this.routesBySlug.has(s)};getRoutesByTemplateId=e=>this.newRoutes.filter(t=>t.templateId===e);getAllRoutesForLocale=(e=m)=>{const t=Array.from(this.routesBySlug.values()),s=e.toLowerCase();return t.filter(r=>e===m?!ee(r.fsPath):r.slug.startsWith(`/${s}`))};getAllRoutes=()=>Array.from(this.routesBySlug.values());getAllApiRoutes=()=>this.apiRoutes;getAllMiddleware=()=>this.middleware;getTemplate=e=>this.templates.get(e);getRequestHandler=e=>this.apiRoutesRequestHandlers.get(e);createTemplate=(e,t)=>(this.templates.set(e,t),e);addBrowserPlugin=e=>{this.browserPlugins.add(e)};copyAsset=async(e,t)=>{const s=this.lifecycleContext?.fs;if(!s)throw new Error(`Cannot copy asset ${e}: the content file system is not ready`);try{const r=await I(e,s,{fromFileRelativePath:t,contentDir:this.contentDir,outdir:this.outdir});if(!r)throw new Error(`Cannot copy asset ${e}`);return r}catch(r){if(r instanceof B)return null;throw r}};createRequestHandler=(e,t)=>(this.apiRoutesRequestHandlers.set(e,t),e);clearRequestHandlersByPrefix=e=>{for(const t of this.apiRoutesRequestHandlers.keys())t.startsWith(e)&&this.apiRoutesRequestHandlers.delete(t)};registerServerPropsGetter=(e,t)=>(this.serverPropsGetters.set(e,t),e);registerPagePropsGetter=(e,t)=>{this.pagePropsGetters.set(e,t)};async writeRouteStaticData(e,t){const s=await this.resolveRouteStaticData(e,t,!1);s&&z(e.slug,s,this.outdir)}async resolveRouteStaticData(e,t,s){if(this.serverMode)return W(e.slug,this.outdir);const r={...this,contentDir:this.contentDir,parseMarkdoc:({input:c,context:h,resource:f})=>this.parseMarkdoc({input:c,context:h,deps:{routeSlugs:[e.slug]},resource:f})},o=await e.getStaticData?.(e,r)||{},a=new Set(this.routesDynamicComponents.get(e.slug)),l=this.routesSharedData.get(e.slug)||{};for(const c of Object.values(l)){const h=this.sharedDataMarkdocComponents.get(c);h&&h.forEach(p=>a.add(p));const f=this.sharedDataDeps.get(c);f&&f.forEach(p=>this.addRouteSharedData(e.slug,p,p))}const i=this.getGlobalConfig("seo"),n=o?.frontmatter||{};return{...o,frontmatter:{...n,seo:{...n?.seo,title:n?.seo?.title||await e.getNavText?.()}},props:{...o.props,dynamicMarkdocComponents:Array.from(a),metadata:{...o?.props?.metadata,...e.metadata},seo:{title:F,...i,...o.props?.seo,siteUrl:i?.siteUrl},compilationErrors:this.compilationErrors},lastModified:s||!e.fsPath?null:await this.lifecycleContext?.fs.getLastModified(e.fsPath)}}addSsrComponents(e,t){if(!e?.length)return;const s=typeof e[0]=="string"?e.join(""):$(e);s&&(t==="head"?this.ssr.headTags.push(s):t==="preBody"?this.ssr.preBodyTags.push(s):this.ssr.postBodyTags.push(s))}clear=()=>{this.routesByFsPath.clear(),this.templates.clear(),this.newRoutes=[],this.routesBySlug.clear(),this.routeAliases.clear(),this.apiRoutes=[],this.middleware=[],this.routesSharedData.clear(),this.sharedDataDeps.clear(),this.sharedDataMarkdocComponents.clear(),this.routesDynamicComponents.clear(),this.routesPartials.clear(),this.skills.clear(),this.config.redirects={},this.config.wildcardRedirectsTree={},this.config.directoryPermissions={},this.ssr={preBodyTags:[],postBodyTags:[],headTags:[]}};#g(){const e=[];for(const[s,r]of Object.entries(P))switch(r){case"map":{const o=Array.from(this[s].entries());e.push([s,o]);break}case"object":e.push([s,this[s]]);break;default:throw new Error("Invalid format")}const t=Object.fromEntries(e);return t[b]=j.PLAN_GATES,t}static#m(e,t){const s=new D(t);for(const[o,a]of Object.entries(P))switch(a){case"map":s[o]=new Map(e[o]);break;case"object":s[o]=e[o];break;default:throw new Error("Invalid format")}const r=e[b];return r&&V("PLAN_GATES",r),s}async writeServerFiles(){x(this.serverOutDir),w(g(this.serverOutDir,C),JSON.stringify(this.#g())),w(g(this.serverOutDir,A),JSON.stringify(await this.getConfigWithEnvPlaceholders()))}static async fromServerFiles(e){const t=g(e.serverOutDir,A),{config:s,env:r}=oe(JSON.parse(await R(t,"utf8")));s[y]=de(s[y]);const o=JSON.parse(await R(g(e.serverOutDir,C),"utf8")),a=D.#m(o,e);a.config=s;const l=Object.fromEntries(Object.entries(r).filter(([i])=>U(i)));return a.configFile={path:t,env:l,config:{...s}},a}async getConfigWithEnvPlaceholders(){const e=JSON.parse(JSON.stringify(this.config));for(const t in this.replacedEnvVars){const{original:s}=this.replacedEnvVars[t],r=t.split(":"),o=r.pop(),{error:a,value:l}=S(e,r);if(a||!H(l)&&!Array.isArray(l)){await E.panicOnBuild(`Failed to replace env var with env name for ${t}`);continue}l[o]=s}return e}async reportUnsetEnvVars(){if(this.unsetEnvVars.size===0)return;const e=Array.from(this.unsetEnvVars).filter(s=>!ce.includes(s));if(e.length===0)return;const t=`Failed to resolve config. The following environment variables are not set: ${e.join(", ")}`;await E.panicOnBuildContentError(t)}}function de(O){return N(O,e=>T.Ast.fromJSON(JSON.stringify(e)))}export{D as Store,We as USER_DEFINED_API_FUNCTIONS_COUNTER_KEY};
@@ -31,6 +31,8 @@ export type ResolveItemsOptions = {
31
31
  };
32
32
  export type MarkdocOptions = Partial<Omit<MarkdocConfigProps, 'relativePath'>> & {
33
33
  themeConfig?: RedoclyConfig['markdown'];
34
+ /** The tags the project's plan lacks, each with the message a page shows in place of the tag. */
35
+ planDeniedTags?: Record<string, string>;
34
36
  };
35
37
  export type GetStaticDataContext = {
36
38
  getRouteByFsPath: (relativePath: string) => PageRouteDetails<PageStaticData, PageProps> | undefined;
@@ -46,6 +46,10 @@ export type PlanGates = {
46
46
  [FEATURE.sdkGeneration]: boolean;
47
47
  /** Absent at runtime from legacy tokens, which keep every npm package. */
48
48
  [FEATURE.customPackages]: boolean;
49
+ /** Absent at runtime from tokens signed before the claim, which keep the project's Markdoc tags. */
50
+ [FEATURE.customMarkdocTags]: boolean;
51
+ /** Absent at runtime from tokens signed before the claim, which keep the tools in `@mcp` folders. */
52
+ [FEATURE.customMcpTools]: boolean;
49
53
  /** The new-pricing tier of the order; `null` or absent for legacy orders. */
50
54
  pricingTier?: PricingTier | null;
51
55
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@redocly/reef",
3
- "version": "0.141.0-next.1",
3
+ "version": "0.141.0-next.2",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "bin": {
@@ -33,12 +33,12 @@
33
33
  "@opentelemetry/sdk-trace-web": "2.8.0",
34
34
  "@opentelemetry/semantic-conventions": "1.40.0",
35
35
  "@redocly/ajv": "8.18.0",
36
- "@redocly/api-docs": "0.6.0-next.1",
36
+ "@redocly/api-docs": "0.6.0-next.2",
37
37
  "@redocly/config": "0.72.1",
38
38
  "@redocly/markdoc": "0.7.0-beta.2",
39
- "@redocly/openapi-core": "2.73.0",
39
+ "@redocly/openapi-core": "2.75.0",
40
40
  "@redocly/portal-legacy-ui": "0.19.0",
41
- "@redocly/portal-plugin-mock-server": "0.25.0",
41
+ "@redocly/portal-plugin-mock-server": "0.26.0-next.0",
42
42
  "@redocly/realm-asyncapi-sdk": "0.17.0",
43
43
  "@redocly/theme": "0.73.0-next.0",
44
44
  "@shikijs/transformers": "3.21.0",