@redocly/reef 0.132.0-next.5 → 0.132.0-next.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/dist/cli/telemetry/index.js +1 -1
  3. package/dist/client/App.js +1 -1
  4. package/dist/client/app/CircularProgress.js +8 -8
  5. package/dist/client/app/hooks/utils/match-banner-target.d.ts +23 -1
  6. package/dist/client/app/hooks/utils/match-banner-target.js +1 -1
  7. package/dist/client/mcp-tool-handlers-entry.d.ts +3 -0
  8. package/dist/client/mcp-tool-handlers-entry.js +1 -0
  9. package/dist/client/templates/asyncapi-docs/helpers.d.ts +1 -1
  10. package/dist/client/types/ai-search.d.ts +5 -3
  11. package/dist/constants/l10n/langs/ar.js +1 -1
  12. package/dist/constants/l10n/langs/de.js +1 -1
  13. package/dist/constants/l10n/langs/en.js +1 -1
  14. package/dist/constants/l10n/langs/es.js +1 -1
  15. package/dist/constants/l10n/langs/fr.js +1 -1
  16. package/dist/constants/l10n/langs/hi.js +1 -1
  17. package/dist/constants/l10n/langs/it.js +1 -1
  18. package/dist/constants/l10n/langs/ja.js +1 -1
  19. package/dist/constants/l10n/langs/ko.js +1 -1
  20. package/dist/constants/l10n/langs/pl.js +1 -1
  21. package/dist/constants/l10n/langs/pt-BR.js +1 -1
  22. package/dist/constants/l10n/langs/pt.js +1 -1
  23. package/dist/constants/l10n/langs/ru.js +1 -1
  24. package/dist/constants/l10n/langs/uk.js +1 -1
  25. package/dist/constants/l10n/langs/zh.js +1 -1
  26. package/dist/markdoc/nodes/fence/index.js +1 -1
  27. package/dist/markdoc/nodes/index.d.ts +1 -1
  28. package/dist/markdoc/nodes/index.js +1 -1
  29. package/dist/server/api-routes/run-api-routes-worker.js +1 -1
  30. package/dist/server/config/env-schema.d.ts +6 -3
  31. package/dist/server/config/env-schemas/api-urls.d.ts +3 -3
  32. package/dist/server/config/env-schemas/api-urls.js +1 -1
  33. package/dist/server/config/env-schemas/auth.d.ts +3 -0
  34. package/dist/server/config/env-schemas/auth.js +1 -1
  35. package/dist/server/esbuild/esbuild.js +3 -3
  36. package/dist/server/esbuild/plugins/codegen/index.d.ts +1 -0
  37. package/dist/server/esbuild/plugins/codegen/index.js +7 -3
  38. package/dist/server/esbuild/plugins/mcp-tool-handlers-resolver.d.ts +7 -0
  39. package/dist/server/esbuild/plugins/mcp-tool-handlers-resolver.js +1 -0
  40. package/dist/server/plugins/catalog-entities/plugin.js +1 -1
  41. package/dist/server/plugins/config-parser/index.js +1 -1
  42. package/dist/server/plugins/config-parser/loaders/content-slugs-loader.js +1 -1
  43. package/dist/server/plugins/default-theme/resolve-products-config.js +1 -1
  44. package/dist/server/plugins/dev-onboarding/api/adapter-factory.d.ts +10 -3
  45. package/dist/server/plugins/dev-onboarding/api/adapter-factory.js +1 -1
  46. package/dist/server/plugins/dev-onboarding/api/adapters/apigee/adapter.d.ts +5 -4
  47. package/dist/server/plugins/dev-onboarding/api/adapters/apigee/adapter.js +4 -4
  48. package/dist/server/plugins/dev-onboarding/api/adapters/gravitee/client.d.ts +3 -3
  49. package/dist/server/plugins/dev-onboarding/api/adapters/gravitee/client.js +1 -1
  50. package/dist/server/plugins/dev-onboarding/api/middlewares/integrations.d.ts +3 -2
  51. package/dist/server/plugins/dev-onboarding/api/middlewares/integrations.js +1 -1
  52. package/dist/server/plugins/dev-onboarding/api/routes/index.js +1 -1
  53. package/dist/server/plugins/dev-onboarding/api/types.d.ts +8 -0
  54. package/dist/server/plugins/dev-onboarding/template/components/ApiLogsActions.js +5 -5
  55. package/dist/server/plugins/dev-onboarding/template/components/DialogStyledComponents.js +1 -1
  56. package/dist/server/plugins/dev-onboarding/template/components/MultiSelect.js +1 -1
  57. package/dist/server/plugins/dev-onboarding/template/components/TextField.js +3 -3
  58. package/dist/server/plugins/enforce-login/index.js +1 -1
  59. package/dist/server/plugins/lifecycle.js +2 -2
  60. package/dist/server/plugins/markdown/attribute-resolvers/index.js +1 -1
  61. package/dist/server/plugins/markdown/attribute-resolvers/resolve-diagram-from-file.d.ts +4 -0
  62. package/dist/server/plugins/markdown/attribute-resolvers/resolve-diagram-from-file.js +1 -0
  63. package/dist/server/plugins/markdown/attribute-resolvers/resolve-native-md-link.js +1 -1
  64. package/dist/server/plugins/markdown/markdoc/markdoc-options.d.ts +1 -1
  65. package/dist/server/plugins/markdown/markdoc/plugins/render-diagrams.d.ts +16 -0
  66. package/dist/server/plugins/markdown/markdoc/plugins/render-diagrams.js +1 -0
  67. package/dist/server/plugins/markdown/runtime-transform.js +1 -1
  68. package/dist/server/plugins/markdown/search/to-markdown.js +24 -16
  69. package/dist/server/plugins/markdown/search/walk-sections.js +1 -1
  70. package/dist/server/plugins/mcp/docs-mcp/tool-schemas.d.ts +7 -0
  71. package/dist/server/plugins/mcp/docs-mcp/tool-schemas.js +1 -0
  72. package/dist/server/plugins/mcp/docs-mcp/tools/get-endpoint-info.d.ts +5 -9
  73. package/dist/server/plugins/mcp/docs-mcp/tools/get-endpoint-info.js +1 -1
  74. package/dist/server/plugins/mcp/docs-mcp/tools/get-endpoints.d.ts +5 -9
  75. package/dist/server/plugins/mcp/docs-mcp/tools/get-endpoints.js +1 -1
  76. package/dist/server/plugins/mcp/docs-mcp/tools/get-full-api-description.d.ts +5 -9
  77. package/dist/server/plugins/mcp/docs-mcp/tools/get-full-api-description.js +1 -1
  78. package/dist/server/plugins/mcp/docs-mcp/tools/get-security-schemes.d.ts +5 -9
  79. package/dist/server/plugins/mcp/docs-mcp/tools/get-security-schemes.js +1 -1
  80. package/dist/server/plugins/mcp/docs-mcp/tools/helpers/load-api-description.d.ts +4 -0
  81. package/dist/server/plugins/mcp/docs-mcp/tools/helpers/load-api-description.js +1 -0
  82. package/dist/server/plugins/mcp/docs-mcp/tools/index.d.ts +10 -7
  83. package/dist/server/plugins/mcp/docs-mcp/tools/index.js +1 -1
  84. package/dist/server/plugins/mcp/docs-mcp/tools/list-apis.d.ts +5 -9
  85. package/dist/server/plugins/mcp/docs-mcp/tools/list-apis.js +1 -1
  86. package/dist/server/plugins/mcp/docs-mcp/tools/search.d.ts +5 -10
  87. package/dist/server/plugins/mcp/docs-mcp/tools/search.js +3 -3
  88. package/dist/server/plugins/mcp/docs-mcp/tools/utils.d.ts +6 -3
  89. package/dist/server/plugins/mcp/docs-mcp/tools/utils.js +6 -6
  90. package/dist/server/plugins/mcp/docs-mcp/tools/whoami.d.ts +5 -9
  91. package/dist/server/plugins/mcp/docs-mcp/tools/whoami.js +1 -1
  92. package/dist/server/plugins/mcp/handlers/docs-mcp-handler.js +1 -1
  93. package/dist/server/plugins/mcp/handlers/handle-mcp-request.js +1 -1
  94. package/dist/server/plugins/mcp/index.js +1 -1
  95. package/dist/server/plugins/mcp/servers/docs-server.d.ts +13 -22
  96. package/dist/server/plugins/mcp/servers/docs-server.js +1 -1
  97. package/dist/server/plugins/mcp/types.d.ts +24 -56
  98. package/dist/server/plugins/mcp/workers/execute-mcp-tool.d.ts +2 -2
  99. package/dist/server/plugins/mcp/workers/execute-mcp-tool.js +1 -1
  100. package/dist/server/plugins/openapi-docs/index.js +1 -1
  101. package/dist/server/plugins/openapi-docs/search-indexer.js +1 -1
  102. package/dist/server/store.d.ts +5 -2
  103. package/dist/server/store.js +1 -1
  104. package/dist/server/telemetry/index.js +1 -1
  105. package/dist/server/types/plugins/common.d.ts +15 -2
  106. package/dist/server/types/redirects.d.ts +6 -0
  107. package/dist/server/utils/rbac.js +1 -1
  108. package/dist/server/utils/redirects/find-redirect.d.ts +8 -31
  109. package/dist/server/utils/redirects/find-redirect.js +1 -1
  110. package/dist/server/utils/redirects/follow-redirect-chain.d.ts +9 -0
  111. package/dist/server/utils/redirects/follow-redirect-chain.js +1 -0
  112. package/dist/server/utils/redirects/validate-redirects.d.ts +8 -0
  113. package/dist/server/utils/redirects/validate-redirects.js +1 -0
  114. package/dist/server/web-server/routes/otel/otel.js +1 -1
  115. package/dist/server/workers/types.d.ts +2 -2
  116. package/dist/server/workers/worker-pool.js +1 -1
  117. package/dist/types/global-data.d.ts +7 -2
  118. package/package.json +10 -10
  119. package/dist/server/plugins/markdown/markdoc/plugins/render-mermaid.d.ts +0 -4
  120. package/dist/server/plugins/markdown/markdoc/plugins/render-mermaid.js +0 -1
  121. package/dist/server/plugins/mcp/docs-mcp/tools/docs-mcp-tool.d.ts +0 -55
  122. package/dist/server/plugins/mcp/docs-mcp/tools/docs-mcp-tool.js +0 -1
  123. package/dist/server/plugins/mcp/handlers/mcp-request-handler.d.ts +0 -11
  124. package/dist/server/plugins/mcp/handlers/mcp-request-handler.js +0 -1
  125. package/dist/server/plugins/mcp/servers/base-server.d.ts +0 -17
  126. package/dist/server/plugins/mcp/servers/base-server.js +0 -1
@@ -1,5 +1,5 @@
1
- import{logger as n}from"../../../../../tools/notifiers/logger.js";import{ApigeeDevOnboardingIntegrationAuthType as w,APIGEE_VERSION as m}from"./types.js";import{AlgorithmTypes as S}from"../../../../../web-server/jwt/types.js";import*as T from"../../../../../web-server/jwt/jwt.js";import{getFirstNameFromClaims as b,getLastNameFromClaims as U}from"../../../utils.js";import{HttpError as $}from"../../../../../utils/errors.js";const f="developer.service.DeveloperDoesNotExist",E=3600*24*365*1;function k(s){return s.replace(/\+/g,"%2B")}function y(s){return{id:s.consumerKey,clientId:s.consumerKey,clientSecret:s.consumerSecret,scopes:s.scopes,issuedAt:s.issuedAt,expiresAt:s.expiresAt,attributes:x(s.attributes),status:s.status,apiProductsStatus:s.apiProducts?.map(e=>({id:e.apiproduct,status:e.status,name:e.apiproduct}))||[],canBeRolled:!1,canBeRevoked:!0,valueToUseInHeader:"clientId"}}function A(s){const e=Object.fromEntries((s.attributes||[]).map(t=>[t.name,t.value]));return{id:s.name,name:e.DisplayName||s.name,description:e.Notes||"",attributes:e,createdAt:s.createdAt,lastModifiedAt:s.lastModifiedAt,scopes:s.scopes,credentials:s.credentials?.map(y)||[],supportsLogs:!1,canCreateKey:!0}}function O(s){const e=Object.fromEntries((s.attributes||[]).map(t=>[t.name,t.value]));return{id:s.name,name:e.DisplayName||s.name,description:s.description,attributes:e,createdAt:s.createdAt,lastModifiedAt:s.lastModifiedAt,approvalType:s.approvalType,scopes:s.scopes}}function v(s){return Object.entries(s||{}).map(([e,t])=>({name:e,value:t}))}function x(s){return Object.fromEntries((s||[]).map(e=>[e.name,e.value]))}let h=null;async function N(s){h?(await h).expiresAt<Date.now()/1e3&&(n.info("Token expired, requesting new apigee access token"),h=P(s)):(n.info("Requesting apigee access token"),h=P(s));try{return(await h).token}catch(e){throw h=null,e}}async function P({auth:s}){switch(s.type){case w.OAUTH2:return I(s);case w.SERVICE_ACCOUNT:return _(s)}}async function I(s){const e={grant_type:"client_credentials",client_id:s.clientId,client_secret:s.clientSecret};let t=await fetch(s.tokenEndpoint,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams(e).toString()});if(!t.ok)throw new Error(`Failed to get access token: ${t.statusText}
2
- ${await t.text()}`);const i=await t.json(),{access_token:a,expires_in:r}=i;return n.info("Apigee access token received"),{token:a,expiresAt:Math.floor(Date.now()/1e3)+r}}async function _(s){n.verbose(`Using service account to sign JWT token: Email: "%s" Private key:
1
+ import{logger as n}from"../../../../../tools/notifiers/logger.js";import{canAccessResource as S}from"../../../../../utils/rbac.js";import{ApigeeDevOnboardingIntegrationAuthType as w,APIGEE_VERSION as m}from"./types.js";import{AlgorithmTypes as b}from"../../../../../web-server/jwt/types.js";import*as T from"../../../../../web-server/jwt/jwt.js";import{getFirstNameFromClaims as U,getLastNameFromClaims as k}from"../../../utils.js";import{HttpError as $}from"../../../../../utils/errors.js";const f="developer.service.DeveloperDoesNotExist",C=3600*24*365*1;function O(s){return s.replace(/\+/g,"%2B")}function y(s){return{id:s.consumerKey,clientId:s.consumerKey,clientSecret:s.consumerSecret,scopes:s.scopes,issuedAt:s.issuedAt,expiresAt:s.expiresAt,attributes:N(s.attributes),status:s.status,apiProductsStatus:s.apiProducts?.map(e=>({id:e.apiproduct,status:e.status,name:e.apiproduct}))||[],canBeRolled:!1,canBeRevoked:!0,valueToUseInHeader:"clientId"}}function A(s){const e=Object.fromEntries((s.attributes||[]).map(t=>[t.name,t.value]));return{id:s.name,name:e.DisplayName||s.name,description:e.Notes||"",attributes:e,createdAt:s.createdAt,lastModifiedAt:s.lastModifiedAt,scopes:s.scopes,credentials:s.credentials?.map(y)||[],supportsLogs:!1,canCreateKey:!0}}function x(s){const e=Object.fromEntries((s.attributes||[]).map(t=>[t.name,t.value]));return{id:s.name,name:e.DisplayName||s.name,description:s.description,attributes:e,createdAt:s.createdAt,lastModifiedAt:s.lastModifiedAt,approvalType:s.approvalType,scopes:s.scopes}}function v(s){return Object.entries(s||{}).map(([e,t])=>({name:e,value:t}))}function N(s){return Object.fromEntries((s||[]).map(e=>[e.name,e.value]))}let h=null;async function I(s){h?(await h).expiresAt<Date.now()/1e3&&(n.info("Token expired, requesting new apigee access token"),h=P(s)):(n.info("Requesting apigee access token"),h=P(s));try{return(await h).token}catch(e){throw h=null,e}}async function P({auth:s}){switch(s.type){case w.OAUTH2:return j(s);case w.SERVICE_ACCOUNT:return _(s)}}async function j(s){const e={grant_type:"client_credentials",client_id:s.clientId,client_secret:s.clientSecret};let t=await fetch(s.tokenEndpoint,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams(e).toString()});if(!t.ok)throw new Error(`Failed to get access token: ${t.statusText}
2
+ ${await t.text()}`);const a=await t.json(),{access_token:i,expires_in:r}=a;return n.info("Apigee access token received"),{token:i,expiresAt:Math.floor(Date.now()/1e3)+r}}async function _(s){n.verbose(`Using service account to sign JWT token: Email: "%s" Private key:
3
3
  %s
4
- `,s.serviceAccountEmail,s.serviceAccountPrivateKey.slice(0,30)+"***"+s.serviceAccountPrivateKey.slice(-30));const t={grant_type:"urn:ietf:params:oauth:grant-type:jwt-bearer",assertion:await T.sign({sub:s.serviceAccountEmail,iss:s.serviceAccountEmail,aud:"https://www.googleapis.com/oauth2/v4/token",iat:Math.floor(Date.now()/1e3),exp:Math.floor(Date.now()/1e3)+3600,scope:"https://www.googleapis.com/auth/cloud-platform"},s.serviceAccountPrivateKey,S.RS256)};n.verbose("Exchanging JWT for access token",s.serviceAccountEmail,s.serviceAccountPrivateKey.slice(0,30)+"***"+s.serviceAccountPrivateKey.slice(-30));let i=await fetch("https://oauth2.googleapis.com/token",{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams(t).toString()});if(!i.ok)throw new Error(`Failed to get access token: ${i.statusText}
5
- ${await i.text()}`);const a=await i.json(),{access_token:r,expires_in:o}=a;return n.info("Apigee access token received"),{token:r,expiresAt:Math.floor(Date.now()/1e3)+o}}class L{apiUrl;developerUrl;accessToken=null;organizationName;email;organizationUrl;version;userClaims;config;ignoreApiProducts;catalogApiProducts;allowApiProductsOutsideCatalog;adapterId;stage;constructor(e,t,i){const a=e;this.apiUrl=a.apiUrl||"https://apigee.googleapis.com/v1",this.organizationName=a.organizationName,this.email=t.email,this.organizationUrl=`${this.apiUrl}/organizations/${this.organizationName}`,this.developerUrl=`${this.organizationUrl}/developers/${k(this.email)}`,this.version=e.type==="APIGEE_X"?m.x:m.edge,this.userClaims=t,this.adapterId=a.organizationName,this.ignoreApiProducts=new Set(a.ignoreApiProducts||[]),this.catalogApiProducts=new Set(i),this.allowApiProductsOutsideCatalog=a.allowApiProductsOutsideCatalog??!1,this.config=a,this.stage=a.stage||"non-production"}async setAuthHeader(e){return e=e||{},e.headers={...e.headers,"Accept-Encoding":"identity",accept:"application/json",Authorization:"Bearer "+await N(this.config),"X-Api-Key":this.config.auth.type===w.OAUTH2?this.config.auth.clientId:void 0},e}getErrorMessage(e){if(!e)return"Fetch error";try{const t=JSON.parse(e);return t.code===f?t.code:t.error.details[0]?.["@type"]==="type.googleapis.com/google.rpc.PreconditionFailure"&&t.error.details[0]?.violations[0]?.type===f?f:t?.message||t.error.message}catch{return e}}async fetchData(e,t){const i=await this.setAuthHeader(t),a=typeof e=="string"?e:e.url,r=typeof e=="string"?"GET":e.method;n.verbose(`${r.toUpperCase()} request to "${a}"`);const o=await fetch(e,i);if(!o.ok){const u=await o.text(),c=this.getErrorMessage(u);if(c===f){const p=this.userClaims,g=b(p),l=U(p),d=this.email;return await this.createDeveloper(this.email,g,l,d),await this.fetchData(e,t)}throw o.status!==404&&n.warn(`${r.toUpperCase()} request to "${a}" failed with ${o.status} code`),new $(o.status,c)}return o.headers.get("x-redocly-apigee-version")===m.x&&(this.version=m.x),n.verbose(`${r.toUpperCase()} request to "${a}" OK`),o.json()}async getApps(){const e=`${this.developerUrl}/apps?expand=true`,{app:t}=await this.fetchData(e),i=(t||[]).map(A);return{data:i,total:i.length}}async getApiProducts(){const e=`${this.organizationUrl}/apiproducts?expand=true`,{apiProduct:t}=await this.fetchData(e),i=(t||[]).filter(a=>(this.allowApiProductsOutsideCatalog||this.catalogApiProducts.has(a.name))&&!this.ignoreApiProducts.has(a.name)).map(O);return{data:i,total:i.length}}async getApp(e){const t=`${this.developerUrl}/apps/${e}${this.version===m.edge?"?expand=true":""}`,i=await this.fetchData(t);return A(i)}createDeveloper(e,t,i,a){const r=`${this.organizationUrl}/developers`;return this.fetchData(r,{headers:{"Content-type":"application/json"},body:JSON.stringify({email:e,firstName:t,lastName:i,userName:a}),method:"POST"})}async createApp(e){const t=`${this.developerUrl}/apps`;n.verbose(`Creating app ${e.id} ${e.apiProductIds}`);const i=await this.fetchData(t,{headers:{"Content-type":"application/json"},body:JSON.stringify({name:e.id,apiProducts:e.apiProductIds||[],keyExpiresIn:1*365*24*60*60*1e3,attributes:v({...e.attributes,DisplayName:e.name,Notes:e.description||""})}),method:"POST"});if(e.credentials){const a=e.credentials[0];await this.fetchData(`${this.developerUrl}/apps/${e.id}/keys/create`,{headers:{"Content-type":"application/json"},body:JSON.stringify({consumerKey:a.clientId,consumerSecret:a.clientSecret,expiresInSeconds:C(a.expiresAt,E)}),method:"POST"}),n.info("Imported previously provided key");const r=i.credentials[0].consumerKey;await this.fetchData(`${this.developerUrl}/apps/${e.id}/keys/${r}`,{method:"DELETE"}),n.info("Deleted autogenerated key");const o=await this.fetchData(`${this.developerUrl}/apps/${e.id}/keys/${a.clientId}`,{headers:{"Content-type":"application/json"},body:JSON.stringify({apiProducts:e.apiProductIds||[]}),method:"POST"});i.credentials=[o]}return A(i)}async updateApp(e,t){const i=`${this.developerUrl}/apps/${e}`;try{const a=await this.getApp(e),r={...t.attributes};t.name&&(r.DisplayName=t.name),t.description&&(r.Notes=t.description);const o=await this.fetchData(i,{headers:{"Content-type":"application/json"},body:JSON.stringify({attributes:v({...a.attributes,...r})}),method:"PUT"});return A(o)}catch(a){if(a.message.includes("does not exist"))return;throw a}}async deleteApp(e){const t=`${this.developerUrl}/apps/${e}`;try{return await this.fetchData(t,{headers:{"Content-type":"application/json"},method:"DELETE"})}catch(i){if(i.message.includes("does not exist"))return;throw i}}async createCredential(e,t){const i=`${this.developerUrl}/apps/${e}`;let a;if(t.clientId&&t.clientSecret)await this.fetchData(`${this.developerUrl}/apps/${e}/keys/create`,{headers:{"Content-type":"application/json"},body:JSON.stringify({consumerKey:t.clientId,consumerSecret:t.clientSecret,expiresInSeconds:C(t.expiresAt,E)}),method:"POST"}),a=await this.fetchData(`${this.developerUrl}/apps/${e}/keys/${t.clientId}`,{headers:{"Content-type":"application/json"},body:JSON.stringify({apiProducts:t.apiProductIds||[]}),method:"POST"}),n.info("Imported previously provided key");else{const r=await this.getApp(e);a=(await this.fetchData(i,{headers:{"Content-type":"application/json"},method:"PUT",body:JSON.stringify({apiProducts:t.apiProductIds,attributes:v({...r.attributes,...t.attributes})})})).credentials[0]}return y(a)}async updateCredential(e,t,i){let a;try{a=await this.fetchData(`${this.developerUrl}/apps/${e}/keys/${t}`)}catch{a=void 0}if(!a)throw new $(404,"Cannot update credential that does not exist");const r=`${this.developerUrl}/apps/${e}/keys/${t}`,o=await this.fetchData(r,{headers:{"Content-type":"application/json"},method:"PUT",body:JSON.stringify({apiProducts:i.apiProductIds})}),u=o.apiProducts.filter(c=>!i.apiProductIds.includes(c.apiproduct)).map(c=>c.apiproduct);return await Promise.all(u.map(c=>this.fetchData(`${this.developerUrl}/apps/${e}/keys/${t}/apiproducts/${c}`,{method:"DELETE"}))),y(o)}async deleteCredential(e,t){const i=`${this.developerUrl}/apps/${e}/keys/${t}`;return y(await this.fetchData(i,{headers:{"Content-type":"application/octet-stream"},method:"DELETE"}))}async getAppLogDetails(e,t){throw new Error("Not implemented")}async getAppLogs(e,t){return{total:0,data:[]}}async getApiAccessStatus(e,t){const{data:i}=await this.getApps(),a=(i||[]).filter(p=>(p.credentials||[]).find(l=>l.apiProductsStatus.find(d=>d.id===e))),r=p=>a.find(g=>g.credentials?.find(d=>d.status===p&&d.apiProductsStatus.find(D=>D.id===e))),o=t?a.map(p=>{if(p.credentials?.find(l=>l.status==="approved"&&l.apiProductsStatus.find(d=>d.id===e)))return{id:p.id,title:p.name}}).filter(Boolean):void 0,u=r("approved");if(u)return{status:"ACCEPTED",appId:u.id,apps:o};const c=r("pending");return c?{status:"PENDING",appId:c.id,apps:o}:{status:"NONE"}}}function C(s,e){if(!(!s&&!e))return s=s||(Date.now()+e*1e3).toString(),Math.floor((parseInt(s,10)-Date.now())/1e3).toString()}export{L as ApigeeAdapter};
4
+ `,s.serviceAccountEmail,s.serviceAccountPrivateKey.slice(0,30)+"***"+s.serviceAccountPrivateKey.slice(-30));const t={grant_type:"urn:ietf:params:oauth:grant-type:jwt-bearer",assertion:await T.sign({sub:s.serviceAccountEmail,iss:s.serviceAccountEmail,aud:"https://www.googleapis.com/oauth2/v4/token",iat:Math.floor(Date.now()/1e3),exp:Math.floor(Date.now()/1e3)+3600,scope:"https://www.googleapis.com/auth/cloud-platform"},s.serviceAccountPrivateKey,b.RS256)};n.verbose("Exchanging JWT for access token",s.serviceAccountEmail,s.serviceAccountPrivateKey.slice(0,30)+"***"+s.serviceAccountPrivateKey.slice(-30));let a=await fetch("https://oauth2.googleapis.com/token",{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams(t).toString()});if(!a.ok)throw new Error(`Failed to get access token: ${a.statusText}
5
+ ${await a.text()}`);const i=await a.json(),{access_token:r,expires_in:o}=i;return n.info("Apigee access token received"),{token:r,expiresAt:Math.floor(Date.now()/1e3)+o}}class F{apiUrl;developerUrl;accessToken=null;organizationName;email;organizationUrl;version;userClaims;config;ignoreApiProducts;catalogApiProducts;allowApiProductsOutsideCatalog;adapterId;stage;rbacConfig;constructor(e,t,a,i){const r=e;this.apiUrl=r.apiUrl||"https://apigee.googleapis.com/v1",this.organizationName=r.organizationName,this.email=a.email,this.organizationUrl=`${this.apiUrl}/organizations/${this.organizationName}`,this.developerUrl=`${this.organizationUrl}/developers/${O(this.email)}`,this.version=e.type==="APIGEE_X"?m.x:m.edge,this.userClaims=a,this.adapterId=r.organizationName,this.ignoreApiProducts=new Set(r.ignoreApiProducts||[]),this.catalogApiProducts=new Map(Object.entries(i)),this.allowApiProductsOutsideCatalog=r.allowApiProductsOutsideCatalog??!1,this.config=r,this.stage=r.stage||"non-production",this.rbacConfig=t}async setAuthHeader(e){return e=e||{},e.headers={...e.headers,"Accept-Encoding":"identity",accept:"application/json",Authorization:"Bearer "+await I(this.config),"X-Api-Key":this.config.auth.type===w.OAUTH2?this.config.auth.clientId:void 0},e}getErrorMessage(e){if(!e)return"Fetch error";try{const t=JSON.parse(e);return t.code===f?t.code:t.error.details[0]?.["@type"]==="type.googleapis.com/google.rpc.PreconditionFailure"&&t.error.details[0]?.violations[0]?.type===f?f:t?.message||t.error.message}catch{return e}}async fetchData(e,t){const a=await this.setAuthHeader(t),i=typeof e=="string"?e:e.url,r=typeof e=="string"?"GET":e.method;n.verbose(`${r.toUpperCase()} request to "${i}"`);const o=await fetch(e,a);if(!o.ok){const u=await o.text(),c=this.getErrorMessage(u);if(c===f){const p=this.userClaims,g=U(p),l=k(p),d=this.email;return await this.createDeveloper(this.email,g,l,d),await this.fetchData(e,t)}throw o.status!==404&&n.warn(`${r.toUpperCase()} request to "${i}" failed with ${o.status} code`),new $(o.status,c)}return o.headers.get("x-redocly-apigee-version")===m.x&&(this.version=m.x),n.verbose(`${r.toUpperCase()} request to "${i}" OK`),o.json()}async getApps(){const e=`${this.developerUrl}/apps?expand=true`,{app:t}=await this.fetchData(e),a=(t||[]).map(A);return{data:a,total:a.length}}async getApiProducts(){const e=`${this.organizationUrl}/apiproducts?expand=true`,{apiProduct:t}=await this.fetchData(e),a=(t||[]).filter(i=>S(this.catalogApiProducts.get(i.name)||{},this.userClaims,this.rbacConfig)&&(this.allowApiProductsOutsideCatalog||this.catalogApiProducts.has(i.name))&&!this.ignoreApiProducts.has(i.name)).map(x);return{data:a,total:a.length}}async getApp(e){const t=`${this.developerUrl}/apps/${e}${this.version===m.edge?"?expand=true":""}`,a=await this.fetchData(t);return A(a)}createDeveloper(e,t,a,i){const r=`${this.organizationUrl}/developers`;return this.fetchData(r,{headers:{"Content-type":"application/json"},body:JSON.stringify({email:e,firstName:t,lastName:a,userName:i}),method:"POST"})}async createApp(e){const t=`${this.developerUrl}/apps`;n.verbose(`Creating app ${e.id} ${e.apiProductIds}`);const a=await this.fetchData(t,{headers:{"Content-type":"application/json"},body:JSON.stringify({name:e.id,apiProducts:e.apiProductIds||[],keyExpiresIn:1*365*24*60*60*1e3,attributes:v({...e.attributes,DisplayName:e.name,Notes:e.description||""})}),method:"POST"});if(e.credentials){const i=e.credentials[0];await this.fetchData(`${this.developerUrl}/apps/${e.id}/keys/create`,{headers:{"Content-type":"application/json"},body:JSON.stringify({consumerKey:i.clientId,consumerSecret:i.clientSecret,expiresInSeconds:E(i.expiresAt,C)}),method:"POST"}),n.info("Imported previously provided key");const r=a.credentials[0].consumerKey;await this.fetchData(`${this.developerUrl}/apps/${e.id}/keys/${r}`,{method:"DELETE"}),n.info("Deleted autogenerated key");const o=await this.fetchData(`${this.developerUrl}/apps/${e.id}/keys/${i.clientId}`,{headers:{"Content-type":"application/json"},body:JSON.stringify({apiProducts:e.apiProductIds||[]}),method:"POST"});a.credentials=[o]}return A(a)}async updateApp(e,t){const a=`${this.developerUrl}/apps/${e}`;try{const i=await this.getApp(e),r={...t.attributes};t.name&&(r.DisplayName=t.name),t.description&&(r.Notes=t.description);const o=await this.fetchData(a,{headers:{"Content-type":"application/json"},body:JSON.stringify({attributes:v({...i.attributes,...r})}),method:"PUT"});return A(o)}catch(i){if(i.message.includes("does not exist"))return;throw i}}async deleteApp(e){const t=`${this.developerUrl}/apps/${e}`;try{return await this.fetchData(t,{headers:{"Content-type":"application/json"},method:"DELETE"})}catch(a){if(a.message.includes("does not exist"))return;throw a}}async createCredential(e,t){const a=`${this.developerUrl}/apps/${e}`;let i;if(t.clientId&&t.clientSecret)await this.fetchData(`${this.developerUrl}/apps/${e}/keys/create`,{headers:{"Content-type":"application/json"},body:JSON.stringify({consumerKey:t.clientId,consumerSecret:t.clientSecret,expiresInSeconds:E(t.expiresAt,C)}),method:"POST"}),i=await this.fetchData(`${this.developerUrl}/apps/${e}/keys/${t.clientId}`,{headers:{"Content-type":"application/json"},body:JSON.stringify({apiProducts:t.apiProductIds||[]}),method:"POST"}),n.info("Imported previously provided key");else{const r=await this.getApp(e);i=(await this.fetchData(a,{headers:{"Content-type":"application/json"},method:"PUT",body:JSON.stringify({apiProducts:t.apiProductIds,attributes:v({...r.attributes,...t.attributes})})})).credentials[0]}return y(i)}async updateCredential(e,t,a){let i;try{i=await this.fetchData(`${this.developerUrl}/apps/${e}/keys/${t}`)}catch{i=void 0}if(!i)throw new $(404,"Cannot update credential that does not exist");const r=`${this.developerUrl}/apps/${e}/keys/${t}`,o=await this.fetchData(r,{headers:{"Content-type":"application/json"},method:"PUT",body:JSON.stringify({apiProducts:a.apiProductIds})}),u=o.apiProducts.filter(c=>!a.apiProductIds.includes(c.apiproduct)).map(c=>c.apiproduct);return await Promise.all(u.map(c=>this.fetchData(`${this.developerUrl}/apps/${e}/keys/${t}/apiproducts/${c}`,{method:"DELETE"}))),y(o)}async deleteCredential(e,t){const a=`${this.developerUrl}/apps/${e}/keys/${t}`;return y(await this.fetchData(a,{headers:{"Content-type":"application/octet-stream"},method:"DELETE"}))}async getAppLogDetails(e,t){throw new Error("Not implemented")}async getAppLogs(e,t){return{total:0,data:[]}}async getApiAccessStatus(e,t){const{data:a}=await this.getApps(),i=(a||[]).filter(p=>(p.credentials||[]).find(l=>l.apiProductsStatus.find(d=>d.id===e))),r=p=>i.find(g=>g.credentials?.find(d=>d.status===p&&d.apiProductsStatus.find(D=>D.id===e))),o=t?i.map(p=>{if(p.credentials?.find(l=>l.status==="approved"&&l.apiProductsStatus.find(d=>d.id===e)))return{id:p.id,title:p.name}}).filter(Boolean):void 0,u=r("approved");if(u)return{status:"ACCEPTED",appId:u.id,apps:o};const c=r("pending");return c?{status:"PENDING",appId:c.id,apps:o}:{status:"NONE"}}}function E(s,e){if(!(!s&&!e))return s=s||(Date.now()+e*1e3).toString(),Math.floor((parseInt(s,10)-Date.now())/1e3).toString()}export{F as ApigeeAdapter};
@@ -1,4 +1,4 @@
1
- import type { Adapter, App, Paginated, Credential, ApiProduct, ExpandedApp, LogsParams, Log, CredentialInput, ApiAccessStatus, LogDetails } from '../../types';
1
+ import type { Adapter, App, Paginated, Credential, ApiProduct, ExpandedApp, LogsParams, Log, CredentialInput, ApiAccessStatus, LogDetails, CatalogApiProduct } from '../../types';
2
2
  import type { GraviteeApp } from './types';
3
3
  import type { GraviteeAdapterConfig } from '@redocly/config';
4
4
  export declare class GraviteeAdapter implements Adapter {
@@ -9,13 +9,13 @@ export declare class GraviteeAdapter implements Adapter {
9
9
  email: string;
10
10
  };
11
11
  config: GraviteeAdapterConfig;
12
- catalogApiProducts: Set<string>;
12
+ catalogApiProducts: Map<string, CatalogApiProduct>;
13
13
  allowApiProductsOutsideCatalog: boolean;
14
14
  adapterId: string;
15
15
  stage: string;
16
16
  constructor(config: GraviteeAdapterConfig, userClaims: Record<string, string> & {
17
17
  email: string;
18
- }, accessToken: string, catalogApiProducts: string[]);
18
+ }, accessToken: string, catalogApiProducts: Record<string, CatalogApiProduct>);
19
19
  setAuthHeader(init: any): Promise<any>;
20
20
  protected getErrorMessage(text: string): any;
21
21
  protected fetchData<T>(input: RequestInfo, init?: RequestInit): Promise<T>;
@@ -1,2 +1,2 @@
1
1
  import{LRUCache as w}from"lru-cache";import{randomUUID as m}from"../../../../../utils/crypto/random-uuid.js";import{HTTP_METHOD_TO_QUERY_CODE as y}from"./constants.js";const h="developer.service.DeveloperDoesNotExist";function g(r,t){return{id:r.id,name:r.name,description:r.description,attributes:{},createdAt:Date.parse(r.created_at).toString(),lastModifiedAt:Date.parse(r.updated_at).toString(),scopes:[],credentials:t||[],clientId:r.settings?.app?.client_id||r.settings?.oauth?.client_id||void 0,apiProductIds:t?.flatMap(e=>e.apiProductIds||[])||[],canCreateKey:!t?.length,supportsLogs:!0}}function E({id:r,method:t,path:e,responseTime:s,status:a,timestamp:i,api:n}){return{id:r,timestamp:i.toString(),path:e,method:t,statusCode:a,responseTime:s,apiId:n}}function P({id:r,timestamp:t,metadata:e,status:s,requestContentLength:a,responseContentLength:i,request:n,response:c,path:d}){const o=Object.values(e).find(p=>p.ip)?.ip;return{id:r,timestamp:t.toString(),path:d,ipAddress:o,statusCode:s,request:{contentLength:a,body:n?.body,headers:n?.headers||{}},response:{contentLength:i,body:c?.body,headers:c?.headers||{}}}}function D(r){if(!r.apis?.length&&!r.methods?.length&&!r.statusCodes?.length)return;const t=[];return r.apis?.length&&t.push(`api:(${r.apis.join(" OR ")})`),r.methods?.length&&t.push(`method:(${r.methods.map(e=>y[e]).join(" OR ")})`),r.statusCodes?.length&&t.push(`status:(${r.statusCodes.join(" OR ")})`),t.join(" AND ")}function b({page:r,size:t,fromDate:e,toDate:s,order:a,filters:i}){return{page:r,size:t||50,from:e||Date.now()-1e3*60*60*24*90,to:s||Date.now(),order:a||"DESC",query:D(i)}}function l(r){switch(r){case"ACCEPTED":return"approved";case"REJECTED":case"PAUSED":return"revoked";case"PENDING":case"CLOSED":return"pending";default:throw new Error(`Unknown status: ${r}`)}}function S(r){return{id:r.id,name:r.name,description:r.description,attributes:{},createdAt:r.created_at?Date.parse(r.created_at).toString():"",lastModifiedAt:r.updated_at?Date.parse(r.updated_at).toString():"",scopes:[]}}const f=new w({max:1e4});async function $(r,t){console.log("Exchanging IdP token for new Gravitee token");let e=await fetch(`${r}/auth/oauth2/gravitee-am-oidc/_exchange?token=`+t,{method:"POST",headers:{Accept:"application/json"}});if(!e.ok)throw new Error(`Failed to get access token: ${e.statusText}
2
- ${await e.text()}`);console.log("Exchanged successfully");const s=await e.json(),{token:a,expires_in:i=3600*48}=s;return{token:a,expiresAt:Math.floor(Date.now()/1e3)+i}}async function T(r,t,e){if(!r.auth)return;if("static"in r.auth)return r.auth?.static;if(!e)throw new Error("No access token provided");let s=f.get(e);return(!s||(await s).expiresAt<Date.now()/1e3)&&(s=$(t,e).catch(a=>{throw f.delete(e),a}),f.set(e,s)),(await s).token}class U{apiUrl;accessToken;email;userClaims;config;catalogApiProducts;allowApiProductsOutsideCatalog;adapterId="";stage="";constructor(t,e,s,a){this.config=t,this.apiUrl=`${this.config.apiBaseUrl}/portal/environments/${this.config.env||"DEFAULT"}`,this.email=e.email,this.userClaims=e,this.accessToken=s,this.stage=t.stage||"non-production",this.catalogApiProducts=new Set(a),this.allowApiProductsOutsideCatalog=t.allowApiProductsOutsideCatalog??!1}async setAuthHeader(t){return t=t||{},t.headers={...t.headers,"Accept-Encoding":"identity",accept:"application/json",Authorization:"Bearer "+await T(this.config,this.apiUrl,this.accessToken)},t}getErrorMessage(t){if(!t)return"Fetch error";try{const e=JSON.parse(t);return e.code===h?e.code:e.error.details[0]?.["@type"]==="type.googleapis.com/google.rpc.PreconditionFailure"&&e.error.details[0]?.violations[0]?.type===h?h:e?.message||e.error.message}catch{return t}}async fetchData(t,e){const s=await this.setAuthHeader(e),a=await fetch(t,s);if(!a.ok){const i=await a.json();throw new Error(i.message||i?.errors?.[0]?.message)}return a.json()}async fetchAppCredentials(t,e=!1){const s=[],a=await this.fetchData(`${this.apiUrl}/subscriptions?applicationId=${t.id}&size=-1&statuses=ACCEPTED&statuses=PAUSED&statuses=PENDING`),i=a.data[0],n=t.api_key_mode==="SHARED"?i?[i]:[]:a.data;return await Promise.all(n.map(async c=>{const d=await this.fetchData(`${this.apiUrl}/subscriptions/${c.id}?include=keys`);d.keys?.length||(s.push({id:d.id,expiresAt:"-1",issuedAt:"-1",canBeRolled:!0,canBeRevoked:!1,clientSecret:"",attributes:{},status:l(i.status),apiProductsStatus:t.api_key_mode==="SHARED"?a.data.map(o=>({id:o.id,apiId:o.api,name:a.metadata[o.api].name,status:l(o.status)})):[{id:c.id,apiId:c.api,name:a.metadata[c.api].name,status:l(c.status)}]}),s[s.length-1].apiProductIds=s[s.length-1].apiProductsStatus.map(o=>o.apiId));for(const o of d.keys||[])o.expired||o.revoked&&!e||(s.push({id:o.key,expiresAt:o.expire_at?Date.parse(o.expire_at).toString():"-1",canBeRolled:o.expire_at==null,canBeRevoked:!1,issuedAt:Date.parse(o.created_at).toString(),clientSecret:o.key,attributes:{},status:l(i.status),apiProductsStatus:t.api_key_mode==="SHARED"?a.data.map(p=>({id:p.id,apiId:p.api,name:a.metadata[p.api].name,status:l(p.status)})):o.subscriptions.map(p=>({id:c.id,apiId:p.api,name:a.metadata[p.api].name,status:l(c.status)}))}),s[s.length-1].apiProductIds=s[s.length-1].apiProductsStatus.map(p=>p.apiId))})),s}async unsubscribeFromApis(t,e){const s=await this.getApp(t),a=[],i=await this.setAuthHeader({});return e.map(n=>{const c=s.credentials.find(u=>u.apiProductIds?.includes(n)),d=c?.apiProductIds?.findIndex(u=>u===n),o=c?.apiProductsStatus[d??-1]?.id;if(!o)throw new Error("Not found");const p=`${this.apiUrl}/subscriptions/${o}/_close`;a.push(fetch(p,{...i,method:"POST"}))}),Promise.all(a)}async subscribeToApis(t,e){return Promise.all(e.map(async s=>{const a=await this.fetchData(`${this.apiUrl}/apis/${s}/plans?size=-1`),i=a.data.find(n=>n.security==="API_KEY"&&n.validation=="AUTO")||a.data.find(n=>n.security==="API_KEY")||a.data[0];if(!i)throw new Error("No plan found");return this.fetchData(`${this.apiUrl}/subscriptions`,{headers:{"Content-type":"application/json"},body:JSON.stringify({application:t,plan:i.id,request:""}),method:"POST"})}))}async getApps(){const t=`${this.apiUrl}/applications?size=-1`,e=await this.fetchData(t),{data:s}=e,a=(s||[]).map(i=>g(i));return{data:a,total:a.length}}async getApiProducts(){const t=`${this.apiUrl}/apis?size=-1`,e=await this.fetchData(t),{data:s}=e,a=(s||[]).filter(i=>this.allowApiProductsOutsideCatalog||this.catalogApiProducts.has(i.name)).map(i=>S(i));return{data:a,total:a.length}}async getApp(t){const e=`${this.apiUrl}/applications/${t}`,s=await this.fetchData(e);let a=await this.fetchAppCredentials(s);return g(s,a)}async createApp(t){const e=`${this.apiUrl}/applications`;if(!t.apiProductIds||!t.apiProductIds.length)throw new Error("At least one API Product is required");const s=await this.fetchData(e,{headers:{"Content-type":"application/json"},body:JSON.stringify({name:t.name,description:t.description||"",domain:t.attributes?.domain||null,picture:t.attributes?.picture||null,api_key_mode:"SHARED",background:void 0,settings:{app:{type:t.attributes?.appType||"",client_id:t.attributes?.clientId||m()}}}),method:"POST"});if(await this.subscribeToApis(s.id,t.apiProductIds||[]),t.credentials)throw new Error("Gravitee adapter does not support manual credentials");return this.getApp(s.id)}async getAppLogDetails(t,e){const s=`${this.apiUrl}/applications/${t}/logs/${e}`,a=await this.fetchData(s);return P(a)}async getAppLogs(t,e){const s=new URL(`${this.apiUrl}/applications/${t}/logs`),a=b(e);Object.keys(a).forEach(n=>{a[n]&&s.searchParams.append(n,a[n])});const i=await this.fetchData(s.toString());return{total:i.metadata.data.total,data:i.data.map(E)}}async updateApp(t,e){const s=`${this.apiUrl}/applications/${t}`,a=await this.getApp(t),i=await this.fetchData(s,{headers:{"Content-type":"application/json"},body:JSON.stringify({id:t,name:e.name||a.name,description:e.description||a.description||"",domain:e.attributes?.domain||a.attributes?.domain||null,picture:e.attributes?.picture||a.attributes?.picture||null,api_key_mode:"SHARED",background:void 0,settings:{app:{type:e.attributes?.appType||a.attributes?.appType||"",client_id:e.attributes?.clientId||a.attributes?.clientId||m()}}}),method:"PUT"});return this.getApp(i.id)}async deleteApp(t){const e=`${this.apiUrl}/applications/${t}`;await this.fetchData(e,{method:"DELETE"})}async createCredential(t,e){const s=await this.getApp(t),a=new Set(e.apiProductIds.filter(c=>!(s.apiProductIds||[]).includes(c))),i=new Set((s.apiProductIds||[]).filter(c=>!e.apiProductIds.includes(c)));return await this.subscribeToApis(t,Array.from(a)),await this.unsubscribeFromApis(t,Array.from(i)),(await this.getApp(t)).credentials[0]}async updateCredential(t,e,s){if(s.apiProductIds)return this.createCredential(t,s);const a=`${this.apiUrl}/applications/${t}`,i=await this.fetchData(a);let n;if(i.api_key_mode==="SHARED")n=`${this.apiUrl}/applications/${t}/keys/_renew`;else{const p=(await this.fetchAppCredentials(i)).find(A=>A.id===e);if(!p)throw new Error("Not found!");const u=p.apiProductsStatus[0].id;n=`${this.apiUrl}/subscriptions/${u}/keys/_renew`}const c=await fetch(n,await this.setAuthHeader({method:"POST"}));if(!c.ok)throw new Error(`Failed to renew the key: ${c.statusText}`);return(await this.fetchAppCredentials(i,!0)).find(o=>o.id===e)}async deleteCredential(t,e){const s=`${this.apiUrl}/applications/${t}`,a=await this.fetchData(s);let i;if(a.api_key_mode==="SHARED")i=`${this.apiUrl}/applications/${t}/keys/${e}/_revoke`;else{const o=(await this.fetchAppCredentials(a)).find(u=>u.id===e);if(!o)throw new Error("Not found!");const p=o.apiProductsStatus[0].id;i=`${this.apiUrl}/subscriptions/${p}/keys/${e}/_revoke`}const n=await fetch(i,await this.setAuthHeader({method:"POST"}));if(!n.ok)throw new Error(`Failed to remove the key: ${n.statusText}`);return(await this.fetchAppCredentials(a,!0)).find(d=>d.id===e)}async getApiAccessStatus(t,e){const s=`${this.apiUrl}/subscriptions?apiId=${t}&size=-1&statuses=ACCEPTED&statuses=PENDING`,a=await this.fetchData(s),i=e?a.data.map(d=>{if(d.status==="ACCEPTED")return{id:d.application,title:a.metadata[d.application]?.name||d.application}}).filter(Boolean):void 0,n=a.data.find(d=>d.status==="ACCEPTED");if(n)return{status:"ACCEPTED",appId:n.application,apps:i};const c=a.data.find(d=>d.status==="PENDING");return c?{status:"PENDING",appId:c.application,apps:i}:{status:"NONE"}}}export{U as GraviteeAdapter};
2
+ ${await e.text()}`);console.log("Exchanged successfully");const s=await e.json(),{token:a,expires_in:i=3600*48}=s;return{token:a,expiresAt:Math.floor(Date.now()/1e3)+i}}async function T(r,t,e){if(!r.auth)return;if("static"in r.auth)return r.auth?.static;if(!e)throw new Error("No access token provided");let s=f.get(e);return(!s||(await s).expiresAt<Date.now()/1e3)&&(s=$(t,e).catch(a=>{throw f.delete(e),a}),f.set(e,s)),(await s).token}class U{apiUrl;accessToken;email;userClaims;config;catalogApiProducts;allowApiProductsOutsideCatalog;adapterId="";stage="";constructor(t,e,s,a){this.config=t,this.apiUrl=`${this.config.apiBaseUrl}/portal/environments/${this.config.env||"DEFAULT"}`,this.email=e.email,this.userClaims=e,this.accessToken=s,this.stage=t.stage||"non-production",this.catalogApiProducts=new Map(Object.entries(a)),this.allowApiProductsOutsideCatalog=t.allowApiProductsOutsideCatalog??!1}async setAuthHeader(t){return t=t||{},t.headers={...t.headers,"Accept-Encoding":"identity",accept:"application/json",Authorization:"Bearer "+await T(this.config,this.apiUrl,this.accessToken)},t}getErrorMessage(t){if(!t)return"Fetch error";try{const e=JSON.parse(t);return e.code===h?e.code:e.error.details[0]?.["@type"]==="type.googleapis.com/google.rpc.PreconditionFailure"&&e.error.details[0]?.violations[0]?.type===h?h:e?.message||e.error.message}catch{return t}}async fetchData(t,e){const s=await this.setAuthHeader(e),a=await fetch(t,s);if(!a.ok){const i=await a.json();throw new Error(i.message||i?.errors?.[0]?.message)}return a.json()}async fetchAppCredentials(t,e=!1){const s=[],a=await this.fetchData(`${this.apiUrl}/subscriptions?applicationId=${t.id}&size=-1&statuses=ACCEPTED&statuses=PAUSED&statuses=PENDING`),i=a.data[0],n=t.api_key_mode==="SHARED"?i?[i]:[]:a.data;return await Promise.all(n.map(async c=>{const d=await this.fetchData(`${this.apiUrl}/subscriptions/${c.id}?include=keys`);d.keys?.length||(s.push({id:d.id,expiresAt:"-1",issuedAt:"-1",canBeRolled:!0,canBeRevoked:!1,clientSecret:"",attributes:{},status:l(i.status),apiProductsStatus:t.api_key_mode==="SHARED"?a.data.map(o=>({id:o.id,apiId:o.api,name:a.metadata[o.api].name,status:l(o.status)})):[{id:c.id,apiId:c.api,name:a.metadata[c.api].name,status:l(c.status)}]}),s[s.length-1].apiProductIds=s[s.length-1].apiProductsStatus.map(o=>o.apiId));for(const o of d.keys||[])o.expired||o.revoked&&!e||(s.push({id:o.key,expiresAt:o.expire_at?Date.parse(o.expire_at).toString():"-1",canBeRolled:o.expire_at==null,canBeRevoked:!1,issuedAt:Date.parse(o.created_at).toString(),clientSecret:o.key,attributes:{},status:l(i.status),apiProductsStatus:t.api_key_mode==="SHARED"?a.data.map(p=>({id:p.id,apiId:p.api,name:a.metadata[p.api].name,status:l(p.status)})):o.subscriptions.map(p=>({id:c.id,apiId:p.api,name:a.metadata[p.api].name,status:l(c.status)}))}),s[s.length-1].apiProductIds=s[s.length-1].apiProductsStatus.map(p=>p.apiId))})),s}async unsubscribeFromApis(t,e){const s=await this.getApp(t),a=[],i=await this.setAuthHeader({});return e.map(n=>{const c=s.credentials.find(u=>u.apiProductIds?.includes(n)),d=c?.apiProductIds?.findIndex(u=>u===n),o=c?.apiProductsStatus[d??-1]?.id;if(!o)throw new Error("Not found");const p=`${this.apiUrl}/subscriptions/${o}/_close`;a.push(fetch(p,{...i,method:"POST"}))}),Promise.all(a)}async subscribeToApis(t,e){return Promise.all(e.map(async s=>{const a=await this.fetchData(`${this.apiUrl}/apis/${s}/plans?size=-1`),i=a.data.find(n=>n.security==="API_KEY"&&n.validation=="AUTO")||a.data.find(n=>n.security==="API_KEY")||a.data[0];if(!i)throw new Error("No plan found");return this.fetchData(`${this.apiUrl}/subscriptions`,{headers:{"Content-type":"application/json"},body:JSON.stringify({application:t,plan:i.id,request:""}),method:"POST"})}))}async getApps(){const t=`${this.apiUrl}/applications?size=-1`,e=await this.fetchData(t),{data:s}=e,a=(s||[]).map(i=>g(i));return{data:a,total:a.length}}async getApiProducts(){const t=`${this.apiUrl}/apis?size=-1`,e=await this.fetchData(t),{data:s}=e,a=(s||[]).filter(i=>this.allowApiProductsOutsideCatalog||this.catalogApiProducts.has(i.name)).map(i=>S(i));return{data:a,total:a.length}}async getApp(t){const e=`${this.apiUrl}/applications/${t}`,s=await this.fetchData(e);let a=await this.fetchAppCredentials(s);return g(s,a)}async createApp(t){const e=`${this.apiUrl}/applications`;if(!t.apiProductIds||!t.apiProductIds.length)throw new Error("At least one API Product is required");const s=await this.fetchData(e,{headers:{"Content-type":"application/json"},body:JSON.stringify({name:t.name,description:t.description||"",domain:t.attributes?.domain||null,picture:t.attributes?.picture||null,api_key_mode:"SHARED",background:void 0,settings:{app:{type:t.attributes?.appType||"",client_id:t.attributes?.clientId||m()}}}),method:"POST"});if(await this.subscribeToApis(s.id,t.apiProductIds||[]),t.credentials)throw new Error("Gravitee adapter does not support manual credentials");return this.getApp(s.id)}async getAppLogDetails(t,e){const s=`${this.apiUrl}/applications/${t}/logs/${e}`,a=await this.fetchData(s);return P(a)}async getAppLogs(t,e){const s=new URL(`${this.apiUrl}/applications/${t}/logs`),a=b(e);Object.keys(a).forEach(n=>{a[n]&&s.searchParams.append(n,a[n])});const i=await this.fetchData(s.toString());return{total:i.metadata.data.total,data:i.data.map(E)}}async updateApp(t,e){const s=`${this.apiUrl}/applications/${t}`,a=await this.getApp(t),i=await this.fetchData(s,{headers:{"Content-type":"application/json"},body:JSON.stringify({id:t,name:e.name||a.name,description:e.description||a.description||"",domain:e.attributes?.domain||a.attributes?.domain||null,picture:e.attributes?.picture||a.attributes?.picture||null,api_key_mode:"SHARED",background:void 0,settings:{app:{type:e.attributes?.appType||a.attributes?.appType||"",client_id:e.attributes?.clientId||a.attributes?.clientId||m()}}}),method:"PUT"});return this.getApp(i.id)}async deleteApp(t){const e=`${this.apiUrl}/applications/${t}`;await this.fetchData(e,{method:"DELETE"})}async createCredential(t,e){const s=await this.getApp(t),a=new Set(e.apiProductIds.filter(c=>!(s.apiProductIds||[]).includes(c))),i=new Set((s.apiProductIds||[]).filter(c=>!e.apiProductIds.includes(c)));return await this.subscribeToApis(t,Array.from(a)),await this.unsubscribeFromApis(t,Array.from(i)),(await this.getApp(t)).credentials[0]}async updateCredential(t,e,s){if(s.apiProductIds)return this.createCredential(t,s);const a=`${this.apiUrl}/applications/${t}`,i=await this.fetchData(a);let n;if(i.api_key_mode==="SHARED")n=`${this.apiUrl}/applications/${t}/keys/_renew`;else{const p=(await this.fetchAppCredentials(i)).find(A=>A.id===e);if(!p)throw new Error("Not found!");const u=p.apiProductsStatus[0].id;n=`${this.apiUrl}/subscriptions/${u}/keys/_renew`}const c=await fetch(n,await this.setAuthHeader({method:"POST"}));if(!c.ok)throw new Error(`Failed to renew the key: ${c.statusText}`);return(await this.fetchAppCredentials(i,!0)).find(o=>o.id===e)}async deleteCredential(t,e){const s=`${this.apiUrl}/applications/${t}`,a=await this.fetchData(s);let i;if(a.api_key_mode==="SHARED")i=`${this.apiUrl}/applications/${t}/keys/${e}/_revoke`;else{const o=(await this.fetchAppCredentials(a)).find(u=>u.id===e);if(!o)throw new Error("Not found!");const p=o.apiProductsStatus[0].id;i=`${this.apiUrl}/subscriptions/${p}/keys/${e}/_revoke`}const n=await fetch(i,await this.setAuthHeader({method:"POST"}));if(!n.ok)throw new Error(`Failed to remove the key: ${n.statusText}`);return(await this.fetchAppCredentials(a,!0)).find(d=>d.id===e)}async getApiAccessStatus(t,e){const s=`${this.apiUrl}/subscriptions?apiId=${t}&size=-1&statuses=ACCEPTED&statuses=PENDING`,a=await this.fetchData(s),i=e?a.data.map(d=>{if(d.status==="ACCEPTED")return{id:d.application,title:a.metadata[d.application]?.name||d.application}}).filter(Boolean):void 0,n=a.data.find(d=>d.status==="ACCEPTED");if(n)return{status:"ACCEPTED",appId:n.application,apps:i};const c=a.data.find(d=>d.status==="PENDING");return c?{status:"PENDING",appId:c.application,apps:i}:{status:"NONE"}}}export{U as GraviteeAdapter};
@@ -1,6 +1,7 @@
1
1
  import type { Context, Next } from 'hono';
2
- import type { DevOnboardingAdapterConfig } from '@redocly/config';
3
- export declare function integrationsMiddleware(integrations: DevOnboardingAdapterConfig[], catalogApiProducts: string[]): (ctx: Context, next: Next) => Promise<(Response & import("hono").TypedResponse<{
2
+ import type { DevOnboardingAdapterConfig, RbacConfig } from '@redocly/config';
3
+ import type { CatalogApiProduct } from '../types.js';
4
+ export declare function integrationsMiddleware(integrations: DevOnboardingAdapterConfig[], catalogApiProducts: Record<string, CatalogApiProduct>, rbacConfig: RbacConfig): (ctx: Context, next: Next) => Promise<(Response & import("hono").TypedResponse<{
4
5
  error: string;
5
6
  }, 401, "json">) | undefined>;
6
7
  //# sourceMappingURL=integrations.d.ts.map
@@ -1 +1 @@
1
- import{AdapterFactory as i}from"../adapter-factory.js";import{CombineAdapter as s}from"../combine.js";const p=new i;function A(n,o){return async(e,d)=>{const t=e.get("auth");if(!t.isAuthenticated)return e.json({error:"Unauthorized"},401);const r=n.map(a=>p.getAdapter(a,o,t.claims,t.idpAccessToken));if(r.length===1)e.set("devOnboardingAdapter",r[0]);else{const a=new s(r);e.set("devOnboardingAdapter",a)}await d()}}export{A as integrationsMiddleware};
1
+ import{AdapterFactory as s}from"../adapter-factory.js";import{CombineAdapter as p}from"../combine.js";const c=new s;function u(n,o,i){return async(e,d)=>{const t=e.get("auth");if(!t.isAuthenticated)return e.json({error:"Unauthorized"},401);const r=n.map(a=>c.getAdapter({config:a,catalogApiProducts:o,userClaims:t.claims,rbacConfig:i,idpAccessToken:t.idpAccessToken}));if(r.length===1)e.set("devOnboardingAdapter",r[0]);else{const a=new p(r);e.set("devOnboardingAdapter",a)}await d()}}export{u as integrationsMiddleware};
@@ -1 +1 @@
1
- import{requireAuthMiddleware as e}from"../middlewares/auth.js";import{integrationsMiddleware as s}from"../middlewares/integrations.js";import{listApps as d,createApp as l,getApp as g,createCredential as c,updateCredential as n,deleteCredential as k,deleteApp as y,updateApp as o,getLogs as A,getLogDetails as m}from"./apps.js";import{getApiAccessStatus as f,listApiProducts as u}from"./products.js";function P(i,t){const p=t.getConfig().developerOnboarding?.adapters||[],a=Object.keys(t.globalData.apiProducts||{});p&&(i.get("/api/api-keys/apps",e(),s(p,a),d(t)),i.post("/api/api-keys/apps",e(),s(p,a),l(t)),i.get("/api/api-keys/apps/:id",e(),s(p,a),g(t)),i.put("/api/api-keys/apps/:id",e(),s(p,a),o(t)),i.delete("/api/api-keys/apps/:id",e(),s(p,a),y(t)),i.post("/api/api-keys/apps/:id/credentials",e(),s(p,a),c(t)),i.put("/api/api-keys/apps/:id/credentials/:credentialId",e(),s(p,a),n(t)),i.delete("/api/api-keys/apps/:id/credentials/:credentialId",e(),s(p,a),k(t)),i.get("/api/api-keys/apps/:id/logs/:logId",e(),s(p,a),m()),i.get("/api/api-keys/apps/:id/logs",e(),s(p,a),A()),i.get("/api/api-keys/api-products",e(),s(p,a),u(t)),i.get("/api/api-keys/api-products/:id/access",e(),s(p,a),f()))}export{P as installRoutes};
1
+ import{requireAuthMiddleware as t}from"../middlewares/auth.js";import{integrationsMiddleware as d}from"../middlewares/integrations.js";import{listApps as l,createApp as c,getApp as g,createCredential as n,updateCredential as o,deleteCredential as k,deleteApp as y,updateApp as A,getLogs as f,getLogDetails as m}from"./apps.js";import{getApiAccessStatus as C,listApiProducts as b}from"./products.js";function v(a,i){const p=i.getConfig().developerOnboarding?.adapters||[],e=i.getConfig().access?.rbac||{},s=i.globalData.apiProducts||{};p&&(a.get("/api/api-keys/apps",t(),d(p,s,e),l(i)),a.post("/api/api-keys/apps",t(),d(p,s,e),c(i)),a.get("/api/api-keys/apps/:id",t(),d(p,s,e),g(i)),a.put("/api/api-keys/apps/:id",t(),d(p,s,e),A(i)),a.delete("/api/api-keys/apps/:id",t(),d(p,s,e),y(i)),a.post("/api/api-keys/apps/:id/credentials",t(),d(p,s,e),n(i)),a.put("/api/api-keys/apps/:id/credentials/:credentialId",t(),d(p,s,e),o(i)),a.delete("/api/api-keys/apps/:id/credentials/:credentialId",t(),d(p,s,e),k(i)),a.get("/api/api-keys/apps/:id/logs/:logId",t(),d(p,s,e),m()),a.get("/api/api-keys/apps/:id/logs",t(),d(p,s,e),f()),a.get("/api/api-keys/api-products",t(),d(p,s,e),b(i)),a.get("/api/api-keys/api-products/:id/access",t(),d(p,s,e),C()))}export{v as installRoutes};
@@ -1,3 +1,4 @@
1
+ import type { REDOCLY_ROUTE_RBAC, REDOCLY_TEAMS_RBAC, RbacScopeItems } from '@redocly/config';
1
2
  export type App = {
2
3
  id: string;
3
4
  name: string;
@@ -16,6 +17,13 @@ export type ExpandedApp = {
16
17
  credentials: Credential[];
17
18
  _adapterIds?: string[];
18
19
  } & App;
20
+ export type CatalogApiProduct = {
21
+ [REDOCLY_TEAMS_RBAC]?: RbacScopeItems;
22
+ [REDOCLY_ROUTE_RBAC]?: {
23
+ slug?: string;
24
+ fsPath?: string;
25
+ };
26
+ };
19
27
  export type ApiProduct = {
20
28
  id: string;
21
29
  name: string;
@@ -1,4 +1,4 @@
1
- import n,{useMemo as D,useState as O}from"react";import{Popup as h}from"reactjs-popup";import l from"styled-components";import{useQuery as N}from"@tanstack/react-query";import{DateTimeRangePicker as R}from"@wojtekmaj/react-datetimerange-picker";import"@wojtekmaj/react-datetimerange-picker/dist/DateTimeRangePicker.css";import{fetch as S}from"../../../../../client/app/utils";import{PopupMenuUl as I}from"./PopupMenuUl";const A=[{name:"OTHER",id:"OTHER"},{name:"CONNECT",id:"CONNECT"},{name:"DELETE",id:"DELETE"},{name:"GET",id:"GET"},{name:"HEAD",id:"HEAD"},{name:"OPTIONS",id:"OPTIONS"},{name:"PATCH",id:"PATCH"},{name:"POST",id:"POST"},{name:"PUT",id:"PUT"},{name:"TRACE",id:"TRACE"}],y=[{type:"predefined",name:"last 5m",fromDateOffset:1e3*60*5},{type:"predefined",name:"last 1h",fromDateOffset:1e3*60*60},{type:"predefined",name:"last 3h",fromDateOffset:1e3*60*60*3},{type:"predefined",name:"last 12h",fromDateOffset:1e3*60*60*12},{type:"predefined",name:"last 1d",fromDateOffset:1e3*60*60*24},{type:"predefined",name:"last 3d",fromDateOffset:1e3*60*60*24*3},{type:"predefined",name:"last 7d",fromDateOffset:1e3*60*60*24*7},{type:"predefined",name:"last 30d",fromDateOffset:1e3*60*60*24*30}],P=[{name:"100 CONTINUE",id:"100"},{name:"101 SWITCHING PROTOCOLS",id:"101"},{name:"102 PROCESSING",id:"102"},{name:"200 OK",id:"200"},{name:"201 CREATED",id:"201"},{name:"202 ACCEPTED",id:"202"},{name:"203 NON AUTHORITATIVE INFORMATION",id:"203"},{name:"204 NO CONTENT",id:"204"},{name:"205 RESET CONTENT",id:"205"},{name:"206 PARTIAL CONTENT",id:"206"},{name:"207 MULTI STATUS",id:"207"},{name:"300 MULTIPLE CHOICES",id:"300"},{name:"301 MOVED PERMANENTLY",id:"301"},{name:"302 FOUND",id:"302"},{name:"303 SEE OTHER",id:"303"},{name:"304 NOT MODIFIED",id:"304"},{name:"305 USE PROXY",id:"305"},{name:"307 TEMPORARY REDIRECT",id:"307"},{name:"400 BAD REQUEST",id:"400"},{name:"401 UNAUTHORIZED",id:"401"},{name:"402 PAYMENT REQUIRED",id:"402"},{name:"403 FORBIDDEN",id:"403"},{name:"404 NOT FOUND",id:"404"},{name:"405 METHOD NOT ALLOWED",id:"405"},{name:"406 NOT ACCEPTABLE",id:"406"},{name:"407 PROXY AUTHENTICATION REQUIRED",id:"407"},{name:"408 REQUEST TIMEOUT",id:"408"},{name:"409 CONFLICT",id:"409"},{name:"410 GONE",id:"410"},{name:"411 LENGTH REQUIRED",id:"411"},{name:"412 PRECONDITION FAILED",id:"412"},{name:"413 REQUEST ENTITY TOO LARGE",id:"413"},{name:"414 REQUEST URI TOO LONG",id:"414"},{name:"415 UNSUPPORTED MEDIA TYPE",id:"415"},{name:"416 REQUESTED RANGE NOT SATISFIABLE",id:"416"},{name:"417 EXPECTATION FAILED",id:"417"},{name:"422 UNPROCESSABLE ENTITY",id:"422"},{name:"423 LOCKED",id:"423"},{name:"424 FAILED DEPENDENCY",id:"424"},{name:"429 TOO MANY REQUESTS",id:"429"},{name:"500 INTERNAL SERVER ERROR",id:"500"},{name:"501 NOT IMPLEMENTED",id:"501"},{name:"502 BAD GATEWAY",id:"502"},{name:"503 SERVICE UNAVAILABLE",id:"503"},{name:"504 GATEWAY TIMEOUT",id:"504"},{name:"505 HTTP VERSION NOT SUPPORTED",id:"505"},{name:"507 INSUFFICIENT STORAGE",id:"507"}];function x(e){return n.createElement(L,null,n.createElement(w,{onFiltersChange:e.onFiltersChange,activeFilters:e.activeFilters}),n.createElement(U,null))}var j=n.memo(x);const U=()=>null,w=n.memo(e=>{const{onFiltersChange:d,activeFilters:t}=e,{data:i}=N({queryKey:["API-PRODUCTS"],queryFn:()=>S("/api/api-keys/api-products").then(o=>o.json())}),[s,r]=O(),a=()=>r(void 0),m=(o,g)=>{const T={...t,[o]:g};d(T)};return n.createElement(h,{trigger:n.createElement(k,null,"Filter"),position:"bottom right"},n.createElement(_,null,n.createElement(E,{open:s==="api",name:"API name",options:i||[],activeOptions:t.api,onOpen:()=>r("api"),onClose:a,onChange:o=>m("api",o),active:(t.api?.length??0)>0}),n.createElement(E,{open:s==="status",name:"Status",options:P,activeOptions:t.status,onOpen:()=>r("status"),onClose:a,onChange:o=>m("status",o),active:(t.status?.length??0)>0}),n.createElement(E,{open:s==="method",name:"Method",options:A,activeOptions:t.method,onOpen:()=>r("method"),onClose:a,onChange:o=>m("method",o),active:(t.method?.length??0)>0}),n.createElement(E,{name:"Date range",open:s==="date",onOpen:()=>r("date"),onClose:a,active:!!t.date,renderSubmenu:()=>n.createElement(M,{onChange:o=>m("date",o),selectedDateFilter:t.date})}),n.createElement(b,null),n.createElement(H,{onClick:()=>d({})},"Clear filters")))}),M=e=>{const{selectedDateFilter:d,onChange:t}=e,i=d?.type==="custom",[s,r]=O(!1),[a,m]=O([null,null]),o=a?.[0]?a[0]:null,g=a?.[1]?a[1]:null,T=()=>{if(!a?.[0]&&!a?.[1])return t();const c=a[1]||new Date,p=a[0]||new Date(c.getDate()-1e3*60*60*24);r(!1),t({type:"custom",fromDate:p.getTime(),toDate:c.getTime()})};return n.createElement(v,{onMouseDown:u,onTouchStart:u},n.createElement(E,{open:s,active:i,name:"Custom range",onOpen:()=>r(!0),onClose:()=>r(!1),renderSubmenu:()=>n.createElement(F,null,n.createElement(Y,{onClick:T},"Submit"),n.createElement(b,null),n.createElement(R,{isCalendarOpen:!0,format:"yyyy-MM-dd HH:mm",closeWidgets:!1,dayPlaceholder:"DD",monthPlaceholder:"MM",yearPlaceholder:"YYYY",hourPlaceholder:"HH",minutePlaceholder:"mm",disableClock:!0,value:[o,g],onChange:c=>m(c)}))}),y.map(c=>{const p=d?.type==="predefined"&&d.name===c.name;return n.createElement(f,{active:p,key:c.name,onClick:C=>{u(C),t(p?void 0:c)}},c.name)}))},E=e=>{const d=e.activeOptions||[],t=D(()=>new Set(d.map(i=>i.id)),[e.activeOptions]);return n.createElement(h,{open:e.open,onOpen:e.onOpen,onClose:e.onClose,trigger:n.createElement(f,{active:e.active||e.open},e.name),position:"left top",arrow:!1},e.options?n.createElement(v,{onMouseDown:u,onTouchStart:u},e.options?.map(i=>n.createElement(f,{active:t.has(i.id),key:i.id,onClick:s=>{if(e.onChange)if(u(s),t.has(i.id)){const r=[...d],a=r.findIndex(m=>m.id===i.id);r.splice(a,1),e.onChange(r)}else e.onChange([...d,i])}},i.name))):null,e.renderSubmenu?e.renderSubmenu():null)},u=e=>{e.stopPropagation()},k=l.div`
1
+ import n,{useMemo as D,useState as O}from"react";import{Popup as h}from"reactjs-popup";import l from"styled-components";import{useQuery as N}from"@tanstack/react-query";import{DateTimeRangePicker as R}from"@wojtekmaj/react-datetimerange-picker";import"@wojtekmaj/react-datetimerange-picker/dist/DateTimeRangePicker.css";import{fetch as S}from"../../../../../client/app/utils";import{PopupMenuUl as I}from"./PopupMenuUl";const A=[{name:"OTHER",id:"OTHER"},{name:"CONNECT",id:"CONNECT"},{name:"DELETE",id:"DELETE"},{name:"GET",id:"GET"},{name:"HEAD",id:"HEAD"},{name:"OPTIONS",id:"OPTIONS"},{name:"PATCH",id:"PATCH"},{name:"POST",id:"POST"},{name:"PUT",id:"PUT"},{name:"TRACE",id:"TRACE"}],y=[{type:"predefined",name:"last 5m",fromDateOffset:1e3*60*5},{type:"predefined",name:"last 1h",fromDateOffset:1e3*60*60},{type:"predefined",name:"last 3h",fromDateOffset:1e3*60*60*3},{type:"predefined",name:"last 12h",fromDateOffset:1e3*60*60*12},{type:"predefined",name:"last 1d",fromDateOffset:1e3*60*60*24},{type:"predefined",name:"last 3d",fromDateOffset:1e3*60*60*24*3},{type:"predefined",name:"last 7d",fromDateOffset:1e3*60*60*24*7},{type:"predefined",name:"last 30d",fromDateOffset:1e3*60*60*24*30}],P=[{name:"100 CONTINUE",id:"100"},{name:"101 SWITCHING PROTOCOLS",id:"101"},{name:"102 PROCESSING",id:"102"},{name:"200 OK",id:"200"},{name:"201 CREATED",id:"201"},{name:"202 ACCEPTED",id:"202"},{name:"203 NON AUTHORITATIVE INFORMATION",id:"203"},{name:"204 NO CONTENT",id:"204"},{name:"205 RESET CONTENT",id:"205"},{name:"206 PARTIAL CONTENT",id:"206"},{name:"207 MULTI STATUS",id:"207"},{name:"300 MULTIPLE CHOICES",id:"300"},{name:"301 MOVED PERMANENTLY",id:"301"},{name:"302 FOUND",id:"302"},{name:"303 SEE OTHER",id:"303"},{name:"304 NOT MODIFIED",id:"304"},{name:"305 USE PROXY",id:"305"},{name:"307 TEMPORARY REDIRECT",id:"307"},{name:"400 BAD REQUEST",id:"400"},{name:"401 UNAUTHORIZED",id:"401"},{name:"402 PAYMENT REQUIRED",id:"402"},{name:"403 FORBIDDEN",id:"403"},{name:"404 NOT FOUND",id:"404"},{name:"405 METHOD NOT ALLOWED",id:"405"},{name:"406 NOT ACCEPTABLE",id:"406"},{name:"407 PROXY AUTHENTICATION REQUIRED",id:"407"},{name:"408 REQUEST TIMEOUT",id:"408"},{name:"409 CONFLICT",id:"409"},{name:"410 GONE",id:"410"},{name:"411 LENGTH REQUIRED",id:"411"},{name:"412 PRECONDITION FAILED",id:"412"},{name:"413 REQUEST ENTITY TOO LARGE",id:"413"},{name:"414 REQUEST URI TOO LONG",id:"414"},{name:"415 UNSUPPORTED MEDIA TYPE",id:"415"},{name:"416 REQUESTED RANGE NOT SATISFIABLE",id:"416"},{name:"417 EXPECTATION FAILED",id:"417"},{name:"422 UNPROCESSABLE ENTITY",id:"422"},{name:"423 LOCKED",id:"423"},{name:"424 FAILED DEPENDENCY",id:"424"},{name:"429 TOO MANY REQUESTS",id:"429"},{name:"500 INTERNAL SERVER ERROR",id:"500"},{name:"501 NOT IMPLEMENTED",id:"501"},{name:"502 BAD GATEWAY",id:"502"},{name:"503 SERVICE UNAVAILABLE",id:"503"},{name:"504 GATEWAY TIMEOUT",id:"504"},{name:"505 HTTP VERSION NOT SUPPORTED",id:"505"},{name:"507 INSUFFICIENT STORAGE",id:"507"}];function x(e){return n.createElement(L,null,n.createElement(w,{onFiltersChange:e.onFiltersChange,activeFilters:e.activeFilters}),n.createElement(U,null))}var j=n.memo(x);const U=()=>null,w=n.memo(e=>{const{onFiltersChange:d,activeFilters:t}=e,{data:i}=N({queryKey:["API-PRODUCTS"],queryFn:()=>S("/api/api-keys/api-products").then(o=>o.json())}),[s,r]=O(),a=()=>r(void 0),m=(o,g)=>{const T={...t,[o]:g};d(T)};return n.createElement(h,{trigger:n.createElement(k,null,"Filter"),position:"bottom right"},n.createElement(b,null,n.createElement(E,{open:s==="api",name:"API name",options:i||[],activeOptions:t.api,onOpen:()=>r("api"),onClose:a,onChange:o=>m("api",o),active:(t.api?.length??0)>0}),n.createElement(E,{open:s==="status",name:"Status",options:P,activeOptions:t.status,onOpen:()=>r("status"),onClose:a,onChange:o=>m("status",o),active:(t.status?.length??0)>0}),n.createElement(E,{open:s==="method",name:"Method",options:A,activeOptions:t.method,onOpen:()=>r("method"),onClose:a,onChange:o=>m("method",o),active:(t.method?.length??0)>0}),n.createElement(E,{name:"Date range",open:s==="date",onOpen:()=>r("date"),onClose:a,active:!!t.date,renderSubmenu:()=>n.createElement(M,{onChange:o=>m("date",o),selectedDateFilter:t.date})}),n.createElement(_,null),n.createElement(H,{onClick:()=>d({})},"Clear filters")))}),M=e=>{const{selectedDateFilter:d,onChange:t}=e,i=d?.type==="custom",[s,r]=O(!1),[a,m]=O([null,null]),o=a?.[0]?a[0]:null,g=a?.[1]?a[1]:null,T=()=>{if(!a?.[0]&&!a?.[1])return t();const c=a[1]||new Date,p=a[0]||new Date(c.getDate()-1e3*60*60*24);r(!1),t({type:"custom",fromDate:p.getTime(),toDate:c.getTime()})};return n.createElement(v,{onMouseDown:u,onTouchStart:u},n.createElement(E,{open:s,active:i,name:"Custom range",onOpen:()=>r(!0),onClose:()=>r(!1),renderSubmenu:()=>n.createElement(F,null,n.createElement(Y,{onClick:T},"Submit"),n.createElement(_,null),n.createElement(R,{isCalendarOpen:!0,format:"yyyy-MM-dd HH:mm",closeWidgets:!1,dayPlaceholder:"DD",monthPlaceholder:"MM",yearPlaceholder:"YYYY",hourPlaceholder:"HH",minutePlaceholder:"mm",disableClock:!0,value:[o,g],onChange:c=>m(c)}))}),y.map(c=>{const p=d?.type==="predefined"&&d.name===c.name;return n.createElement(f,{active:p,key:c.name,onClick:C=>{u(C),t(p?void 0:c)}},c.name)}))},E=e=>{const d=e.activeOptions||[],t=D(()=>new Set(d.map(i=>i.id)),[e.activeOptions]);return n.createElement(h,{open:e.open,onOpen:e.onOpen,onClose:e.onClose,trigger:n.createElement(f,{active:e.active||e.open},e.name),position:"left top",arrow:!1},e.options?n.createElement(v,{onMouseDown:u,onTouchStart:u},e.options?.map(i=>n.createElement(f,{active:t.has(i.id),key:i.id,onClick:s=>{if(e.onChange)if(u(s),t.has(i.id)){const r=[...d],a=r.findIndex(m=>m.id===i.id);r.splice(a,1),e.onChange(r)}else e.onChange([...d,i])}},i.name))):null,e.renderSubmenu?e.renderSubmenu():null)},u=e=>{e.stopPropagation()},k=l.div`
2
2
  color: var(--text-color-primary);
3
3
  border-radius: var(--border-radius);
4
4
  cursor: pointer;
@@ -14,7 +14,7 @@ import n,{useMemo as D,useState as O}from"react";import{Popup as h}from"reactjs-
14
14
  `,L=l.div`
15
15
  display: flex;
16
16
  gap: var(--spacing-xxs);
17
- `,_=l(I)`
17
+ `,b=l(I)`
18
18
  padding: var(--spacing-xs);
19
19
  width: 288px;
20
20
  li {
@@ -32,7 +32,7 @@ import n,{useMemo as D,useState as O}from"react";import{Popup as h}from"reactjs-
32
32
  margin-bottom: 2px;
33
33
  }
34
34
  }
35
- `,v=l(_)`
35
+ `,v=l(b)`
36
36
  max-height: 200px;
37
37
  overflow-y: scroll;
38
38
  &::-webkit-scrollbar {
@@ -96,7 +96,7 @@ import n,{useMemo as D,useState as O}from"react";import{Popup as h}from"reactjs-
96
96
  }
97
97
 
98
98
  .react-calendar__tile--now {
99
- color: var(--color-primary-base);
99
+ color: var(--color-primary-base, var(--color-blueberry-6));
100
100
  }
101
101
 
102
102
  .react-datetimerange-picker__inputGroup__input:invalid {
@@ -146,7 +146,7 @@ import n,{useMemo as D,useState as O}from"react";import{Popup as h}from"reactjs-
146
146
  font-size: var(--font-size-lg);
147
147
  text-align: center;
148
148
  margin: 0 var(--spacing-xs);
149
- `,b=l.div`
149
+ `,_=l.div`
150
150
  margin: var(--spacing-xs);
151
151
  width: auto;
152
152
  min-width: auto;
@@ -28,7 +28,7 @@ import o,{css as t}from"styled-components";const a=o.div`
28
28
 
29
29
  &:hover,
30
30
  &:focus {
31
- border-color: var(--color-primary-base);
31
+ border-color: var(--color-primary-base, var(--color-blueberry-6));
32
32
  }
33
33
 
34
34
  &::placeholder {
@@ -1 +1 @@
1
- import i from"react";import c from"react-select";import{useTranslate as d}from"../../../../../client/app/hooks";const m=function(o){const{options:r,defaultValue:e,onChange:a}=o,{translate:l}=d();return i.createElement(c,{isMulti:!0,defaultValue:e,options:r,closeMenuOnSelect:!1,styles:p,placeholder:l("dev.select.placeholder","Empty"),onChange:t=>{a(t.map(n=>n.value))}})},p={control:o=>({...o,border:"1px solid var(--border-color-primary)",boxShadow:"none",backgroundColor:"var(--bg-color-raised)","&:hover":{borderColor:"var(--color-primary-base)",cursor:"pointer"}}),placeholder:o=>({...o,color:"var(--input-content-placeholder-color)",fontSize:"var(--font-size-lg)"}),indicatorsContainer:()=>({display:"none"}),menu:o=>({...o,padding:"var(--spacing-xxs)",margin:"0",boxShadow:"var(--bg-raised-shadow)",border:"1px solid var(--border-color-primary)",backgroundColor:"var(--bg-color)"}),menuList:o=>({...o,paddingBottom:0,paddingTop:0}),option:o=>({...o,cursor:"pointer",borderRadius:"4px",color:"var(--text-color-primary)",backgroundColor:"transparent",fontSize:"14px","&:hover":{backgroundColor:"var(--bg-color-hover)"}}),multiValue:o=>({...o,backgroundColor:"var(--bg-color-raised)",color:"var(--text-color-primary)",border:"1px solid var(--border-color-primary)",borderRadius:"32px",height:"32px",alignItems:"center"}),multiValueLabel:o=>({...o,fontSize:"14px",color:"var(--text-color-primary)",paddingLeft:"var(--spacing-sm)"}),valueContainer:o=>({...o,padding:"6px 8px"}),multiValueRemove:o=>({...o,padding:0,margin:"0 var(--spacing-xxs)","&:hover":{backgroundColor:"var(--bg-color-raised)",color:"var(--text-color-secondary)"}})};export{m as MultiSelect};
1
+ import i from"react";import c from"react-select";import{useTranslate as d}from"../../../../../client/app/hooks";const v=function(r){const{options:o,defaultValue:e,onChange:a}=r,{translate:l}=d();return i.createElement(c,{isMulti:!0,defaultValue:e,options:o,closeMenuOnSelect:!1,styles:p,placeholder:l("dev.select.placeholder","Empty"),onChange:t=>{a(t.map(n=>n.value))}})},p={control:r=>({...r,border:"1px solid var(--border-color-primary)",boxShadow:"none",backgroundColor:"var(--bg-color-raised)","&:hover":{borderColor:"var(--color-primary-base, var(--color-blueberry-6))",cursor:"pointer"}}),placeholder:r=>({...r,color:"var(--input-content-placeholder-color)",fontSize:"var(--font-size-lg)"}),indicatorsContainer:()=>({display:"none"}),menu:r=>({...r,padding:"var(--spacing-xxs)",margin:"0",boxShadow:"var(--bg-raised-shadow)",border:"1px solid var(--border-color-primary)",backgroundColor:"var(--bg-color)"}),menuList:r=>({...r,paddingBottom:0,paddingTop:0}),option:r=>({...r,cursor:"pointer",borderRadius:"4px",color:"var(--text-color-primary)",backgroundColor:"transparent",fontSize:"14px","&:hover":{backgroundColor:"var(--bg-color-hover)"}}),multiValue:r=>({...r,backgroundColor:"var(--bg-color-raised)",color:"var(--text-color-primary)",border:"1px solid var(--border-color-primary)",borderRadius:"32px",height:"32px",alignItems:"center"}),multiValueLabel:r=>({...r,fontSize:"14px",color:"var(--text-color-primary)",paddingLeft:"var(--spacing-sm)"}),valueContainer:r=>({...r,padding:"6px 8px"}),multiValueRemove:r=>({...r,padding:0,margin:"0 var(--spacing-xxs)","&:hover":{backgroundColor:"var(--bg-color-raised)",color:"var(--text-color-secondary)"}})};export{v as MultiSelect};
@@ -1,13 +1,13 @@
1
- import*as r from"react";import t from"styled-components";function i(e){return r.createElement(l,null,e.label?r.createElement("span",null,e.label):null,r.createElement(o,{...e.inputProps}))}const o=t.input`
1
+ import*as e from"react";import o from"styled-components";function i(r){return e.createElement(t,null,r.label?e.createElement("span",null,r.label):null,e.createElement(l,{...r.inputProps}))}const l=o.input`
2
2
  border: 1px solid var(--border-color-primary);
3
3
  padding: var(--spacing-sm);
4
4
  border-radius: var(--border-radius);
5
5
  width: 100%;
6
6
  height: 48px;
7
7
  display: block;
8
- outline-color: var(--color-primary-base);
8
+ outline-color: var(--color-primary-base, var(--color-blueberry-6));
9
9
  transition: outline 0.25s ease;
10
- `,l=t.label`
10
+ `,t=o.label`
11
11
  color: var(--text-color-primary);
12
12
  span {
13
13
  font-size: 0.9em;
@@ -1 +1 @@
1
- import{envConfig as o}from"../../config/env-config.js";async function i(r){return{id:"enforce-login",async processContent(n){if(o.REDOCLY_ENFORCE_LOGIN!=="true")return;const e=n.getConfig();n.setGlobalConfig({access:{...e.access,requiresLogin:!0,rbac:{}}})}}}export{i as enforceLoginPlugin};
1
+ import{envConfig as r}from"../../config/env-config.js";async function f(c){return{id:"enforce-login",async processContent(o){const i=!!r.REDOCLY_ENFORCE_RESIDENCY,n=r.REDOCLY_ENFORCE_LOGIN==="true";if(!i&&!n)return;const e=o.getConfig();o.setGlobalConfig({...n&&"rbac"in e&&{rbac:void 0},...n&&"requiresLogin"in e&&{requiresLogin:void 0},...i&&"residency"in e&&{residency:void 0},access:{...e.access,...i&&{residency:r.REDOCLY_ENFORCE_RESIDENCY},...n&&{requiresLogin:!0,rbac:void 0}}})}}}export{f as enforceLoginPlugin};
@@ -1,2 +1,2 @@
1
- import x from"@redocly/portal-plugin-mock-server";import B from"path";import{REDOCLY_ROUTE_RBAC as O}from"@redocly/config";import{combineUrls as v,withPathPrefix as N}from"@redocly/theme/core/utils";import{VERSION_SEPARATOR as L}from"../constants/common.js";import{removeTrailingSlash as F}from"../../utils/url/remove-trailing-slash.js";import{removeLeadingSlash as V}from"../../utils/url/remove-leading-slash.js";import{isTruthy as j}from"../../utils/guards/is-truthy.js";import{normalizeRouteSlug as T}from"../../utils/path/normalize-route-slug.js";import{slash as k}from"../../utils/path/slash.js";import{parsePathVersions as $}from"../../utils/path/parse-path-versions.js";import{reporter as E}from"../tools/notifiers/reporter.js";import{logger as P}from"../tools/notifiers/logger.js";import{envConfig as A}from"../config/env-config.js";import{shaDirPathShort as z}from"../utils/crypto/sha-dir-path-short.js";import{customPagesPlugin as M}from"../../server/plugins/pages/index.js";import{openAPIDocsPlugin as q}from"../../server/plugins/openapi-docs/index.js";import{asyncAPIDocsPlugin as I}from"../../server/plugins/asyncapi-docs/index.js";import{configParserPlugin as U}from"./config-parser/index.js";import{markdownPlugin as G}from"./markdown/index.js";import{generateBrowserPluginsModule as W,generateClientRoutes as K,generateTemplatesModule as H}from"../esbuild/generate.js";import{graphqlDocsPlugin as Y}from"./graphql-docs/index.js";import{searchPlugin as J}from"./search/index.js";import{defaultThemePlugin as Q}from"./default-theme/index.js";import{apiKeyMgmtPlugin as X}from"./dev-onboarding/index.js";import{apiFunctionsPlugin as Z}from"./api-functions/index.js";import{scorecardClassicPlugin as ee}from"./scorecard-classic/index.js";import{lintPlugin as te}from"./lint/index.js";import{resolveExternalPlugins as oe}from"../external-plugins/resolve-external-plugins.js";import{sidebarsPlugin as ie}from"./sidebars/index.js";import{l10nPlugin as ne}from"./l10n/index.js";import{analyticsPlugins as re}from"./analytics/index.js";import{sitemapPlugin as se}from"./sitemap/index.js";import{entitlementsPlugin as ae}from"./entitlements/index.js";import{getBilledPagesCount as le,slug as ce}from"../utils/index.js";import{telemetry as ue}from"../../cli/telemetry/index.js";import{telemetryTraceStep as b}from"../../cli/telemetry/helpers/trace-step.js";import{EntitlementsProvider as D}from"../entitlements/entitlements-provider.js";import{enforceLoginPlugin as fe}from"./enforce-login/index.js";import{ssoPlugin as me}from"./sso/index.js";import{Cache as de}from"../fs/cache.js";import{ContentFs as ge}from"../fs/content-fs.js";import{findProductBySlug as pe}from"../utils/product.js";import{parseBaseName as Pe}from"./utils.js";import{isRouteReserved as he}from"./get-reserved-routes.js";import{catalogClassicPlugin as ye}from"./catalog-classic/index.js";import{arazzoDocsPlugin as Ce}from"./arazzo-docs/index.js";const we=[U,fe,me,Q,ne,G,q,I,Ce,ee,te,Z,M,Y,X,ye,{importPath:"./catalog-entities/plugin.js",loadCondition:()=>A.NEW_CATALOG_ENABLED==="true"},{importPath:"./scorecards/plugin.js",loadCondition:()=>A.NEW_SCORECARDS_ENABLED==="true"},{importPath:"./mcp/index.js",loadCondition:()=>D.instance().canAccessFeature("mcp")},ie,se,ae,J,x,...re];async function ht(o,t=we){return await b("build.plugins_init",async()=>{const n=[],w=D.instance(),h={};for(const f of t){let a;if("loadCondition"in f){if(!f.loadCondition())continue;const e=await import(f.importPath);if(!e.default||typeof e.default!="function"){await E.panicOnBuild(`Dynamic plugin ${f.importPath} does not export a default export or it is not a function`);continue}a=e.default}else a=f;const d=await a(o);for(const[e,i]of Object.entries(d.loaders||{}))h[e]&&await E.panicOnBuild(`Duplicate loader with name ${e}`),h[e]=i;(!d.requiredEntitlements||d.requiredEntitlements?.every(e=>w.canAccessFeature(e)))&&n.push(d)}const s=new ge(o.contentDir);await s.ready;const u=new de(s);return u.setLoaders(h),P.verbose("All plugins instantiated"),{pluginInstances:n,lifecycleContext:Ee(s,u)}})}function _(o){P.verbose("Generating templates"),b("build.write_client_entries",()=>{H(o),W(o),K(o)})}async function Re(o){const t=o.getAllRoutes();le(t)||await E.panicOnBuild("No routes created by plugins. Please check your project configuration.")}async function yt(o,t,n,w={}){const h=D.instance();try{await b("build.plugins_run",async()=>{t.startPluginsRun();let s=[];await b("build.plugins_process_content",async a=>{for(const e of o){const i=P.startTiming();await e.processContent?.(t,n),P.verboseTime(i,`processContent for ${e.id}`)}s=(await oe(t.contentDir,t.config.plugins)).map(e=>e.lifecyclePlugin).filter(e=>j(e)&&(!e.requiredEntitlements||e.requiredEntitlements?.every(i=>h.canAccessFeature(i)))),n.cache.setLoaders(Object.fromEntries(s.flatMap(e=>Object.entries(e.loaders||{}))));for(const e of s){const i=P.startTiming();await e.processContent?.(t,n),P.verboseTime(i,`processContent for ${e.id}`)}a?.setAttribute("externalPluginsProcessed",s.length.toString())});const u=await ve(t,n),f=[...o,...s];_(t),A.isDevelopMode?await t.userCodeReady:t.buildRevision++,await b("build.plugins_after_routes_created",async()=>{for(const a of f){const d=P.startTiming();await a.afterRoutesCreated?.(t,u),P.verboseTime(d,`afterRoutesCreated for ${a.id}`)}}),await t.reportUnsetEnvVars(),await Re(t),_(t)})}catch(s){const u="Unhandled error in plugin. "+s.message+`
2
- `+s.stack;ue.sendCliErrorCaughtMessage({message:u}),w.failFast?await E.panic(u):await E.panicOnBuild(u)}finally{t.finishPluginsRun()}}async function ve(o,t){const{cache:n,fs:w}=t,h=await t.getConfig(),s=Object.values(h.products||{}),u=(await n.load("versions-config","versions-config")).data,f=(await n.load("content-slugs","content-slugs")).data;for(const{duplicateInAllLocales:e,slugSuffix:i,sharedData:y=[],redirectFrom:C=[],...l}of o.newRoutes){const c=T(l.slug?l.slug:a(l.fsPath)),g=F(i?v(c,i):c),r={...l,[O]:{slug:g,fsPath:l.fsPath},slug:g,baseSlug:c,versions:d(l.fsPath,i),product:pe(s,g,a)};he(g,h)&&await E.panicOnBuildContentError(`Route "${g}" is reserved and cannot be used. Please choose a different slug for "${l.fsPath}".`),o.routesByFsPath.set(r.fsPath,r.slug),o.routesBySlug.set(r.slug,r);for(const{key:p,id:m}of y)o.addRouteSharedData(r.slug,p,m);for(const p of C)o.addRedirect(p.from,{type:p.type,to:r.slug});if(e)for(const p of w.localeFolders){const m={...r,slug:"/"+p.toLowerCase()+r.slug};o.routesByFsPath.set(m.fsPath,m.slug),o.routesBySlug.set(m.slug,m);for(const{key:R,id:S}of y)o.addRouteSharedData(m.slug,R,S);for(const R of C){const S=v(w.localizationFolder,p,R.from);o.addRedirect(S,{type:R.type,to:m.slug})}}}return o.newRoutes=[],{...t,slugify:a};function a(e){const i=k(e).replace(new RegExp("^(@i18n|@l10n)\\/"),""),y=f.fileSlugs.get(i)||f.dirSlugs.get(F(i));if(y)return y;const{baseName:C,isIndexFile:l}=Pe(e);let c=B.dirname(e.replace(new RegExp("^(@i18n|@l10n)\\/"),""));return c=c==="."?"/":c,v("/",ce(l?c:v(c,C)),"/")}function d(e,i=""){const y=$(e);if(!y?.versionName)return;const{versionFolderPath:C,filePathInVersion:l,versionName:c}=y,g=u.get(C);if(g)return g.versions.map(r=>{const p=g.defaultVersion===r.version,m=V(v(C,L+r.version,l)),R=a(m);return{version:r.version,label:r.name||r.version,link:T(v(R,i)),default:p,active:c===r.version,folderId:z(`${C}`)}})}}function Ee(o,t){return{fs:o,cache:t,getConfig:async(n=".")=>(await t.load(n,"nearest-redocly-config",o.localeFolders)).data,isPathIgnored:async n=>(await t.load(n,"is-ignored")).data,withPathPrefix:N,logger:P}}export{we as INTERNAL_PLUGINS,Ee as createLifecycleContext,ht as initPlugins,yt as runPlugins,_ as writeClientEntries};
1
+ import x from"@redocly/portal-plugin-mock-server";import B from"path";import{REDOCLY_ROUTE_RBAC as O}from"@redocly/config";import{combineUrls as v,withPathPrefix as N}from"@redocly/theme/core/utils";import{VERSION_SEPARATOR as L}from"../constants/common.js";import{removeTrailingSlash as F}from"../../utils/url/remove-trailing-slash.js";import{removeLeadingSlash as k}from"../../utils/url/remove-leading-slash.js";import{isTruthy as V}from"../../utils/guards/is-truthy.js";import{normalizeRouteSlug as T}from"../../utils/path/normalize-route-slug.js";import{slash as j}from"../../utils/path/slash.js";import{parsePathVersions as $}from"../../utils/path/parse-path-versions.js";import{reporter as E}from"../tools/notifiers/reporter.js";import{logger as P}from"../tools/notifiers/logger.js";import{envConfig as A}from"../config/env-config.js";import{shaDirPathShort as z}from"../utils/crypto/sha-dir-path-short.js";import{customPagesPlugin as M}from"../../server/plugins/pages/index.js";import{openAPIDocsPlugin as q}from"../../server/plugins/openapi-docs/index.js";import{asyncAPIDocsPlugin as I}from"../../server/plugins/asyncapi-docs/index.js";import{configParserPlugin as U}from"./config-parser/index.js";import{markdownPlugin as G}from"./markdown/index.js";import{generateBrowserPluginsModule as W,generateClientRoutes as K,generateTemplatesModule as H}from"../esbuild/generate.js";import{graphqlDocsPlugin as Y}from"./graphql-docs/index.js";import{searchPlugin as J}from"./search/index.js";import{defaultThemePlugin as Q}from"./default-theme/index.js";import{apiKeyMgmtPlugin as X}from"./dev-onboarding/index.js";import{apiFunctionsPlugin as Z}from"./api-functions/index.js";import{scorecardClassicPlugin as ee}from"./scorecard-classic/index.js";import{lintPlugin as te}from"./lint/index.js";import{resolveExternalPlugins as oe}from"../external-plugins/resolve-external-plugins.js";import{sidebarsPlugin as ie}from"./sidebars/index.js";import{l10nPlugin as ne}from"./l10n/index.js";import{validateRedirects as re}from"../utils/redirects/validate-redirects.js";import{analyticsPlugins as se}from"./analytics/index.js";import{sitemapPlugin as ae}from"./sitemap/index.js";import{entitlementsPlugin as le}from"./entitlements/index.js";import{getBilledPagesCount as ce,slug as ue}from"../utils/index.js";import{telemetry as fe}from"../../cli/telemetry/index.js";import{telemetryTraceStep as b}from"../../cli/telemetry/helpers/trace-step.js";import{EntitlementsProvider as D}from"../entitlements/entitlements-provider.js";import{enforceLoginPlugin as me}from"./enforce-login/index.js";import{ssoPlugin as de}from"./sso/index.js";import{Cache as ge}from"../fs/cache.js";import{ContentFs as pe}from"../fs/content-fs.js";import{findProductBySlug as Pe}from"../utils/product.js";import{parseBaseName as he}from"./utils.js";import{isRouteReserved as ye}from"./get-reserved-routes.js";import{catalogClassicPlugin as Ce}from"./catalog-classic/index.js";import{arazzoDocsPlugin as we}from"./arazzo-docs/index.js";const Re=[U,me,de,Q,ne,G,q,I,we,ee,te,Z,M,Y,X,Ce,{importPath:"./catalog-entities/plugin.js",loadCondition:()=>A.NEW_CATALOG_ENABLED==="true"},{importPath:"./scorecards/plugin.js",loadCondition:()=>A.NEW_SCORECARDS_ENABLED==="true"},{importPath:"./mcp/index.js",loadCondition:()=>D.instance().canAccessFeature("mcp")},ie,ae,le,J,x,...se];async function Ct(o,t=Re){return await b("build.plugins_init",async()=>{const n=[],w=D.instance(),h={};for(const f of t){let a;if("loadCondition"in f){if(!f.loadCondition())continue;const e=await import(f.importPath);if(!e.default||typeof e.default!="function"){await E.panicOnBuild(`Dynamic plugin ${f.importPath} does not export a default export or it is not a function`);continue}a=e.default}else a=f;const d=await a(o);for(const[e,i]of Object.entries(d.loaders||{}))h[e]&&await E.panicOnBuild(`Duplicate loader with name ${e}`),h[e]=i;(!d.requiredEntitlements||d.requiredEntitlements?.every(e=>w.canAccessFeature(e)))&&n.push(d)}const s=new pe(o.contentDir);await s.ready;const u=new ge(s);return u.setLoaders(h),P.verbose("All plugins instantiated"),{pluginInstances:n,lifecycleContext:be(s,u)}})}function _(o){P.verbose("Generating templates"),b("build.write_client_entries",()=>{H(o),W(o),K(o)})}async function ve(o){const t=o.getAllRoutes();ce(t)||await E.panicOnBuild("No routes created by plugins. Please check your project configuration.")}async function wt(o,t,n,w={}){const h=D.instance();try{await b("build.plugins_run",async()=>{t.startPluginsRun();let s=[];await b("build.plugins_process_content",async a=>{for(const e of o){const i=P.startTiming();await e.processContent?.(t,n),P.verboseTime(i,`processContent for ${e.id}`)}s=(await oe(t.contentDir,t.config.plugins)).map(e=>e.lifecyclePlugin).filter(e=>V(e)&&(!e.requiredEntitlements||e.requiredEntitlements?.every(i=>h.canAccessFeature(i)))),n.cache.setLoaders(Object.fromEntries(s.flatMap(e=>Object.entries(e.loaders||{}))));for(const e of s){const i=P.startTiming();await e.processContent?.(t,n),P.verboseTime(i,`processContent for ${e.id}`)}a?.setAttribute("externalPluginsProcessed",s.length.toString())});const u=await Ee(t,n),f=[...o,...s];_(t),A.isDevelopMode?await t.userCodeReady:t.buildRevision++,await b("build.plugins_after_routes_created",async()=>{for(const a of f){const d=P.startTiming();await a.afterRoutesCreated?.(t,u),P.verboseTime(d,`afterRoutesCreated for ${a.id}`)}}),re(t),await t.reportUnsetEnvVars(),await ve(t),_(t)})}catch(s){const u="Unhandled error in plugin. "+s.message+`
2
+ `+s.stack;fe.sendCliErrorCaughtMessage({message:u}),w.failFast?await E.panic(u):await E.panicOnBuild(u)}finally{t.finishPluginsRun()}}async function Ee(o,t){const{cache:n,fs:w}=t,h=await t.getConfig(),s=Object.values(h.products||{}),u=(await n.load("versions-config","versions-config")).data,f=(await n.load("content-slugs","content-slugs")).data;for(const{duplicateInAllLocales:e,slugSuffix:i,sharedData:y=[],redirectFrom:C=[],...l}of o.newRoutes){const c=T(l.slug?l.slug:a(l.fsPath)),g=F(i?v(c,i):c),r={...l,[O]:{slug:g,fsPath:l.fsPath},slug:g,baseSlug:c,versions:d(l.fsPath,i),product:Pe(s,g,a)};ye(g,h)&&await E.panicOnBuildContentError(`Route "${g}" is reserved and cannot be used. Please choose a different slug for "${l.fsPath}".`),o.routesByFsPath.set(r.fsPath,r.slug),o.routesBySlug.set(r.slug,r);for(const{key:p,id:m}of y)o.addRouteSharedData(r.slug,p,m);for(const p of C)o.addRedirect(p.from,{type:p.type,to:r.slug});if(e)for(const p of w.localeFolders){const m={...r,slug:"/"+p.toLowerCase()+r.slug};o.routesByFsPath.set(m.fsPath,m.slug),o.routesBySlug.set(m.slug,m);for(const{key:R,id:S}of y)o.addRouteSharedData(m.slug,R,S);for(const R of C){const S=v(w.localizationFolder,p,R.from);o.addRedirect(S,{type:R.type,to:m.slug},{trackOriginalSource:!1})}}}return o.newRoutes=[],{...t,slugify:a};function a(e){const i=j(e).replace(new RegExp("^(@i18n|@l10n)\\/"),""),y=f.fileSlugs.get(i)||f.dirSlugs.get(F(i));if(y)return y;const{baseName:C,isIndexFile:l}=he(e);let c=B.dirname(e.replace(new RegExp("^(@i18n|@l10n)\\/"),""));return c=c==="."?"/":c,v("/",ue(l?c:v(c,C)),"/")}function d(e,i=""){const y=$(e);if(!y?.versionName)return;const{versionFolderPath:C,filePathInVersion:l,versionName:c}=y,g=u.get(C);if(g)return g.versions.map(r=>{const p=g.defaultVersion===r.version,m=k(v(C,L+r.version,l)),R=a(m);return{version:r.version,label:r.name||r.version,link:T(v(R,i)),default:p,active:c===r.version,folderId:z(`${C}`)}})}}function be(o,t){return{fs:o,cache:t,getConfig:async(n=".")=>(await t.load(n,"nearest-redocly-config",o.localeFolders)).data,isPathIgnored:async n=>(await t.load(n,"is-ignored")).data,withPathPrefix:N,logger:P}}export{Re as INTERNAL_PLUGINS,be as createLifecycleContext,Ct as initPlugins,wt as runPlugins,_ as writeClientEntries};
@@ -1 +1 @@
1
- import{resolveOpenApiRef as e}from"./resolve-open-api-ref.js";import{resolveJsonSchemaRef as o}from"./resolve-json-schema-ref.js";import{resolveParsedYaml as r}from"./resolve-parsed-yaml.js";import{resolveRawContent as m}from"./resolve-raw-content.js";import{resolveSvgContent as t}from"./resolve-svg-content.js";import{resolveRelativePath as i}from"./resolve-relative-path.js";import{resolveLink as l}from"./resolve-link.js";import{resolveNativeMdLink as s}from"./resolve-native-md-link.js";import{resolveCodeSnippetFromFile as a}from"./resolve-code-snippet-from-file.js";import{resolveHtmlSourceAttribute as p}from"./resolve-html-source-attribute.js";import{resolveHtmlHref as n}from"./resolve-html-href.js";import{resolveImageSrc as v}from"./resolve-image-src.js";import{resolveImageSrcSet as f}from"./resolve-image-src-set.js";import{resolveNavLinks as S}from"./resolve-nav-links.js";import{resolveRelativeOrCdnIcon as c}from"./resolve-relative-or-cdn-icon.js";import{resolveCodeWalkthroughFilesets as h}from"./code-walkthrough/filesets-resolver.js";import{resolveJsonExampleRef as d}from"./resolve-json-example-ref.js";import{resolveSampleFromJsonSchema as R}from"./resolve-sample-from-json-schema.js";const N={openapiRef:e,jsonSchemaRef:o,parsedYaml:r,rawContent:m,svgContent:t,relativePath:i,link:l,nativeMdLink:s,codeSnippetFile:a,htmlSourceAttribute:p,htmlHref:n,imageSrc:v,imageSrcSet:f,navLinks:S,relativeOrCdnIcon:c,codeWalkthroughFilesets:h,jsonExampleRef:d,sampleFromJsonSchema:R};export{N as attributeResolvers};
1
+ import{resolveOpenApiRef as e}from"./resolve-open-api-ref.js";import{resolveJsonSchemaRef as o}from"./resolve-json-schema-ref.js";import{resolveParsedYaml as r}from"./resolve-parsed-yaml.js";import{resolveRawContent as m}from"./resolve-raw-content.js";import{resolveSvgContent as t}from"./resolve-svg-content.js";import{resolveRelativePath as i}from"./resolve-relative-path.js";import{resolveLink as l}from"./resolve-link.js";import{resolveNativeMdLink as s}from"./resolve-native-md-link.js";import{resolveCodeSnippetFromFile as a}from"./resolve-code-snippet-from-file.js";import{resolveDiagramFromFile as p}from"./resolve-diagram-from-file.js";import{resolveHtmlSourceAttribute as n}from"./resolve-html-source-attribute.js";import{resolveHtmlHref as v}from"./resolve-html-href.js";import{resolveImageSrc as f}from"./resolve-image-src.js";import{resolveImageSrcSet as S}from"./resolve-image-src-set.js";import{resolveNavLinks as c}from"./resolve-nav-links.js";import{resolveRelativeOrCdnIcon as h}from"./resolve-relative-or-cdn-icon.js";import{resolveCodeWalkthroughFilesets as d}from"./code-walkthrough/filesets-resolver.js";import{resolveJsonExampleRef as g}from"./resolve-json-example-ref.js";import{resolveSampleFromJsonSchema as F}from"./resolve-sample-from-json-schema.js";const Y={openapiRef:e,jsonSchemaRef:o,parsedYaml:r,rawContent:m,svgContent:t,relativePath:i,link:l,nativeMdLink:s,codeSnippetFile:a,diagramFile:p,htmlSourceAttribute:n,htmlHref:v,imageSrc:f,imageSrcSet:S,navLinks:c,relativeOrCdnIcon:h,codeWalkthroughFilesets:d,jsonExampleRef:g,sampleFromJsonSchema:F};export{Y as attributeResolvers};
@@ -0,0 +1,4 @@
1
+ import type { Node } from '@markdoc/markdoc';
2
+ import type { MarkdocResolveContext, WithOriginalAttr } from '../../../types';
3
+ export declare function resolveDiagramFromFile(node: WithOriginalAttr<Node>, attributeName: string, pageRelativePath: string, { actions: { contentDir }, context }: MarkdocResolveContext): Promise<void>;
4
+ //# sourceMappingURL=resolve-diagram-from-file.d.ts.map
@@ -0,0 +1 @@
1
+ import a from"node:path";import{slash as f}from"../../../../utils/path/slash.js";import{reporter as l}from"../../../tools/notifiers/reporter.js";import{getNodeAttribute as p}from"../../../../markdoc/helpers/get-node-attribute.js";async function h(t,s,m,{actions:{contentDir:e},context:o}){const r=p(t,s);if(!r)return;const i=r.startsWith("/")?r.slice(1):f(a.relative(e,a.resolve(e,a.dirname(m),r)));if(!o.fs.exists(i)){await l.panicOnBuildContentError(`Diagram file ${i} does not exist`);return}const n=await o.fs.read(i);t.children=[],t.attributes.rawContent=n}export{h as resolveDiagramFromFile};
@@ -1 +1 @@
1
- import{getPathPrefix as s,withPathPrefix as n}from"@redocly/theme/core/utils";import{isLocalLink as m}from"../../../../utils/path/is-local-link.js";import{getNodeAttribute as a}from"../../../../markdoc/helpers/get-node-attribute.js";import{setNodeAttributeValue as p}from"../../../../markdoc/helpers/set-node-attribute-value.js";import{resolveLink as h}from"./resolve-link.js";async function x(r,i,e,f){await h(r,i,e,f);const o=s();if(!o)return;const t=a(r,i);!t||t==="#"||!m(t)||t.startsWith(o)||p(r,i,t.startsWith("#")?t:n(t))}export{x as resolveNativeMdLink};
1
+ import{getPathPrefix as s,withPathPrefix as n}from"@redocly/theme/core/utils";import{isLocalLink as m}from"../../../../utils/path/is-local-link.js";import{getNodeAttribute as p}from"../../../../markdoc/helpers/get-node-attribute.js";import{setNodeAttributeValue as a}from"../../../../markdoc/helpers/set-node-attribute-value.js";import{resolveLink as l}from"./resolve-link.js";async function v(r,i,o,f){if(await l(r,i,o,f),r.type==="link")return;const e=s();if(!e)return;const t=p(r,i);!t||t==="#"||!m(t)||t.startsWith(e)||a(r,i,t.startsWith("#")?t:n(t))}export{v as resolveNativeMdLink};
@@ -100,8 +100,8 @@ export declare function getMarkdocOptions(serverOutDir?: string, _templateId?: s
100
100
  description?: string;
101
101
  };
102
102
  link: {
103
+ render: string;
103
104
  children: string[];
104
- render?: string | undefined;
105
105
  attributes?: Record<string, import("@markdoc/markdoc").SchemaAttribute>;
106
106
  slots?: Record<string, import("@markdoc/markdoc").SchemaSlot>;
107
107
  selfClosing?: boolean;
@@ -0,0 +1,16 @@
1
+ export type DiagramInput = {
2
+ type: DiagramType;
3
+ source: string;
4
+ };
5
+ type DiagramType = 'mermaid' | 'excalidraw' | 'plantuml';
6
+ type DiagramHtmlVariants = {
7
+ light: string;
8
+ dark: string;
9
+ error?: string;
10
+ };
11
+ export declare const cache: Record<string, DiagramHtmlVariants>;
12
+ export declare function generateDiagramHash(source: string, type?: DiagramType): string;
13
+ export declare function renderDiagramsWithVariants(diagrams: DiagramInput[]): Promise<DiagramHtmlVariants[]>;
14
+ export declare function renderDiagrams(diagrams: DiagramInput[], theme?: string): Promise<string[]>;
15
+ export {};
16
+ //# sourceMappingURL=render-diagrams.d.ts.map
@@ -0,0 +1 @@
1
+ import{nanoid as w}from"nanoid";import{envConfig as l}from"../../../../config/env-config.js";import{logger as m}from"../../../../tools/notifiers/logger.js";import{sha as I}from"../../../../utils/crypto/sha.js";const u={};function g(r,n="mermaid"){const s=`${n}:${r}`;if(n==="mermaid"&&r.toLowerCase().includes("gantt")&&!r.toLowerCase().includes("todaymarker off")){const t=new Date().toISOString().split("T")[0];return I(s+t)}return I(s)}function y(){return l.REDOCLY_DIAGRAM_MICROSERVICE_URL||"https://tools.redocly.com/diagram-renders"}function R(r,n){return n==="dark"?r.dark??r.light??"":r.light??r.dark??""}async function D(r,n){const s=y(),a=m.startTiming(),e=w(),t=await fetch(s,{method:"POST",headers:{"Content-Type":"application/json","x-request-id":l.REQUEST_ID||""},body:JSON.stringify({type:r,definitions:n,rayId:e,theme:"both",organizationId:l.ORGANIZATION_ID})});if(t.status!==200)throw m.error("Diagram rendering service returned %s (rayId: %s)",t.status,e),new Error(`Something went wrong during rendering of ${r} diagrams`);return m.verboseTime(a,"Rendered %s diagrams (%s)",r,n.length),t.json()}async function T(r){if(r.length===0)return[];const n=new Map;for(let e=0;e<r.length;e++){const{type:t,source:i}=r[e],f=g(i,t);if(!u[f]){n.has(t)||n.set(t,[]);const o=n.get(t);o&&o.push({index:e,source:i})}}const s=[],a=new Map;for(const[e,t]of n){const i=t.map(o=>o.source),f=D(e,i).then(o=>{for(let c=0;c<t.length;c++){const d=o[c],h=g(t[c].source,e);if(d.error)m.error("Failed to render %s diagram: %s",e,d.error),a.set(h,{light:"",dark:"",error:`Failed to render ${e} diagram: ${d.error}`});else{const p={light:d.light??"",dark:d.dark??""};u[h]=p,a.set(h,p)}}}).catch(o=>{m.error("Failed to render %s diagrams: %s",e,o.message);for(const c of t){const d=g(c.source,e);a.set(d,{light:"",dark:"",error:`Failed to render ${e} diagram: ${o.message}`})}});s.push(f)}return await Promise.all(s),r.map(({type:e,source:t})=>{const i=g(t,e);return a.get(i)??u[i]})}async function M(r,n="light"){return(await T(r)).map(a=>R(a,n))}export{u as cache,g as generateDiagramHash,M as renderDiagrams,T as renderDiagramsWithVariants};
@@ -1 +1 @@
1
- import u from"@markdoc/markdoc";import{isTag as b}from"../../../markdoc/helpers/guards/is-tag.js";import{slugger as g}from"../../utils/index.js";import{getMarkdocOptions as l}from"./markdoc/markdoc-options.js";import{visit as h,getHeadingData as k}from"./markdoc/plugins/utils.js";import{renderMermaid as v}from"./markdoc/plugins/render-mermaid.js";import{deepStringify as M}from"./markdoc/utils/deep-stringify.js";import{stringifyTagChildrenObjects as w}from"./utils/stringify-tag-children-objects.js";async function _(d,e,p){const c=await l(p),t=[],a=[],i=M(e.variables?.pageProps),{headers:y,...f}=e.variables||{};g.reset();const s=u.transform(d,{...c,...e,variables:{...f,pageProps:i}});let o=0;h(s,r=>{if(b(r)){switch(r.name){case"Heading":r.attributes.__idx=o,o++;const n=k(r);n&&t.push(n);break;case"Mermaid":a.push({tag:r,source:r.attributes.diagramSource});break}w(r)}});const m=await v(a.map(r=>r.source));for(let r=0;r<m.length;r++)a[r].tag.attributes.diagramHtml=m[r];return{headings:t,renderableAst:s,pageProps:i}}export{_ as transformMdAst};
1
+ import u from"@markdoc/markdoc";import{isTag as b}from"../../../markdoc/helpers/guards/is-tag.js";import{slugger as l}from"../../utils/index.js";import{getMarkdocOptions as f}from"./markdoc/markdoc-options.js";import{visit as h,getHeadingData as k}from"./markdoc/plugins/utils.js";import{renderDiagramsWithVariants as v}from"./markdoc/plugins/render-diagrams.js";import{deepStringify as y}from"./markdoc/utils/deep-stringify.js";import{stringifyTagChildrenObjects as D}from"./utils/stringify-tag-children-objects.js";async function _(d,a,p){const g=await f(p),i=[],t=[],s=y(a.variables?.pageProps),{headers:H,...c}=a.variables||{};l.reset();const o=u.transform(d,{...g,...a,variables:{...c,pageProps:s}});let m=0;h(o,r=>{if(b(r)){switch(r.name){case"Heading":r.attributes.__idx=m,m++;const n=k(r);n&&i.push(n);break;case"Diagram":t.push({tag:r,input:{type:r.attributes.diagramType,source:r.attributes.diagramSource}});break}D(r)}});const e=await v(t.map(r=>r.input));for(let r=0;r<t.length;r++)t[r].tag.attributes.diagramError=e[r].error,t[r].tag.attributes.diagramHtml=e[r].light,t[r].tag.attributes.diagramHtmlDark=e[r].dark;return{headings:i,renderableAst:o,pageProps:s}}export{_ as transformMdAst};
@@ -1,21 +1,29 @@
1
- import{isPrimitive as w}from"../../../../utils/guards/is-primitive.js";import{getNodeAttribute as t}from"../../../../markdoc/helpers/get-node-attribute.js";import{getVariable as C}from"../../../../markdoc/helpers/get-variable.js";import{isTag as E}from"../../../../markdoc/helpers/guards/is-tag.js";import{isNode as N}from"../../../../markdoc/helpers/guards/is-node.js";import{isConditionalNode as v}from"../../../../markdoc/helpers/guards/is-conditional-node.js";import{isVariable as A}from"../../../../markdoc/helpers/guards/is-variable.js";import{isExampleNode as S}from"../../../../markdoc/helpers/guards/is-example-node.js";import{isFenceNode as x}from"../../../../markdoc/helpers/guards/is-fence-node.js";function a(s,r={}){const n=[];for(const e of s){if(w(e)){const i=r.isTrim?u(String(e)):String(e);i&&n.push(i)}else if(N(e))switch(e.type){case"text":n.push(a([t(e,"content")],r));break;case"code":n.push(`\`${a([t(e,"content")],r)}\``);break;case"blockquote":n.push(`> ${a(e.children,r)}
2
- `);break;case"fence":const i=t(e,"process")===!1;n.push(o(e,r,i));break;case"list":const h=t(e,"ordered")||!1,d=t(e,"marker"),f=e.children.map((c,l)=>`${" ".repeat((r?.indent??0)*2)}${h?l+1:""}${d} ${a([c],{...r??{},indent:(r?.indent??0)+1})}`);n.push(`${f.join("")}
3
- `);break;case"item":n.push(e.children.map(c=>`${a([c],r).trimEnd()}
4
- `).join(""));break;case"thead":const $=e.children.map(c=>a([c],r));n.push(`${$}| ${" --- |".repeat(e.children?.[0]?.children.length)}
5
- `);break;case"tr":const p=e.children.map(c=>a([c],r));n.push(`| ${p.join(" | ")} |
6
- `);break;case"em":n.push(`*${a(e.children,r)}*`);break;case"strong":n.push(`**${a(e.children,r)}**`);break;case"softbreak":case"hardbreak":n.push(`
7
- `);break;case"hr":n.push(`
1
+ import{isPrimitive as v}from"../../../../utils/guards/is-primitive.js";import{getNodeAttribute as c}from"../../../../markdoc/helpers/get-node-attribute.js";import{getVariable as T}from"../../../../markdoc/helpers/get-variable.js";import{isTag as C}from"../../../../markdoc/helpers/guards/is-tag.js";import{isNode as N}from"../../../../markdoc/helpers/guards/is-node.js";import{isConditionalNode as A}from"../../../../markdoc/helpers/guards/is-conditional-node.js";import{isVariable as E}from"../../../../markdoc/helpers/guards/is-variable.js";import{isExampleNode as w}from"../../../../markdoc/helpers/guards/is-example-node.js";import{isFenceNode as x}from"../../../../markdoc/helpers/guards/is-fence-node.js";function s(a,n={}){const r=[];for(const e of a){if(v(e)){const i=n.isTrim?d(String(e)):String(e);i&&r.push(i)}else if(N(e))switch(e.type){case"text":r.push(s([c(e,"content")],n));break;case"code":r.push(`\`${s([c(e,"content")],n)}\``);break;case"blockquote":r.push(`> ${s(e.children,n)}
2
+ `);break;case"fence":const i=c(e,"process")===!1;r.push(f(e,n,i));break;case"list":const l=c(e,"ordered")||!1,o=c(e,"marker"),u=e.children.map((t,h)=>`${" ".repeat((n?.indent??0)*2)}${l?h+1:""}${o} ${s([t],{...n??{},indent:(n?.indent??0)+1})}`);r.push(`${u.join("")}
3
+ `);break;case"item":r.push(e.children.map(t=>`${s([t],n).trimEnd()}
4
+ `).join(""));break;case"thead":const p=e.children.map(t=>s([t],n));r.push(`${p}| ${" --- |".repeat(e.children?.[0]?.children.length)}
5
+ `);break;case"tr":const $=e.children.map(t=>s([t],n));r.push(`| ${$.join(" | ")} |
6
+ `);break;case"em":r.push(`*${s(e.children,n)}*`);break;case"strong":r.push(`**${s(e.children,n)}**`);break;case"softbreak":case"hardbreak":r.push(`
7
+ `);break;case"hr":r.push(`
8
8
 
9
9
  ---
10
10
 
11
- `);break;case"heading":const k=t(e,"level")??0;n.push(`${"#".repeat(k)} ${a(e.children,r)}
12
- `);break;case"image":const b=t(e,"alt")||"",g=t(e,"src")||"";n.push(`![${b}](${g})`);break;case"link":const T=t(e,"href")||"";n.push(`[${a(e.children,r)}](${T})`);break;case"paragraph":case"table":n.push(`${a(e.children,r)}
13
- `);break;case"tag":if(v(e)&&r.skipConditionals)continue;if(S(e)){n.push(...e.children.map(c=>{if(x(c)){const l=t(c,"process")!==!0;return o(c,r,l)}return a([c],r)}));continue}if(e.tag==="code-snippet"){const c=t(e,"rawContent");if(c){const l=t(e,"language"),m=t(e,"title"),j=`
14
- \`\`\`${`${l||""}${m?`${l?" ":""}${m}`:""}`}
15
- ${c.trimEnd()}
11
+ `);break;case"heading":const k=c(e,"level")??0;r.push(`${"#".repeat(k)} ${s(e.children,n)}
12
+ `);break;case"image":const g=c(e,"alt")||"",b=c(e,"src")||"";r.push(`![${g}](${b})`);break;case"link":const j=c(e,"href")||"";r.push(`[${s(e.children,n)}](${j})`);break;case"paragraph":case"table":r.push(`${s(e.children,n)}
13
+ `);break;case"tag":if(A(e)&&n.skipConditionals)continue;if(w(e)){r.push(...e.children.map(t=>{if(x(t)){const h=c(t,"process")!==!0;return f(t,n,h)}return s([t],n)}));continue}if(e.tag==="code-snippet"){const t=c(e,"rawContent");if(t){const h=c(e,"language"),m=c(e,"title"),S=`
14
+ \`\`\`${`${h||""}${m?`${h?" ":""}${m}`:""}`}
15
+ ${t.trimEnd()}
16
16
  \`\`\`
17
- `;n.push(j)}continue}n.push(`${a(e.children,r)}`);break;default:n.push(a(e.children,r));break}else E(e)&&n.push(a(e.children,r));A(e)&&n.push(a([C(e,r.variables)],r))}return r.isTrim?u(n.map(e=>u(e)).join("")):n.join("")}function u(s){return s.replace(/^[ \t\r\f]+|[ \t\r\f]+$/g,"")}function o(s,r={},n=!1){const e=t(s,"title"),i=t(s,"language"),h=`${i||""}${e?`${i?" ":""}${e}`:""}`,d=n?(t(s,"content")||"").trimEnd():a(s.children,r).trimEnd();return`
18
- \`\`\`${h}
19
- ${d}
17
+ `;r.push(S)}continue}if(e.tag==="json-example"){const t=y(e);t&&r.push(t);continue}if(e.tag==="json-schema"){const t=B(e);t&&r.push(t);continue}r.push(`${s(e.children,n)}`);break;default:r.push(s(e.children,n));break}else C(e)&&r.push(s(e.children,n));E(e)&&r.push(s([T(e,n.variables)],n))}return n.isTrim?d(r.map(e=>d(e)).join("")):r.join("")}function d(a){return a.replace(/^[ \t\r\f]+|[ \t\r\f]+$/g,"")}function f(a,n={},r=!1){const e=c(a,"title"),i=c(a,"language"),l=`${i||""}${e?`${i?" ":""}${e}`:""}`,o=r?(c(a,"content")||"").trimEnd():s(a.children,n).trimEnd();return`
18
+ \`\`\`${l}
19
+ ${o}
20
20
  \`\`\`
21
- `}export{a as toMarkdown};
21
+ `}function y(a){const n=c(a,"json")??c(a,"valueResolved")??c(a,"schemaResolved"),r=c(a,"title");return n===null?null:`
22
+ \`\`\`${`json${r?` ${r}`:""}`}
23
+ ${JSON.stringify(n,null,2)}
24
+ \`\`\`
25
+ `}function B(a){const n=c(a,"schemaResolved");if(n===null)return null;const{components:r,openapi:e,...i}=n,{__root:l,...o}=r?.schemas||{},u=l?{...l,...Object.keys(o).length>0?{components:{schemas:o}}:{},...i}:n;return`
26
+ \`\`\`json
27
+ ${JSON.stringify(u,null,2)}
28
+ \`\`\`
29
+ `}export{s as toMarkdown};
@@ -1 +1 @@
1
- import{logger as a}from"../../../tools/notifiers/logger.js";import{isNode as f}from"../../../../markdoc/helpers/guards/is-node.js";import{isConditionalNode as u}from"../../../../markdoc/helpers/guards/is-conditional-node.js";import{isContentNode as y}from"../../../../markdoc/helpers/guards/is-content-node.js";import{getNodeAttribute as h}from"../../../../markdoc/helpers/get-node-attribute.js";import{extractRbacFromCondition as N}from"../../../../markdoc/helpers/extract-rbac-from-condition-node.js";import{TextNode as e}from"./nodes/text-node.js";import{TAG_TITLE_ATTRIBUTES as T,TagNode as n}from"./nodes/tag-node.js";import{HeadingNode as p}from"./nodes/heading-node.js";class C{#t;#o;#i;#s;constructor({ast:i,partials:t,skipConditionals:r=!1,getInnerContent:s}){if(this.#t=i,this.#o=t,this.#i=r,this.#s=s,!this.#t||!f(this.#t))throw new Error("ast is not a valid Markdoc Node.")}*transform(){yield*this.#c(this.#t,{parentNode:null})}*#c(i,t,r=this.#s){if(!(!i||!f(i))){if(u(i)){if(this.#i)return;const s=N(i);s&&s.length>0&&(yield*this.#r(i,{...t,rbacTeams:s},r));return}if(y(i)){yield new e({node:i,content:r([i],{skipConditionals:this.#i}),...t});return}if(i.type==="heading"){yield new p({node:i,content:r([i],{skipConditionals:this.#i}),rbacTeams:t?.rbacTeams});return}if(i.type==="tag"){yield*this.#l(i,t,r);return}yield*this.#r(i,t,r)}}*#l(i,t,r=this.#s){switch(i.tag){case"partial":{const s=i.attributes.file,o=i.attributes.variables??{};if(s&&this.#o[s]){yield*this.#c(this.#o[s],t,(c,l)=>r(c,{...l,variables:o}));return}a.warn(`Could not create search indexes for partial \u201C${s}\u201D: file not found`);return}case"cards":case"tabs":case"code-walkthrough":{yield*this.#r(i,t,r);return}case"markdoc-example":{const s=r([i],{skipConditionals:this.#i});yield new e({node:i,content:s,...t});return}case"code-snippet":{const s=h(i,"title"),o=r([i],{skipConditionals:this.#i});if(s){const c=new n({node:i,content:s,...t});t={...t,parentNode:c},yield c}o&&(yield new e({node:i,content:o,...t}));return}default:{const s=T.find(l=>l in i.attributes),o=(s&&h(i,s))??"",c=typeof o=="string"?o:r([o]);if(c){const l=new n({node:i,content:c,...t});t={...t,parentNode:l},yield l}yield*this.#r(i,t,r);return}}}*#r(i,t,r=this.#s){for(const s of[...Object.values(i.slots),...i.children])for(const o of this.#c(s,t,r))o instanceof p&&(t={...t,parentNode:o}),yield o}}export{C as AstToSearchNodeTransformer};
1
+ import{logger as u}from"../../../tools/notifiers/logger.js";import{isNode as f}from"../../../../markdoc/helpers/guards/is-node.js";import{isConditionalNode as y}from"../../../../markdoc/helpers/guards/is-conditional-node.js";import{isContentNode as N}from"../../../../markdoc/helpers/guards/is-content-node.js";import{getNodeAttribute as n}from"../../../../markdoc/helpers/get-node-attribute.js";import{extractRbacFromCondition as T}from"../../../../markdoc/helpers/extract-rbac-from-condition-node.js";import{TextNode as e}from"./nodes/text-node.js";import{TAG_TITLE_ATTRIBUTES as b,TagNode as p}from"./nodes/tag-node.js";import{HeadingNode as a}from"./nodes/heading-node.js";class j{#s;#o;#i;#t;constructor({ast:i,partials:s,skipConditionals:r=!1,getInnerContent:t}){if(this.#s=i,this.#o=s,this.#i=r,this.#t=t,!this.#s||!f(this.#s))throw new Error("ast is not a valid Markdoc Node.")}*transform(){yield*this.#l(this.#s,{parentNode:null})}*#l(i,s,r=this.#t){if(!(!i||!f(i))){if(y(i)){if(this.#i)return;const t=T(i);t&&t.length>0&&(yield*this.#r(i,{...s,rbacTeams:t},r));return}if(N(i)){yield new e({node:i,content:r([i],{skipConditionals:this.#i}),...s});return}if(i.type==="heading"){yield new a({node:i,content:r([i],{skipConditionals:this.#i}),rbacTeams:s?.rbacTeams});return}if(i.type==="tag"){yield*this.#c(i,s,r);return}yield*this.#r(i,s,r)}}*#c(i,s,r=this.#t){switch(i.tag){case"partial":{const t=i.attributes.file,o=i.attributes.variables??{};if(t&&this.#o[t]){yield*this.#l(this.#o[t],s,(l,h)=>r(l,{...h,variables:o}));return}u.warn(`Could not create search indexes for partial \u201C${t}\u201D: file not found`);return}case"cards":case"tabs":case"code-walkthrough":{yield*this.#r(i,s,r);return}case"markdoc-example":{const t=r([i],{skipConditionals:this.#i});yield new e({node:i,content:t,...s});return}case"code-snippet":{const t=n(i,"title"),o=r([i],{skipConditionals:this.#i});if(t){const l=new p({node:i,content:t,...s});s={...s,parentNode:l},yield l}o&&(yield new e({node:i,content:o,...s}));return}default:{const t=b.find(c=>c in i.attributes),o=(t&&n(i,t))??"",l=typeof o=="string"?o:r([o]);if(l){const c=new p({node:i,content:l,...s});s={...s,parentNode:c},yield c}if(i.children.length>0||Object.keys(i.slots).length>0)yield*this.#r(i,s,r);else{const c=r([i],{skipConditionals:this.#i});c&&(yield new e({node:i,content:c,...s}))}return}}}*#r(i,s,r=this.#t){for(const t of[...Object.values(i.slots),...i.children])for(const o of this.#l(t,s,r))o instanceof a&&(s={...s,parentNode:o}),yield o}}export{j as AstToSearchNodeTransformer};
@@ -0,0 +1,7 @@
1
+ import type { McpToolSchema } from '../../../types';
2
+ export declare function getDefaultToolSchemas(config: {
3
+ products?: string[];
4
+ requiresLogin: boolean;
5
+ rbac?: Record<string, unknown>;
6
+ }): McpToolSchema[];
7
+ //# sourceMappingURL=tool-schemas.d.ts.map
@@ -0,0 +1 @@
1
+ import{shouldHandleMcpAuth as n}from"../auth/auth-handlers.js";const i=["GET","POST","PUT","DELETE","PATCH","OPTIONS","HEAD","TRACE"];function s(e){const t=[{name:"list-apis",description:"Lists available APIs with their context and purpose",schema:{type:"object",additionalProperties:!1,required:[],properties:{filter:{type:"string",description:"API name (or part of it)",minLength:1,nullable:!0},page:{type:"number",description:"Page number",minimum:1,default:1,nullable:!0},limit:{type:"number",description:"Number of APIs per page. Default is 300",minimum:1,default:300,nullable:!0}}}},{name:"get-endpoints",description:"Get all endpoints for a specific API",schema:{type:"object",required:["name"],additionalProperties:!1,properties:{name:{type:"string",description:"API name",minLength:1}}}},{name:"get-endpoint-info",description:"Get comprehensive information about specific endpoint including parameters, security, and examples",schema:{type:"object",required:["name","path","method"],additionalProperties:!1,properties:{name:{type:"string",description:"API name",minLength:1},path:{type:"string",description:"Endpoint path (e.g. /api/v1/users)",minLength:1},method:{type:"string",description:"HTTP method (GET, POST, PUT, DELETE, etc.)",enum:[...i,...i.map(r=>r.toLowerCase())],minLength:1}}}},{name:"get-security-schemes",description:"Get the security schemes for a specific API",schema:{type:"object",required:["name"],additionalProperties:!1,properties:{name:{type:"string",description:"API name",minLength:1}}}},{name:"get-full-api-description",description:"Get the complete OpenAPI description",schema:{type:"object",required:["name"],additionalProperties:!1,properties:{name:{type:"string",description:"API name",minLength:1}}}},a(e.products)];return n(e.requiresLogin,e.rbac)&&t.push({name:"whoami",description:"Get information about the currently authenticated user",schema:{type:"object",required:[],additionalProperties:!1,properties:{}}}),t}function a(e){const t=e&&e.length>0;return{name:"search",description:"Search across the documentation to fetch relevant content for a given query",schema:{type:"object",required:["query"],additionalProperties:!1,properties:{query:{type:"string",description:"Search query. Should be a single word or that phrase that is presented in a documentation.",minLength:1},...t?{product:{type:"string",description:"Optional product name to filter search results by specific product.",enum:e,nullable:!0}}:{}}}}}export{s as getDefaultToolSchemas};
@@ -1,10 +1,6 @@
1
- import type { McpToolWorkerParams, McpToolWorkerResponse, ToolArgsMap } from '../../types.js';
2
- import { DocsMcpTool, type ContextKey } from './docs-mcp-tool.js';
3
- export declare class GetEndpointInfoTool extends DocsMcpTool<'get-endpoint-info'> {
4
- readonly name = "get-endpoint-info";
5
- readonly description = "Get comprehensive information about specific endpoint including parameters, security, and examples";
6
- readonly requiredContext: readonly ContextKey[];
7
- constructor();
8
- protected executeAction(args: ToolArgsMap['get-endpoint-info'], context: McpToolWorkerParams['context']): Promise<McpToolWorkerResponse>;
9
- }
1
+ import type { McpToolHandler } from '../../types.js';
2
+ declare const _default: {
3
+ 'get-endpoint-info': McpToolHandler;
4
+ };
5
+ export default _default;
10
6
  //# sourceMappingURL=get-endpoint-info.d.ts.map
@@ -1 +1 @@
1
- import{resolveParameters as T,resolveRequestBody as y,resolveResponses as P}from"../utils.js";import{isMcpEndpoint as g}from"./utils.js";import{DocsMcpTool as x}from"./docs-mcp-tool.js";import{checkEndpointAndDeleteXMcp as v}from"../../utils/xmcp-utils.js";const p=["GET","POST","PUT","DELETE","PATCH","OPTIONS","HEAD","TRACE"],S={type:"object",required:["name","path","method"],additionalProperties:!1,properties:{name:{type:"string",description:"API name",minLength:1},path:{type:"string",description:"Endpoint path (e.g. /api/v1/users)",minLength:1},method:{type:"string",description:"HTTP method (GET, POST, PUT, DELETE, etc.)",enum:[...p,...p.map(r=>r.toLowerCase())],minLength:1}}};class D extends x{name="get-endpoint-info";description="Get comprehensive information about specific endpoint including parameters, security, and examples";requiredContext=["outdir","accessInfo"];constructor(){super(S)}async executeAction(c,a){const{name:d,path:o,method:i}=c,n=await this.getApiDefinition(d,a);if(!n.success)return n.response;const{definition:e}=n,m=o.startsWith("/")?o:`/${o}`,{title:u=""}=e.info||{},s=e.paths?.[m],h=i.toLowerCase();if(!s)return{content:[{type:"text",text:"Endpoint not found"}],isError:!0};const t=s[h];if(!g(t)||!v(t,"docs"))return{content:[{type:"text",text:"Endpoint not found"}],isError:!0};const l=s?.parameters||[],E=t.parameters||[],f={...t,parameters:T({pathParams:l,opParams:E,definition:e}),requestBody:y(t.requestBody,e),responses:P(t.responses,e)};return{content:[{type:"text",text:JSON.stringify({api:u,version:e.info?.version||"",servers:e.servers||[],endpoint:{path:o,method:i.toUpperCase(),...f},globalSecurity:e.security||[],securitySchemes:e.components?.securitySchemes||[]},null,2)}]}}}export{D as GetEndpointInfoTool};
1
+ import{resolveParameters as y,resolveRequestBody as h,resolveResponses as x}from"../utils.js";import{isMcpEndpoint as E}from"./utils.js";import{loadApiDescription as v}from"./helpers/load-api-description.js";import{checkEndpointAndDeleteXMcp as g}from"../../utils/xmcp-utils.js";const P=async(s,i)=>{const{name:p,path:o,method:n}=s;let t;try{t=await v(p,i)}catch(f){return{content:[{type:"text",text:f.message}],isError:!0}}const a=o.startsWith("/")?o:`/${o}`,{title:c=""}=t.info||{},r=t.paths?.[a],d=n.toLowerCase();if(!r)return{content:[{type:"text",text:"Endpoint not found"}],isError:!0};const e=r[d];if(!E(e)||!g(e,"docs"))return{content:[{type:"text",text:"Endpoint not found"}],isError:!0};const m=r?.parameters||[],u=e.parameters||[],l={...e,parameters:y({pathParams:m,opParams:u,definition:t}),requestBody:h(e.requestBody,t),responses:x(e.responses,t)};return{content:[{type:"text",text:JSON.stringify({api:c,version:t.info?.version||"",servers:t.servers||[],endpoint:{path:o,method:n.toUpperCase(),...l},globalSecurity:t.security||[],securitySchemes:t.components?.securitySchemes||[]},null,2)}]}};var C={"get-endpoint-info":P};export{C as default};