@redocly/realm 0.138.0-next.5 → 0.138.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.
- package/CHANGELOG.md +18 -0
- package/dist/client/app/pages/DevLogin/DevLoginForm.js +1 -1
- package/dist/client/app/pages/Invite/Invite.js +1 -1
- package/dist/server/plugins/dev-onboarding/template/App.js +5 -5
- package/dist/server/plugins/mcp/codemode/capabilities/fetch/index.js +3 -3
- package/dist/server/plugins/mcp/codemode/tools/manage-credentials.js +2 -2
- package/dist/server/plugins/mcp/gateway-mcp/elicitation.d.ts +1 -7
- package/dist/server/plugins/mcp/gateway-mcp/elicitation.js +5 -6
- package/dist/server/plugins/mcp/gateway-mcp/fetch/fetch-bridge.js +1 -1
- package/dist/server/plugins/mcp/gateway-mcp/fetch/ssrf-guard.js +1 -1
- package/dist/server/plugins/mcp/gateway-mcp/rate-limit/ip-key.js +1 -1
- package/dist/server/plugins/mcp/gateway-mcp/upstream-auth-scheme.d.ts +0 -6
- package/dist/server/plugins/mcp/gateway-mcp/upstream-auth-scheme.js +2 -2
- package/dist/server/plugins/mcp/servers/mcp-server.js +2 -4
- package/dist/server/plugins/scorecard-classic/template/Grid/GridHeader.js +21 -8
- package/dist/server/plugins/scorecard-classic/template/ScorecardDashboard.js +3 -3
- package/dist/server/plugins/scorecard-classic/template/index.styles.d.ts +1 -0
- package/dist/server/plugins/scorecard-classic/template/index.styles.js +15 -5
- package/dist/server/plugins/scorecard-classic/template/views.js +1 -1
- package/dist/server/plugins/search/engines/flexsearch/index.js +2 -1
- package/dist/server/plugins/search/engines/flexsearch/search-index.d.ts +2 -2
- package/dist/server/plugins/search/engines/flexsearch/search-index.js +1 -1
- package/dist/server/types/plugins/search.d.ts +6 -4
- package/dist/server/web-server/middleware/ensureSearchData.js +1 -1
- package/dist/server/web-server/routes/cors-proxy.js +2 -2
- package/package.json +4 -4
- /package/dist/server/{plugins/mcp/gateway-mcp/fetch → web-server/utils}/ssrf-blocklist.d.ts +0 -0
- /package/dist/server/{plugins/mcp/gateway-mcp/fetch → web-server/utils}/ssrf-blocklist.js +0 -0
- /package/dist/server/{plugins/mcp/gateway-mcp/fetch → web-server/utils}/ssrf-safe-lookup.d.ts +0 -0
- /package/dist/server/{plugins/mcp/gateway-mcp/fetch → web-server/utils}/ssrf-safe-lookup.js +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# @redocly/realm
|
|
2
2
|
|
|
3
|
+
## 0.138.0-next.7
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 55a98f9decd: Hardened CORS proxy validation of request targets.
|
|
8
|
+
- 15ad3df0069: Improved keyboard navigation for catalog filters, scorecard table sorting, and the "API keys" and "Logs" tabs on app pages in developer onboarding.
|
|
9
|
+
- 15ad3df0069: Improved keyboard and screen reader accessibility for image lightboxes, feedback reasons, select menus such as the version picker, and schema variant switches in API reference.
|
|
10
|
+
- Updated dependencies [15ad3df0069]
|
|
11
|
+
- Updated dependencies [15ad3df0069]
|
|
12
|
+
- @redocly/theme@0.70.0-next.5
|
|
13
|
+
- @redocly/api-docs@0.3.0-next.5
|
|
14
|
+
|
|
15
|
+
## 0.138.0-next.6
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- c634df4a861: Fixed an issue where search returned an error on built projects with a very large search index.
|
|
20
|
+
|
|
3
21
|
## 0.138.0-next.5
|
|
4
22
|
|
|
5
23
|
### Minor Changes
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import a,{useState as T}from"react";import C from"styled-components";import{Button as o}from"@redocly/theme/components/Button/Button";import{isEmailValid as x}from"../../pages/DevLogin/utils";import{DEFAULT_AUTHENTICATED_TEAM as n}from"../../../../constants/common";import{TeamsSelector as g}from"./styled";function F({teams:s,formState:{values:t,errors:l},setFormState:m,onSubmit:d}){const[u,p]=T([]),f=()=>m({values:t,errors:void 0}),c=()=>{t?.email&&x(t.email)?(d(),l&&f()):m({values:t,errors:{...l,email:"Please enter a correct email"}})},h=({target:e})=>{m({errors:l,values:{...t,[e.name]:e.value}})},E=({target:e})=>{const i=[...t?.teams||[],e.name];e.checked?m({errors:l,values:{...t,teams:i}}):m({errors:l,values:{...t,teams:t.teams?.filter(k=>k!==e.name)}})},b=e=>{e.preventDefault(),c()},y=()=>{const e=prompt("Enter custom team name");e&&p(i=>[...i,e])};return a.createElement("form",{id:"main_form",onSubmit:b},a.createElement("div",{className:"email-screen"},a.createElement("span",{className:"label","data-cy":"email-input-label"},"Email address"),a.createElement("input",{type:"email",id:"email",name:"email",autoFocus:!0,value:t?.email||"",onChange:h,"data-cy":"email-input",className:l?.email?"error":""}),l?.email&&a.createElement("span",{id:"email-screen-email-error",className:"email-error-block","data-cy":"incorrect-email-error"},l.email),a.createElement(a.Fragment,null,a.createElement("span",{className:"label","data-cy":"email-input-label"},"Select teams"),a.createElement(g,null,s.concat(u).map(e=>a.createElement(r,{key:e},a.createElement("input",{type:"checkbox",name:e,id:e,checked:t?.teams?.includes(e)||!1,onChange:E}),a.createElement("label",{htmlFor:e},e))),a.createElement(r,{key:n},a.createElement("input",{type:"checkbox",name:n,id:n,disabled:!0,checked:!0}),a.createElement("label",{htmlFor:n,title:"This team is enabled for all authenticated users by default"},n)),a.createElement(o,{type:"button",size:"small",fullWidth:!0,onClick:y},"+ Add custom team"))),a.createElement(o,{fullWidth:!0,size:"large",variant:"primary",onClick:c,"data-cy":"log-in-button"},"Login")))}const r=C.div`
|
|
1
|
+
import a,{useState as T}from"react";import C from"styled-components";import{Button as o}from"@redocly/theme/components/Button/Button";import{isEmailValid as x}from"../../pages/DevLogin/utils";import{DEFAULT_AUTHENTICATED_TEAM as n}from"../../../../constants/common";import{TeamsSelector as g}from"./styled";function F({teams:s,formState:{values:t,errors:l},setFormState:m,onSubmit:d}){const[u,p]=T([]),f=()=>m({values:t,errors:void 0}),c=()=>{t?.email&&x(t.email)?(d(),l&&f()):m({values:t,errors:{...l,email:"Please enter a correct email"}})},h=({target:e})=>{m({errors:l,values:{...t,[e.name]:e.value}})},E=({target:e})=>{const i=[...t?.teams||[],e.name];e.checked?m({errors:l,values:{...t,teams:i}}):m({errors:l,values:{...t,teams:t.teams?.filter(k=>k!==e.name)}})},b=e=>{e.preventDefault(),c()},y=()=>{const e=prompt("Enter custom team name");e&&p(i=>[...i,e])};return a.createElement("form",{id:"main_form",onSubmit:b},a.createElement("div",{className:"email-screen"},a.createElement("span",{className:"label",id:"email-label","data-cy":"email-input-label"},"Email address"),a.createElement("input",{type:"email",id:"email","aria-labelledby":"email-label",name:"email",autoFocus:!0,value:t?.email||"",onChange:h,"data-cy":"email-input",className:l?.email?"error":""}),l?.email&&a.createElement("span",{id:"email-screen-email-error",className:"email-error-block","data-cy":"incorrect-email-error"},l.email),a.createElement(a.Fragment,null,a.createElement("span",{className:"label","data-cy":"email-input-label"},"Select teams"),a.createElement(g,null,s.concat(u).map(e=>a.createElement(r,{key:e},a.createElement("input",{type:"checkbox",name:e,id:e,checked:t?.teams?.includes(e)||!1,onChange:E}),a.createElement("label",{htmlFor:e},e))),a.createElement(r,{key:n},a.createElement("input",{type:"checkbox",name:n,id:n,disabled:!0,checked:!0}),a.createElement("label",{htmlFor:n,title:"This team is enabled for all authenticated users by default"},n)),a.createElement(o,{type:"button",size:"small",fullWidth:!0,onClick:y},"+ Add custom team"))),a.createElement(o,{fullWidth:!0,size:"large",variant:"primary",onClick:c,"data-cy":"log-in-button"},"Login")))}const r=C.div`
|
|
2
2
|
display: flex;
|
|
3
3
|
overflow: hidden;
|
|
4
4
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import e,{useState as m}from"react";import
|
|
1
|
+
import e,{useState as m}from"react";import d from"styled-components";import{Button as s}from"@redocly/theme/components/Button/Button";import{H3 as p}from"@redocly/theme/components/Typography/H3";import{ServerRoutes as u}from"../../../../constants/api";import{withPathPrefix as f}from"@redocly/theme/core/utils";function g(){const t=new URLSearchParams(window.location.search);return{code:t.get("code")||"",org:t.get("org")||"",invitedBy:t.get("invitedBy")||""}}function P(){const{code:t,org:a,invitedBy:i}=g(),[o,l]=m(t),c=async r=>{if(r.preventDefault(),!o)return;const n=new URL(f(u.IDP_LOGIN),window.location.href);n.searchParams.set("inviteCode",o),n.searchParams.set("redirectTo","/"),window.location.href=n.toString()};return e.createElement(v,null,e.createElement(p,null,"Join ",a||"Redocly"),e.createElement("form",{onSubmit:c},e.createElement("div",{className:"form-content"},!t&&e.createElement(e.Fragment,null,e.createElement("span",{className:"label",id:"invite-code-label"},"Enter your invite code"),e.createElement("input",{type:"text","aria-labelledby":"invite-code-label",value:o,onChange:r=>l(r.target.value),placeholder:"Invite code",autoFocus:!0})),i&&e.createElement("div",{className:"invite-info"},e.createElement("strong",null,i)," has invited you to join"),e.createElement(s,{fullWidth:!0,size:"large",variant:"primary",type:"submit",disabled:!o},"Accept invite"))))}const v=d.div`
|
|
2
2
|
font-family: var(--font-family-base);
|
|
3
3
|
display: flex;
|
|
4
4
|
justify-content: center;
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import*as e from"react";import
|
|
1
|
+
import*as e from"react";import i from"styled-components";import{useQuery as v}from"@tanstack/react-query";import{useParams as x}from"react-router";import{Box as y,Flex as E}from"@redocly/portal-legacy-ui";import{Admonition as A}from"@redocly/theme/markdoc/components/Admonition/Admonition";import{useTabList as w}from"@redocly/theme/core/hooks";import{useTranslate as T}from"../../../../client/app/hooks";import C from"../../../../client/app/CircularProgress";import{Container as P}from"./components/Container";import k from"./components/AppOverview";import I from"./components/ApiKeys";import L from"./components/ApiLogs";import _ from"./components/CreateApiKey";import{Description as B}from"./components/Description";import{CallbackUrl as K}from"./components/CallbackUrl";const S="app-tab-actions-portal",p="api_keys",z="logs";function D(U){const{id:s}=x(),{isLoading:m,error:l,data:t}=v({queryKey:["APP:"+s],queryFn:()=>fetch(`/api/api-keys/apps/${s}`).then(a=>a.json())}),{translate:c}=T(),d=a=>r.findIndex(o=>o.id===a),r=[{id:p,name:c("dev.main.tab.appKeys","API keys"),content:e.createElement(e.Fragment,null,e.createElement(I,{credentials:t?.credentials,attributes:t?.attributes}),e.createElement(B,{text:t?.description}),t?.callbackUrl!==void 0&&e.createElement(K,{text:t.callbackUrl})),show:!0},{id:z,name:c("dev.main.tab.logs","Logs"),content:e.createElement(L,null),show:!!t?.supportsLogs}].filter(a=>a.show),[n,g]=e.useState(0),{tabListProps:u,getTabProps:b,getTabPanelProps:f}=w({count:r.length,activeIndex:n,onChange:g}),h=t?.canCreateKey&&n===d(p);return e.createElement(y,{my:"2rem"},e.createElement(P,null,m?e.createElement(E,{justifyContent:"center",mt:"2em"},e.createElement(C,null)):l?e.createElement(A,{type:"danger"},l?.message??"Something went wrong"):t?e.createElement(e.Fragment,null,e.createElement(k,{app:t}),e.createElement(F,null,e.createElement(O,{...u},r.map(({name:a},o)=>e.createElement("span",{key:a,className:n===o?"active":"",...b(o)},a))),e.createElement("div",{id:S}),h&&e.createElement(_,{initialEnabledApis:(t.credentials||[]).flatMap(a=>a.apiProductIds||[])})),e.createElement(j,{...f(n)},r[n].content)):null))}const ae=i.i`
|
|
2
2
|
display: inline-block;
|
|
3
3
|
width: 12px;
|
|
4
4
|
height: 12px;
|
|
5
5
|
background-repeat: no-repeat;
|
|
6
6
|
background-size: 12px 12px;
|
|
7
7
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='black' viewBox='0 0 451.847 451.847' width='12px' height='12px' %3E%3Cpath d='M225.923 354.706c-8.098 0-16.195-3.092-22.369-9.263L9.27 151.157c-12.359-12.359-12.359-32.397 0-44.751 12.354-12.354 32.388-12.354 44.748 0l171.905 171.915 171.906-171.909c12.359-12.354 32.391-12.354 44.744 0 12.365 12.354 12.365 32.392 0 44.751L248.292 345.449c-6.177 6.172-14.274 9.257-22.369 9.257z' /%3E%3C/svg%3E");
|
|
8
|
-
`,
|
|
8
|
+
`,F=i.div`
|
|
9
9
|
display: flex;
|
|
10
10
|
justify-content: space-between;
|
|
11
11
|
align-items: end;
|
|
12
|
-
`,
|
|
12
|
+
`,O=i.div`
|
|
13
13
|
display: flex;
|
|
14
14
|
align-items: center;
|
|
15
15
|
height: 42px;
|
|
@@ -27,6 +27,6 @@ import*as e from"react";import a from"styled-components";import{useQuery as f}fr
|
|
|
27
27
|
> span.active {
|
|
28
28
|
border-bottom: 2px solid var(--border-color-primary);
|
|
29
29
|
}
|
|
30
|
-
`,
|
|
30
|
+
`,j=i.div`
|
|
31
31
|
margin-top: var(--spacing-base);
|
|
32
|
-
`;export{
|
|
32
|
+
`;export{ae as ArrowIcon,S as TAB_ACTIONS_PORTAL_ID,D as default};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import{getCallableApis as n,isFetchCapable as o}from"../../../gateway-mcp/callable-apis.js";import{FETCH_TOOL_NAME as i}from"../../constants.js";const l=["```ts","/**"," * Call a documented API. Only the callable APIs' documented hosts are reachable."," * Responses cap at 1 MiB and redirects are not followed."," */","declare function fetch(url: string | URL, init?: {"," method?: string;"," /** `content-type` is set automatically for URLSearchParams/FormData unless you set one. */"," headers?: Record<string, string>;"," /** string \xB7 URLSearchParams (\u2192 application/x-www-form-urlencoded) \xB7 FormData (\u2192 multipart/form-data) */"," body?: string | URLSearchParams | FormData;"," /** Security scheme name (from the operation's `security` or `getSecuritySchemes`) whose credential to send. Omit to let the server choose. */"," securityScheme?: string;","}): Promise<{"," status: number;"," statusText: string;"," ok: boolean;"," headers: { get(name: string): string | null };"," json(): Promise<unknown>;"," text(): Promise<string>;","}>;","```"].join(`
|
|
2
|
-
`),c=["listApis","getEndpoints","getEndpointInfo"],
|
|
3
|
-
`),
|
|
4
|
-
`);function
|
|
2
|
+
`),c=["listApis","getEndpoints","getEndpointInfo"],p=["Example - list the paid invoices of a billing API:","","```ts","const { items } = await tools.listApis({ filter: 'billing' });","const [api] = items;",`if (!api) return { error: 'no API matches "billing"' };`,"const { endpoints } = await tools.getEndpoints({ name: api.name });","const ep = endpoints.find((e) => e.method === 'GET' && e.path.includes('invoices'));","const info = await tools.getEndpointInfo({ name: api.name, path: ep.path, method: ep.method });","// Replace every `{placeholder}` first.","const url = new URL((info.servers?.[0]?.url ?? '') + ep.path);","// Every name below comes from `info.endpoint.parameters` - read them first, never guess them.","url.searchParams.set('filter', 'status:paid');","url.searchParams.set('sort', '-createdTime');","url.searchParams.set('limit', '100');","try {"," const res = await fetch(url, { method: ep.method });"," return res.ok ? await res.json() : { status: res.status, error: await res.text() };","} catch (error) {"," return { error: error instanceof Error ? error.message : String(error), endpointId: info };","}","```"].join(`
|
|
3
|
+
`),d=["Example - call an endpoint you already read:","","```ts","// Call `getEndpointInfo` first for the server URL, the path, and the parameter names.","// Replace every `{placeholder}` first.","const url = new URL('https://api.example.com/invoices');","url.searchParams.set('filter', 'status:paid');","try {"," const res = await fetch(url, { method: 'GET' });"," return res.ok ? await res.json() : { status: res.status, error: await res.text() };","} catch (error) {"," return { error: error instanceof Error ? error.message : String(error) };","}","```"].join(`
|
|
4
|
+
`);function h(r){return c.every(t=>r.includes(t))?p:d}function m(r){const t=new Map;for(const{name:e,version:a}of r){if(!e)continue;const s=t.get(e)??[];a&&s.push(a),t.set(e,s)}return[...t.entries()].map(([e,a])=>a.length>1?`${e} (${a.map(s=>`v${s}`).join(", ")})`:e).join(", ")}const g={id:i,purpose:"Call the documented APIs over HTTP",isActive:o,annotations:{readOnlyHint:!1,destructiveHint:!0,openWorldHint:!0},renderSection(r,t){const e=m(n(r));return["## `fetch` \u2014 call the documented APIs","",l,"","Always call `getEndpointInfo` before `fetch` for the exact URL, required parameters, and body shape. Put filtering, sorting, and paging in the query parameters, and keep sandbox JS for what the endpoint cannot express. Never guess.","","A `servers[].url` or an endpoint path can hold `{placeholders}`. Replace every one before you call `fetch`. Use the server variable `default`. Ask the user when the `default` only repeats the variable name, such as `{organizationId}`.","",`Callable APIs (their documented hosts are reachable via \`fetch\`): ${e}`,"",h(t)].join(`
|
|
5
5
|
`)}};export{l as FETCH_DECLARATION,g as fetchCapability};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{MANAGE_API_CREDENTIALS_TOOL_NAME as P}from"../../constants.js";import{acceptedCredentialsLink as k,buildCredentialsAcceptedHint as w,buildUpstreamCredentialFallback as S,buildUpstreamCredentialInputRequired as I,credentialElicitationAnswer as E,dedupeElicitation as C,isStatelessRequest as j,schemeLabelOf as q,supportsUrlElicitation as T}from"../../gateway-mcp/elicitation.js";import{getCallableApis as u,isFetchCapable as H}from"../../gateway-mcp/callable-apis.js";import{secretStore as R}from"../../gateway-mcp/secret-store.js";import{MISSING_SESSION_HANDLE_MESSAGE as U,resolveSecretSubject as $}from"../../gateway-mcp/subject.js";import{upstreamAuthKey as L}from"../../gateway-mcp/upstream-auth.js";import{resolveUpstreamApiAuth as N}from"../../gateway-mcp/upstream-auth-scheme.js";import{apiTitleKey as O,countApiTitles as _}from"../../docs-mcp/utils/api-titles.js";function Q(e){return!!e.elicitationEnabled&&H(e)}function V(e){const s=u(e),t=s.map(
|
|
2
|
-
`),annotations:{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!1,openWorldHint:!1},schema:{type:"object",required:["api"],additionalProperties:!1,properties:{api:{type:"string",description:`The API to manage credentials for: its \`filePath\` or the \`name\` from \`listApis\`.${t.length>0?` The file paths are: ${t.join(", ")}.`:""}`,minLength:1,...
|
|
1
|
+
import{MANAGE_API_CREDENTIALS_TOOL_NAME as P}from"../../constants.js";import{acceptedCredentialsLink as k,buildCredentialsAcceptedHint as w,buildUpstreamCredentialFallback as S,buildUpstreamCredentialInputRequired as I,credentialElicitationAnswer as E,dedupeElicitation as C,isStatelessRequest as j,schemeLabelOf as q,supportsUrlElicitation as T}from"../../gateway-mcp/elicitation.js";import{getCallableApis as u,isFetchCapable as H}from"../../gateway-mcp/callable-apis.js";import{secretStore as R}from"../../gateway-mcp/secret-store.js";import{MISSING_SESSION_HANDLE_MESSAGE as U,resolveSecretSubject as $}from"../../gateway-mcp/subject.js";import{upstreamAuthKey as L}from"../../gateway-mcp/upstream-auth.js";import{resolveUpstreamApiAuth as N}from"../../gateway-mcp/upstream-auth-scheme.js";import{apiTitleKey as O,countApiTitles as _}from"../../docs-mcp/utils/api-titles.js";function Q(e){return!!e.elicitationEnabled&&H(e)}function V(e){const s=u(e),t=s.map(r=>r.relativePath),i=[...t,...M(s)];return{name:P,title:"Manage API credentials",description:["Get a secure link where the user sets, replaces, or removes the credentials this server sends to a documented API.","Call it when the user wants to change or clear an API key, or when a tool result tells you the stored credentials were rejected.","The link covers every credential the API accepts, so scheme is optional - pass it only when a tool result names the scheme that was rejected.","It returns a link for the user to open - never ask for the secret in the conversation and never pass it as an argument."].join(`
|
|
2
|
+
`),annotations:{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!1,openWorldHint:!1},schema:{type:"object",required:["api"],additionalProperties:!1,properties:{api:{type:"string",description:`The API to manage credentials for: its \`filePath\` or the \`name\` from \`listApis\`.${t.length>0?` The file paths are: ${t.join(", ")}.`:""}`,minLength:1,...i.length>0?{enum:i}:{}},scheme:{type:"string",description:"Name of the security scheme to manage the credential for, as named in the API description (a tool result that reports a rejected credential names it). Omit it to let the link cover every scheme the API accepts.",minLength:1},sessionHandle:{type:"string",description:"Handle returned by createAnonymousSession. Required while the caller is anonymous, so the credentials are stored against the same subject the API calls use.",minLength:1}}}}}function M(e){const s=_(e);return e.map(t=>t.name).filter(t=>s.get(O(t))===1)}function X(e,s){return async(t,i)=>{const r=$(e.user,typeof t.sessionHandle=="string"?t.sessionHandle:void 0);if(r.kind==="invalid")return m(r.message);if(r.kind==="anonymous")return m(U);const{subject:c}=r,p=typeof t.api=="string"?t.api:"",n=u(e).find(l=>l.relativePath===p||l.name===p);if(!n){const l=u(e).map(b=>b.relativePath).join(", ");return m(`Unknown api "${p}". Credentials can only be managed for the APIs this server can call: ${l||"none"}.`)}const d=E(i.mcpReq.inputResponses);if(d==="accepted"){const l=await k(i.mcpReq.requestState(),{kv:await s.getKv(),subject:c,baseUrl:e.baseUrl??"",apis:[n.relativePath]});return{content:[{type:"text",text:w(n.name,l?.url)}],isError:!1}}if(d==="declined")return{content:[{type:"text",text:`The user declined the credentials prompt for the "${n.name}" API, so this call minted no link.`}],isError:!1};const a=await N(e,n.relativePath),o=typeof t.scheme=="string"?t.scheme:void 0,y=Object.keys(a.schemes);if(o&&!a.schemes[o])return m(`Unknown scheme "${o}" for api "${n.relativePath}". The security schemes this server can store credentials for are: ${y.join(", ")}.`);const h=o??a.defaultScheme,f=o?q(a.schemes,o):void 0,A=await s.getKv(),v={subject:c,baseUrl:e.baseUrl??"",target:{api:n.relativePath,name:n.name,scheme:h,...f?{schemeLabel:f}:{}},auth:a.schemes[h],apiAuth:a,kv:A,hasExistingSecret:await R.hasSecret(A,c,n.relativePath,h),reason:{kind:"requested"}};if(j(i.mcpReq)&&T(s.getClientCapabilities()))return await I(v);const g=L({api:n.relativePath,scheme:h});return{content:[{type:"text",text:await C(`${c}:${g}`,()=>S(v))}],isError:!1}}}function m(e){return{content:[{type:"text",text:e}],isError:!0}}export{Q as isManageApiCredentialsToolAvailable,X as manageApiCredentials,V as manageApiCredentialsSchema};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { InputRequiredResult } from '@modelcontextprotocol/server';
|
|
2
2
|
import type { UpstreamAuthRequiredEvent } from './upstream-auth.js';
|
|
3
|
-
import type {
|
|
3
|
+
import type { UpstreamApiAuth, UpstreamAuthScheme } from './upstream-auth-scheme.js';
|
|
4
4
|
import type { KvService } from '@redocly/config';
|
|
5
5
|
export declare const CREDENTIALS_INPUT_REQUEST_KEY = "credentials";
|
|
6
6
|
export type CredentialTarget = {
|
|
@@ -71,11 +71,5 @@ export declare function buildUpstreamCredentialFallback(request: CredentialElici
|
|
|
71
71
|
* likely a permissions problem than a missing key.
|
|
72
72
|
*/
|
|
73
73
|
export declare function buildCredentialsToolHint(event: UpstreamAuthRequiredEvent, schemeLabel?: string): string;
|
|
74
|
-
/**
|
|
75
|
-
* Text for an operation that accepts several security schemes and has no stored credential for
|
|
76
|
-
* any of them. Picking one here is what sent an API key as a session cookie, so the model is told
|
|
77
|
-
* to ask the user which credential they hold and pass it back as `scheme`.
|
|
78
|
-
*/
|
|
79
|
-
export declare function buildSchemeChoiceHint(event: UpstreamAuthRequiredEvent, choices: readonly SchemeChoice[]): string;
|
|
80
74
|
export {};
|
|
81
75
|
//# sourceMappingURL=elicitation.d.ts.map
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import{inputRequired as
|
|
2
|
-
`)}async function Y(e,{kv:t,subject:r,baseUrl:n,apis:
|
|
3
|
-
`)}const n=e.status===401?`The "${e.name}" API rejected the stored ${t?`"${t}" `:""}credential (${r}).`:`The "${e.name}" API rejected the request with ${r}.`,
|
|
4
|
-
`)}function
|
|
5
|
-
`)}
|
|
6
|
-
`)}export{m as CREDENTIALS_INPUT_REQUEST_KEY,Y as acceptedCredentialsLink,B as buildCredentialsAcceptedHint,J as buildCredentialsToolHint,K as buildSchemeChoiceHint,G as buildUpstreamCredentialFallback,z as buildUpstreamCredentialInputRequired,q as credentialElicitationAnswer,F as dedupeElicitation,D as isStatelessRequest,W as schemeLabelOf,H as supportsUrlElicitation};
|
|
1
|
+
import{inputRequired as h,inputResponse as y}from"@modelcontextprotocol/server";import{withPathPrefix as I}from"@redocly/theme/core/utils";import{MCP_CREDENTIALS_ROUTE as A}from"../../../constants/mcp.js";import{MANAGE_API_CREDENTIALS_TOOL_NAME as u}from"../constants.js";import{secretStore as l,ELICITATION_TTL_MS as P}from"./secret-store.js";import{operationsForScheme as E,orderedSchemesOf as g}from"./upstream-auth-scheme.js";import{ANONYMOUS_SUBJECT_PREFIX as p}from"./subject.js";const m="credentials",d=new Map;function F(e,t){const r=d.get(e);if(r)return r;const n=t().finally(()=>{d.delete(e)});return d.set(e,n),n}function D(e){return!!e?.elicitation?.url}function H(e){return e.envelope!==void 0}function q(e){const t=y(e,m);if(t.kind==="elicit")return t.action==="accept"?"accepted":"declined"}function B(e,t){return[`The user accepted the prompt to add credentials for the "${e}" API.`,...t?["The credentials page:",t]:[],"",`Wait until the user says they saved the credentials, then retry the call that needed them. Do not call \`${u}\` again unless the user asks for a new link.`].join(`
|
|
2
|
+
`)}async function Y(e,{kv:t,subject:r,baseUrl:n,apis:o}){if(typeof e!="string")return;const i=await l.peekElicitation(t,e);if(!(i?.subject!==r||!o.includes(i.api)))return{apiName:i.name,url:T(n,e)}}function W(e,t){return Object.keys(e).length>1?t:void 0}async function z(e){const{token:t,url:r}=await f(e);return h({inputRequests:{[m]:h.elicitUrl({message:C(e),url:r})},requestState:t})}async function G(e){const{url:t}=await f(e);return _(e,t,S(e.subject))}function J(e,t){const r=b(e);if(e.status===401&&!e.sentScheme){const[i,s]=e.callerHeader?[`Your code set the "${e.callerHeader}" header itself, so the stored credential was not sent.`,"Remove that header from the request and retry. Do not replace the stored credentials."]:["No stored credential was sent with this request, so this result says nothing about the stored credentials.","Do not replace them. Check whether this operation needs a different kind of credential or a different route."];return[`The "${e.name}" API returned ${r}. ${i}`,"",s].join(`
|
|
3
|
+
`)}const n=e.status===401?`The "${e.name}" API rejected the stored ${t?`"${t}" `:""}credential (${r}).`:`The "${e.name}" API rejected the request with ${r}.`,o=t?`api: "${e.api}" and scheme: "${t}"`:`api: "${e.api}"`;return[n,"",`Do not retry the same call. Call \`${u}\` with ${o} to get a link the user has to open in a browser to replace or remove the stored credentials, then retry once they confirm they saved them.`].join(`
|
|
4
|
+
`)}function b({status:e,detail:t}){return t?`HTTP ${e}: ${t}`:`HTTP ${e}`}async function f({kv:e,subject:t,baseUrl:r,target:n,auth:o,apiAuth:i,hasExistingSecret:s}){const a=i?await k(e,t,n.api,i):[],c=await l.createElicitation(e,{subject:t,api:n.api,name:n.name,scheme:n.scheme,...n.schemeLabel?{schemeLabel:n.schemeLabel}:{},auth:o,hasExistingSecret:s,...a.length>1?{schemes:a}:{}});return{token:c,url:T(r,c)}}async function k(e,t,r,n){const i=(await l.getSecretsForSubject(e,t))[r]??{};return g(n.schemes).map(s=>{const a=E(n,s),c=n.descriptions?.[s];return{name:s,...c?{label:c}:{},auth:n.schemes[s],hasExistingSecret:!!i[s],...a.length>0?{operations:a}:{}}})}function S(e){return e.startsWith(p)?e.slice(p.length):void 0}function C({target:e,hasExistingSecret:t,reason:r}){const n=`The link works for ${$()} minutes.`,o=x(e),i=r.kind==="authFailure"&&r.detail?` The API answered: ${r.detail}.`:"";return t?`Open this page in a browser to replace or remove the stored credentials for ${o}. They go straight to the API and never enter the chat. ${n}`:`${O(o)} needs credentials.${i} Open this page in a browser to paste them - they go straight to the API and never enter the chat. ${n}`}function x({name:e,schemeLabel:t}){return t?`the "${t}" scheme of the "${e}" API`:`the "${e}" API`}function O(e){return e.charAt(0).toUpperCase()+e.slice(1)}function $(){return Math.round(P/6e4)}function T(e,t){const r=I(A);if(!e)return`${r}?token=${t}`;try{const n=new URL(r,e);return n.searchParams.set("token",t),n.toString()}catch{return`${e}${r}?token=${t}`}}function _({target:e,reason:t,hasExistingSecret:r},n,o){const s=[`**Stop and show the user this link. They have to open it in a browser to ${r?`replace or remove the stored credentials for the "${e.name}" API`:`add credentials for the "${e.name}" API`} - nothing continues until they do.**`,"",n,"",`The link is valid ${$()} minutes and opens a form on this site. Credentials go straight to the API from there: never ask for them in the conversation and never pass them as a tool argument.`,"",t.kind==="authFailure"?`The upstream API "${e.name}" returned ${t.status}${t.detail?` (${t.detail})`:""} and needs credentials.`:r?`Credentials are already stored for the "${e.name}" API; the link lets the user replace or remove them.`:`The "${e.name}" API needs credentials.`,...e.schemeLabel?[`The operation authenticates with its "${e.schemeLabel}" security scheme.`]:[],o?`Once the user confirms they saved them, call this tool again with sessionHandle: "${o}" - the credentials are stored against that handle, applied server-side, and never appear in the conversation.`:"Once the user confirms they saved them, call this tool again - the credentials are applied server-side and never appear in the conversation."],a=t.kind==="authFailure"?t.otherApiNames??[]:[];if(a.length>0){const c=a.map(w=>`"${w}"`).join(", ");s.push("",`The remaining APIs (${c}) will prompt for credentials on subsequent calls.`)}return s.join(`
|
|
5
|
+
`)}export{m as CREDENTIALS_INPUT_REQUEST_KEY,Y as acceptedCredentialsLink,B as buildCredentialsAcceptedHint,J as buildCredentialsToolHint,G as buildUpstreamCredentialFallback,z as buildUpstreamCredentialInputRequired,q as credentialElicitationAnswer,F as dedupeElicitation,H as isStatelessRequest,W as schemeLabelOf,D as supportsUrlElicitation};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{Agent as Q}from"undici";import{envConfig as Z}from"../../../../config/env-config.js";import{logger as N}from"../../../../tools/notifiers/logger.js";import{assertUrlAllowed as I}from"./ssrf-guard.js";import{createSsrfSafeLookup as q}from"
|
|
1
|
+
import{Agent as Q}from"undici";import{envConfig as Z}from"../../../../config/env-config.js";import{logger as N}from"../../../../tools/notifiers/logger.js";import{assertUrlAllowed as I}from"./ssrf-guard.js";import{createSsrfSafeLookup as q}from"../../../../web-server/utils/ssrf-safe-lookup.js";import{SsrfBlockedError as W}from"../../../../web-server/utils/ssrf-blocklist.js";import{GatewayFetchBlockedError as R,GatewayFetchSystemError as ee,GatewayFetchUserError as g}from"./fetch-errors.js";import{redactHeaders as J,redactSecretsFromString as te}from"./redact.js";import{extractUpstreamDetail as re}from"./upstream-detail.js";import{normalizeFetchPath as ne}from"./normalize-path.js";import{reportGatewayFetch as K}from"./fetch-telemetry.js";import{logGatewayFetchAudit as V}from"./fetch-audit.js";const X="x-forwarded-for",oe=3e4,se=1024*1024,ae=new Set([401,403,407]);let C;function ce(){if(!C){const e=Z.isDevelopMode;e&&N.warn("Gateway MCP SSRF guard: loopback upstreams are ALLOWED (develop mode only, never in runtime)."),C=new Q({connect:{lookup:q({allowLoopback:e})}})}return C}function _e({allowedHosts:e,apis:t=[],authorization:r,onAuthRequired:n,fetchImpl:c=fetch,dispatcher:a=ce(),timeoutMs:h=oe,maxResponseBytes:l=se,maxFetchesPerExec:w,clientIp:k}){const f=[...e,...t.flatMap(o=>o.matchers)],$=[...new Set(t.map(o=>o.name).filter(Boolean))].join(", "),m=t.flatMap(o=>Object.values(o.secrets??{})),D=[r,...m.map(o=>o.value)].filter(o=>!!o),x=m.map(o=>o.header);let O=0;return async o=>{const y=o.method??"GET",T=Date.now();let B,b,A,E={},H,_,j;try{if(w!==void 0){const u=Math.max(0,w);if(O+=1,O>u)throw new g(`Outbound fetch budget exceeded (max ${u} fetches per execute); split the work across calls`)}const d=le(o.url,f,$);B=d.hostname,b=ne(d.pathname);const v=t.filter(u=>u.matchers.some(z=>z.test(d.hostname))),s=v.length===1?v[0]:void 0;A=s?.slug;const S=pe(o.securityScheme,s),F=S?[S]:s?ye(s,d.pathname,y):void 0,L=s&&F?Se(s,F):void 0,P=L?s?.secrets?.[L]:void 0,M=be({callerHeaders:o.headers,secret:P,authorization:r,clientIp:k,credentialHeaders:s?.credentialHeaders});E=M.headers,H=P&&!M.callerHeader?L:void 0;const G=new AbortController;j=setTimeout(()=>G.abort(),h);const i=await c(d,{method:y,headers:E,body:o.body,redirect:"manual",signal:G.signal,dispatcher:a});_=i.status;let U="";try{U=await we(i,l)}finally{if(ae.has(i.status)&&s&&n){const u=re(U,i.headers.get("content-type"),D);n({api:s.slug,name:s.name,status:i.status,...L?{scheme:L}:{},...F?.length?{schemes:[...F]}:{},...H?{sentScheme:H}:{},...M.callerHeader?{callerHeader:M.callerHeader}:{},...u?{detail:u}:{}})}}let p=Ae(i.headers);if(fe(i.status)){p=J(p,x);const{location:u}=p;u&&!he(u,d,f)&&delete p.location}return K({host:d.hostname,method:y,outcome:"success",durationMs:Date.now()-T,path:b,api:A,status:i.status,bytes:Buffer.byteLength(U,"utf8")}),V({rawUrl:d.href,method:y,host:d.hostname,outcome:"success",durationMs:Date.now()-T,injectedSecretValues:D,path:b,api:A,status:i.status,injectedScheme:H,requestHeaders:E,requestBody:o.body,responseHeaders:p,responseBody:U}),{status:i.status,statusText:i.statusText,ok:i.ok,headers:p,bodyText:U}}catch(d){const{outcome:v,userSafe:s}=ie(d),S=B??(s instanceof R?s.host:void 0)??ue(o.url)??"invalid-url";throw K({host:S,method:y,outcome:v,durationMs:Date.now()-T,path:b,api:A,status:_}),V({rawUrl:o.url,method:y,host:S,outcome:v,durationMs:Date.now()-T,injectedSecretValues:D,path:b,api:A,status:_,injectedScheme:H,requestHeaders:E,requestBody:o.body}),s||(N.error(`Gateway MCP fetch failed [${y} ${S}]: ${te(me(d),D)} headers=${JSON.stringify(J(E,x))}`),new ee("Upstream fetch failed due to an internal error"))}finally{j!==void 0&&clearTimeout(j)}}}function de(e){let t=e;for(let r=0;r<5&&t instanceof Error;r++){if(t instanceof g||t instanceof W)return t;t=t.cause}}function ie(e){const t=de(e);return{outcome:t instanceof R||t instanceof W?"blocked":t?"user_error":"system_error",userSafe:t}}function le(e,t,r){try{return I(e,t)}catch(n){throw n instanceof R&&r?new R(`${n.message}. \`fetch\` reaches only the documented hosts of the callable APIs (${r}); other documented APIs can be read through the tools but not called.`,n.host):n}}function ue(e){try{return new URL(e).hostname||void 0}catch{return}}function fe(e){return e>=300&&e<400}function he(e,t,r){try{return!!I(new URL(e,t).href,r)}catch{return!1}}function me(e){if(!(e instanceof Error))return String(e);const t=e.cause;return t instanceof Error?`${e.message}: ${t.message}`:e.message}async function we(e,t){const r=Number(e.headers.get("content-length"));if(Number.isFinite(r)&&r>t)throw Y(t,r);if(!e.body)return"";const n=e.body.getReader(),c=new TextDecoder;let a=0,h="";try{for(;;){const{done:l,value:w}=await n.read();if(l)break;if(a+=w.byteLength,a>t)throw Y(t,a);h+=c.decode(w,{stream:!0})}return h+c.decode()}finally{await n.cancel().catch(()=>{})}}function Y(e,t){return new g(`Response is too large (over ${e} bytes, got ${t}); request less data`)}function ye(e,t,r){const n=e.routes?.find(c=>c.method===r&&c.pattern.test(t));return n?n.schemes:ge(e)}function Se(e,t){const r=t.filter(n=>e.secrets?.[n]);return r.length===0?t[0]:r.reduce((n,c)=>{const a=e.secrets?.[n]?.savedAt??0;return(e.secrets?.[c]?.savedAt??0)>a?c:n})}function pe(e,t){if(e==null)return;if(typeof e!="string")throw new g("securityScheme must be a security scheme name (a string)");if(!t)throw new g("securityScheme cannot be applied: the URL host does not identify exactly one callable API");const r=t.schemePriority??[];if(r.length>0&&!r.includes(e))throw new g(`Unknown securityScheme "${e}" for ${t.name}; valid values: ${r.join(", ")}`);return e}function ge(e){const t=Object.keys(e.secrets??{});if(t.length===0)return e.defaultScheme?[e.defaultScheme]:[];const r=(e.schemePriority??[]).filter(n=>t.includes(n));return[...r,...t.filter(n=>!r.includes(n))]}function be({callerHeaders:e,secret:t,authorization:r,clientIp:n,credentialHeaders:c}){const a={},h=new Set,l=t??(r?{header:"Authorization",value:r}:void 0),w=l?new Set((c??[]).map(f=>f.toLowerCase()).filter(f=>f!==l.header.toLowerCase())):new Set;for(const[f,$]of Object.entries(e??{})){const m=f.toLowerCase();m==="host"||m==="content-length"||m!==X&&(w.has(m)||(h.add(m),a[f]=$))}if(n&&(a[X]=n),!l)return{headers:a};const k=l.header.toLowerCase();return h.has(k)?{headers:a,callerHeader:k}:(a[l.header]=l.value,{headers:a})}function Ae(e){const t={};return e.forEach((r,n)=>{t[n.toLowerCase()]=r}),t}export{_e as buildFetchBridge,ce as getDefaultAgent,we as readCappedBody};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{isIP as d}from"node:net";import{isHostAllowed as h}from"./allowed-hosts.js";import{isBlockedIp as w}from"
|
|
1
|
+
import{isIP as d}from"node:net";import{isHostAllowed as h}from"./allowed-hosts.js";import{isBlockedIp as w}from"../../../../web-server/utils/ssrf-blocklist.js";import{GatewayFetchBlockedError as p,GatewayFetchUserError as r}from"./fetch-errors.js";import{findUnresolvedPlaceholders as a,unresolvedPlaceholderMessage as i}from"./url-placeholders.js";function v(o,t){let e;try{e=new URL(o)}catch{throw new r(`Invalid URL: ${o}`)}if(e.protocol!=="http:"&&e.protocol!=="https:")throw new r(`Only http(s) URLs are allowed, got ${e.protocol}`);if(e.username||e.password)throw new r("URLs must not contain embedded credentials");const n=a(e.hostname);if(n.length>0)throw new r(i(n));const s=c(e.hostname);if(f(s)||!h(s,t))throw new p(`Host "${s}" is not allowed`,s);const l=a(e.pathname);if(l.length>0)throw new r(i(l));return e}function f(o){const t=c(o.toLowerCase()).split("%")[0];return t==="localhost"||t.endsWith(".localhost")?!0:d(t)!==0?w(t):!1}function c(o){return o.replace(/^\[|\]$/g,"")}export{v as assertUrlAllowed,f as isBlockedAddress};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{isIP as l}from"node:net";import{getFeedbackClientIp as a}from"../../../../web-server/utils/feedback-ip.js";import{extractMappedIpv4 as c}from"
|
|
1
|
+
import{isIP as l}from"node:net";import{getFeedbackClientIp as a}from"../../../../web-server/utils/feedback-ip.js";import{extractMappedIpv4 as c}from"../../../../web-server/utils/ssrf-blocklist.js";function I(t){const n=a(t);if(n)return f(n)}function f(t){if(l(t)===6){const n=c(t);return n||`${u(t)}::/64`}return t}function u(t){const n=t.split("%")[0],[e,i=""]=n.split("::"),r=e?e.split(":"):[],o=i?i.split(":"):[],s=8-r.length-o.length;return[...r,...Array(Math.max(0,s)).fill("0"),...o].slice(0,4).map(p=>parseInt(p||"0",16).toString(16)).join(":")}export{I as ipRateLimitKey};
|
|
@@ -27,15 +27,9 @@ export type UpstreamApiAuth = {
|
|
|
27
27
|
routes: UpstreamAuthRoute[];
|
|
28
28
|
descriptions?: Record<string, string>;
|
|
29
29
|
};
|
|
30
|
-
export type SchemeChoice = {
|
|
31
|
-
name: string;
|
|
32
|
-
label: string;
|
|
33
|
-
description?: string;
|
|
34
|
-
};
|
|
35
30
|
type SecuritySchemeLoader = typeof getApiDescriptionFromFs;
|
|
36
31
|
export declare const DEFAULT_SCHEME_NAME = "default";
|
|
37
32
|
export declare function resolveUpstreamApiAuth(context: McpToolContext, apiRelativePath: string, loadDescription?: SecuritySchemeLoader): Promise<UpstreamApiAuth>;
|
|
38
|
-
export declare function schemeChoicesOf(auth: UpstreamApiAuth, names: readonly string[]): SchemeChoice[];
|
|
39
33
|
export declare function credentialHeadersOf(schemes: Record<string, UpstreamAuthScheme>): string[];
|
|
40
34
|
export declare function orderedSchemesOf(schemes: Record<string, UpstreamAuthScheme>): string[];
|
|
41
35
|
export declare function operationsForScheme(auth: UpstreamApiAuth, scheme: string): string[];
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{getApiDescriptionFromFs as
|
|
2
|
-
`)[0].trim();s&&(n[r]=s.slice(0,A))}return n}function
|
|
1
|
+
import{getApiDescriptionFromFs as S}from"../docs-mcp/tools/openapi/utils.js";import{OPERATION_METHODS as b}from"../docs-mcp/tools/openapi/constants.js";const A=120,l="default",g={kind:"raw"},h=["oauth2ClientCredentials","bearer","apiKey","cookie","raw"],E=new Set(b),j=/\{(?<!\{[^}]*?\{)[^}]*\}/g;function c(){return{schemes:{[l]:g},defaultScheme:l,routes:[]}}async function M(e,t,n=S){const r=Object.values(e.apiDescriptionsMap??{}).find(i=>i.relativePath===t);if(!r)return c();try{const i=await n({relativePath:r.relativePath,outdir:e.outdir||"",user:e.user,rbac:e.config?.access?.rbac||{},requiresLogin:!!e.config?.access?.requiresLogin});return i?w(i,r.servers??[]):c()}catch{return c()}}function w(e,t){const n=x(e),r=Object.keys(n);if(r.length===0)return c();const i=m(e.security,n)[0]??a(r,n)[0],o=C(e,r);return{schemes:n,defaultScheme:i,routes:H(e,n,t),...Object.keys(o).length>0?{descriptions:o}:{}}}function L(e){return[...new Set(Object.values(e).map(P))]}function N(e){return a(Object.keys(e),e)}function U(e,t){const n=new Set;for(const r of e.routes)r.schemes.includes(t)&&n.add(`${r.method} ${r.path}`);return[...n]}function P(e){return e.kind==="apiKey"?e.header:e.kind==="cookie"?"Cookie":"Authorization"}function C(e,t){const n={};for(const r of t){const i=e.components?.securitySchemes?.[r],o=O(i)?i.description:void 0;if(typeof o!="string")continue;const s=o.split(`
|
|
2
|
+
`)[0].trim();s&&(n[r]=s.slice(0,A))}return n}function x(e){const t={};for(const[n,r]of Object.entries(e.components?.securitySchemes??{})){if(!O(r))continue;const i=T(r);i&&(t[n]=i)}return t}function T(e){if(e.type==="oauth2"){const t=e.flows?.clientCredentials;return t?{kind:"oauth2ClientCredentials",tokenUrl:t.tokenUrl,scopes:Object.keys(t.scopes??{})}:{kind:"bearer"}}if(e.type==="http"&&e.scheme==="bearer")return{kind:"bearer"};if(e.type==="apiKey"&&e.in==="header")return{kind:"apiKey",header:e.name||"X-Api-Key"};if(e.type==="apiKey"&&e.in==="cookie"&&e.name)return{kind:"cookie",name:e.name}}function a(e,t){return[...e].sort((n,r)=>h.indexOf(t[n].kind)-h.indexOf(t[r].kind)||e.indexOf(n)-e.indexOf(r))}function m(e,t){const n=[];for(const r of e??[])for(const i of Object.keys(r))t[i]&&!n.includes(i)&&n.push(i);return n}function H(e,t,n){const r=_(n),i=[];for(const[o,s]of Object.entries(e.paths??{})){if(!s||typeof s!="object")continue;const f=R(r,o);if(f)for(const[p,k]of Object.entries(s)){if(!E.has(p.toLowerCase()))continue;const u=k?.security??e.security;if(u===void 0)continue;const d=m(u,t);d.length===0&&u.length>0||i.push({pattern:f,path:o,method:p.toUpperCase(),schemes:a(d,t)})}}return i}function R(e,t){if(t.startsWith("/"))return new RegExp(`^${e}${y(t)}/?$`)}function y(e){return e.split(j).map(v).join("[^/]+").replace(/(?<!\/)\/+$/,"")}function _(e){const t=[...new Set(e.map(n=>$(n.url)).filter(Boolean).map(y))];return t.length>0?`(?:${t.join("|")})?`:""}function $(e){if(!e)return"";const t=e.replace(/^[a-z][a-z0-9+.-]*:\/\//i,""),n=t.indexOf("/");return n===-1?"":t.slice(n).split(/[?#]/)[0].replace(/(?<!\/)\/+$/,"")}function v(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function O(e){return typeof e=="object"&&e!==null&&"type"in e}export{l as DEFAULT_SCHEME_NAME,L as credentialHeadersOf,U as operationsForScheme,N as orderedSchemesOf,M as resolveUpstreamApiAuth};
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import{McpServer as
|
|
1
|
+
import{McpServer as C}from"@modelcontextprotocol/server";import{logger as S}from"../../../tools/notifiers/logger.js";import{mcpToolWorkers as O,MCP_TOOL_WORKER_KEY as _}from"../../../workers/mcp-tool-worker-pool.js";import{secretStore as L}from"../gateway-mcp/secret-store.js";import{readAuthRequiredMeta as D,stripAuthRequiredMeta as E,upstreamAuthKey as b}from"../gateway-mcp/upstream-auth.js";import{acceptedCredentialsLink as K,buildCredentialsAcceptedHint as j,buildCredentialsToolHint as F,buildUpstreamCredentialFallback as q,buildUpstreamCredentialInputRequired as v,credentialElicitationAnswer as H,dedupeElicitation as N,isStatelessRequest as P,schemeLabelOf as $,supportsUrlElicitation as B}from"../gateway-mcp/elicitation.js";import{DEFAULT_SCHEME_NAME as y,resolveUpstreamApiAuth as G}from"../gateway-mcp/upstream-auth-scheme.js";import{MISSING_SESSION_HANDLE_MESSAGE as V,resolveSecretSubject as W}from"../gateway-mcp/subject.js";const Y=6e4;function ue(e,t){return new C({name:e,version:new Date().toISOString().slice(0,10)},{capabilities:{logging:{}},...t?{instructions:t}:{}})}function le(e,t){return r=>async(n,s)=>{S.info(`MCP tool called: ${r}`);const i=e.elicitationEnabled??!1,c=P(s.mcpReq),a=i?W(e.user,n.sessionHandle):{kind:"anonymous"},o=a.kind==="resolved"?a.subject:void 0;if(a.kind==="invalid")return{content:[{type:"text",text:a.message}],isError:!0};const u=async()=>{if(!(!i||!o||!t?.getKv))try{const m=await t.getKv();return await L.getSecretsForSubject(m,o)}catch(m){S.warn(`gateway mcp secret store error, continuing unauthenticated: ${String(m)}`);return}};let l;const p=async()=>{l=await u();const m={toolName:r,args:n,context:{...e,upstreamSecrets:l},extra:ee(s)};return await O.exec(_,[m],{timeout:Y})};let d=await p();const f=D(d);if(f.length>0&&i&&!o)return E(I(d,[{type:"text",text:V}]));if(f.length>0&&i&&o&&t?.getKv){S.info(`gateway mcp credentials prompt: era=${c?"2026-07-28":"2025"} clientElicitation=${J(t)}`);const m=await t.getKv(),h=await Q(e,f),w=f.map(U=>X(U,h)),k=Z(l),g=c?await x(e,s,w,o,m,k,h,t):await z(e,w,o,m,k,h);switch(g.kind){case"inputRequired":return g.result;case"retry":d=await p();break;case"prependText":d=I(d,[{type:"text",text:g.text},...d.content]);break;case"none":break}}return E(d)}}function I(e,t){const{structuredContent:r,...n}=e;return{...n,content:t,isError:!0}}function J(e){const t=e?.getClientCapabilities()?.elicitation;if(!t)return"none";const r=[t.form?"form":void 0,t.url?"url":void 0].filter(Boolean);return r.length>0?r.join("+"):"none"}async function Q(e,t){const r=new Map;for(const n of new Set(t.map(s=>s.api)))r.set(n,await G(e,n));return r}function X(e,t){const r=t.get(e.api);if(!r)return{...e,scheme:e.scheme??y};const n=e.scheme&&r.schemes[e.scheme]?e.scheme:r.defaultScheme;return{...e,scheme:n}}function Z(e){const t=new Set;for(const[r,n]of Object.entries(e??{}))for(const s of Object.keys(n))t.add(b({api:r,scheme:s}));return t}function R(e,t){return e.status===401&&!t.has(b(e))}function T(e,t){const r=t.get(e.api),n=e.sentScheme??e.scheme;return r&&n?$(r.schemes,n):void 0}function M(e,t){return e.map(r=>F(r,T(r,t))).join(`
|
|
2
2
|
|
|
3
|
-
`)}function
|
|
4
|
-
|
|
5
|
-
`)}function _(e,t,r,n,s){const[i,...u]=t,o=s.get(i.api),l=i.scheme??o?.defaultScheme??T,d=A(i,s);return{subject:r,baseUrl:e.baseUrl??"",target:{api:i.api,name:i.name,scheme:l,...d?{schemeLabel:d}:{}},auth:o?.schemes[l]??{kind:"raw"},...o?{apiAuth:o}:{},kv:n,hasExistingSecret:!1,reason:{kind:"authFailure",status:i.status,...i.detail?{detail:i.detail}:{},otherApiNames:u.map(c=>c.name)}}}async function ne(e,t,r,n,s,i,u,o){const l=v(t.mcpReq.inputResponses);if(l==="declined")return{kind:"none"};const d=r.filter(a=>R(a,i));if(d.length===0)return{kind:"prependText",text:w(r,u)};if(l==="accepted"){const a=await K(t.mcpReq.requestState(),{kv:s,subject:n,baseUrl:e.baseUrl??"",apis:d.map(p=>p.api)}),m=a?.apiName??d[0].name;return{kind:"prependText",text:N(m,a?.url)}}const c=d.filter(a=>C(a,u));if(c.length>0){const a=r.filter(m=>!c.includes(m));return{kind:"prependText",text:U(c,a,u)}}const f=_(e,d,n,s,u);return W(o?.getClientCapabilities())?{kind:"inputRequired",result:await B(f)}:{kind:"prependText",text:await y(f)}}async function ie(e,t,r,n,s,i){const u=t.filter(c=>R(c,s));if(u.length===0)return{kind:"prependText",text:w(t,i)};const o=u.filter(c=>C(c,i));if(o.length>0){const c=t.filter(f=>!o.includes(f));return{kind:"prependText",text:U(o,c,i)}}const l=_(e,u,r,n,i);return{kind:"prependText",text:await x(`${r}:${b(u[0])}`,()=>y(l))}}function se(e){return{sessionId:e.sessionId,authInfo:e.http?.authInfo,requestId:e.mcpReq.id,_meta:e.mcpReq._meta}}function ge(e){return{user:e.user,config:e.config,outdir:e.outdir,baseUrl:e.baseUrl,params:e.params,query:e.query,cookies:e.cookies,apiDescriptionsMap:e.apiDescriptionsMap,graphqlDescriptions:e.graphqlDescriptions,products:e.products,accessToken:e.accessToken,metadata:e.metadata,upstreamAuthorization:e.upstreamAuthorization,mcpMode:e.mcpMode,elicitationEnabled:e.elicitationEnabled,gatewayFetchBudgetPerExec:e.gatewayFetchBudgetPerExec,clientIp:e.clientIp,client:e.client,clientVersion:e.clientVersion,requestId:e.requestId,messageId:e.messageId,upstreamSecrets:e.upstreamSecrets,searchIgnoredRoutes:e.searchIgnoredRoutes,internalBaseUrl:e.internalBaseUrl,sandboxToolSchemas:e.sandboxToolSchemas,fs:void 0}}export{fe as createMcpServer,he as createToolDispatch,ge as extractSerializableContext};
|
|
3
|
+
`)}function A(e,t,r,n,s){const[i,...c]=t,a=s.get(i.api),o=i.scheme??a?.defaultScheme??y,l=(i.schemes?.length??0)<=1?T(i,s):void 0;return{subject:r,baseUrl:e.baseUrl??"",target:{api:i.api,name:i.name,scheme:o,...l?{schemeLabel:l}:{}},auth:a?.schemes[o]??{kind:"raw"},...a?{apiAuth:a}:{},kv:n,hasExistingSecret:!1,reason:{kind:"authFailure",status:i.status,...i.detail?{detail:i.detail}:{},otherApiNames:c.map(p=>p.name)}}}async function x(e,t,r,n,s,i,c,a){const o=H(t.mcpReq.inputResponses);if(o==="declined")return{kind:"none"};const u=r.filter(p=>R(p,i));if(u.length===0)return{kind:"prependText",text:M(r,c)};if(o==="accepted"){const p=await K(t.mcpReq.requestState(),{kv:s,subject:n,baseUrl:e.baseUrl??"",apis:u.map(f=>f.api)}),d=p?.apiName??u[0].name;return{kind:"prependText",text:j(d,p?.url)}}const l=A(e,u,n,s,c);return B(a?.getClientCapabilities())?{kind:"inputRequired",result:await v(l)}:{kind:"prependText",text:await q(l)}}async function z(e,t,r,n,s,i){const c=t.filter(u=>R(u,s));if(c.length===0)return{kind:"prependText",text:M(t,i)};const a=A(e,c,r,n,i);return{kind:"prependText",text:await N(`${r}:${b(c[0])}`,()=>q(a))}}function ee(e){return{sessionId:e.sessionId,authInfo:e.http?.authInfo,requestId:e.mcpReq.id,_meta:e.mcpReq._meta}}function pe(e){return{user:e.user,config:e.config,outdir:e.outdir,baseUrl:e.baseUrl,params:e.params,query:e.query,cookies:e.cookies,apiDescriptionsMap:e.apiDescriptionsMap,graphqlDescriptions:e.graphqlDescriptions,products:e.products,accessToken:e.accessToken,metadata:e.metadata,upstreamAuthorization:e.upstreamAuthorization,mcpMode:e.mcpMode,elicitationEnabled:e.elicitationEnabled,gatewayFetchBudgetPerExec:e.gatewayFetchBudgetPerExec,clientIp:e.clientIp,client:e.client,clientVersion:e.clientVersion,requestId:e.requestId,messageId:e.messageId,upstreamSecrets:e.upstreamSecrets,searchIgnoredRoutes:e.searchIgnoredRoutes,internalBaseUrl:e.internalBaseUrl,sandboxToolSchemas:e.sandboxToolSchemas,fs:void 0}}export{ue as createMcpServer,le as createToolDispatch,pe as extractSerializableContext};
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import
|
|
1
|
+
import r from"react";import t from"styled-components";import{flexRender as g}from"@tanstack/react-table";const w=({headerGroups:e,gridTemplateColumns:i,groupHeaderTitle:l})=>r.createElement(p,null,l&&r.createElement(u,{gridTemplateColumns:i,role:"row"},r.createElement(c,{gridColumn:"1",role:"cell"}),r.createElement(c,{gridColumn:"2 / -1",role:"cell"},r.createElement("span",null,l))),e.map((a,m)=>r.createElement(b,{key:`header-group-${m}`,gridTemplateColumns:i,role:"row"},a.headers.map((o,s)=>{const d=g(o.column.columnDef.header,o.getContext()),n=o.column.getIsSorted();return r.createElement(x,{key:o.id,gridColumn:s+1,$sortable:o.column.getCanSort(),role:"columnheader","aria-sort":n==="asc"?"ascending":n==="desc"?"descending":void 0},o.column.getCanSort()?r.createElement(f,{type:"button",onClick:o.column.getToggleSortingHandler()},d,r.createElement(h,{"aria-hidden":"true"},n?n==="desc"?"\u25BE":"\u25B4":"\u21D5")):d)})))),p=t.div`
|
|
2
2
|
border: 1px solid var(--border-color-primary);
|
|
3
3
|
min-width: 775px;
|
|
4
|
-
`,
|
|
4
|
+
`,u=t.div`
|
|
5
5
|
display: grid;
|
|
6
6
|
grid-template-columns: ${e=>e.gridTemplateColumns};
|
|
7
7
|
width: 100%;
|
|
8
8
|
min-width: 775px;
|
|
9
|
-
`,
|
|
9
|
+
`,c=t.div`
|
|
10
10
|
padding: 5px 15px;
|
|
11
11
|
background-color: var(--bg-color-raised);
|
|
12
12
|
font-weight: bold;
|
|
@@ -21,12 +21,12 @@ import o from"react";import l from"styled-components";import{flexRender as a}fro
|
|
|
21
21
|
&:nth-child(2) {
|
|
22
22
|
border-bottom: 1px solid var(--border-color-primary);
|
|
23
23
|
}
|
|
24
|
-
`,
|
|
24
|
+
`,b=t.div`
|
|
25
25
|
display: grid;
|
|
26
26
|
grid-template-columns: ${e=>e.gridTemplateColumns};
|
|
27
27
|
width: 100%;
|
|
28
|
-
`,
|
|
29
|
-
padding: 5px 15px;
|
|
28
|
+
`,x=t.div`
|
|
29
|
+
padding: ${({$sortable:e})=>e?"0":"5px 15px"};
|
|
30
30
|
background-color: var(--bg-color-raised);
|
|
31
31
|
font-weight: bold;
|
|
32
32
|
color: var(--text-color-secondary);
|
|
@@ -37,6 +37,19 @@ import o from"react";import l from"styled-components";import{flexRender as a}fro
|
|
|
37
37
|
&:first-child {
|
|
38
38
|
justify-content: flex-start;
|
|
39
39
|
}
|
|
40
|
-
`,
|
|
40
|
+
`,f=t.button`
|
|
41
|
+
display: block;
|
|
42
|
+
width: 100%;
|
|
43
|
+
height: 100%;
|
|
44
|
+
box-sizing: border-box;
|
|
45
|
+
margin: 0;
|
|
46
|
+
padding: 5px 15px;
|
|
47
|
+
border: 0;
|
|
48
|
+
background: none;
|
|
49
|
+
font: inherit;
|
|
50
|
+
color: inherit;
|
|
51
|
+
text-align: inherit;
|
|
52
|
+
cursor: pointer;
|
|
53
|
+
`,h=t.span`
|
|
41
54
|
font-family: monospace;
|
|
42
|
-
`;export{
|
|
55
|
+
`;export{w as GridHeader};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import*as e from"react";import{useState as
|
|
1
|
+
import*as e from"react";import{useState as F}from"react";import N from"styled-components";import{HighlightContext as x}from"@redocly/portal-legacy-ui";import{breakpoints as B,getScorecardColorVariable as L}from"@redocly/theme/core/utils";import{FilterContent as O}from"@redocly/theme/components/Filter/FilterContent";import{FilterPopover as D}from"@redocly/theme/components/Filter/FilterPopover";import{CatalogPageWrapper as I,CatalogPageContent as M,CatalogTitle as R,CatalogDescription as W,CatalogPageDescriptionWrapper as j}from"@redocly/theme/components/CatalogClassic/CatalogClassic";import{useModalScrollLock as $}from"@redocly/theme/core/hooks";import{CatalogClassicActions as H}from"@redocly/theme/components/CatalogClassic/CatalogClassicActions";import{Sidebar as _}from"@redocly/theme/components/Sidebar/Sidebar";import{CardValue as p,CardsWrapper as q,ModeSwitcherTab as z,ModeSwitcherTabs as G,CardRow as J,ProblemsByStatusCardBody as K,ScoreCardStatusCardBody as Q,TableWrap as d,ContentWithDotWrap as U,ScorecardCard as h,ScorecardCardTitle as S,LinkButton as X}from"./index.styles";import{NON_CONFORMANT as T}from"./utils";import{ApiLevel as Y,StatusDistribution as Z}from"./components";import{ApiListView as ee,TeamsView as te,RulesView as re}from"./views";import{useData as ae}from"./useData";function Se(y){const{apis:v,summary:r,problemsByRule:A,nonConformantByTeam:P,sortedStatsByTeam:m,filterTerm:a,setFilterTerm:u,filters:l,scorecardInfo:f,hasTeam:i,hasPublishedAt:V,catalogConfig:E,teamLabel:n,teamProperty:w}=ae(y),b={apis:"APIs",rules:"Rules",...i&&{teams:n}},[C,g]=e.useState(!1),[o,s]=F("apis");return $(C),e.createElement(x.Provider,{value:[a]},e.createElement(I,null,e.createElement(le,{menu:e.createElement(O,{setFilterTerm:u,filters:l,filterTerm:a,filterValuesCasing:E.filterValuesCasing})}),C&&e.createElement(D,{onClose:()=>g(!1),setFilterTerm:u,filterTerm:a,filters:l,filterValuesCasing:E.filterValuesCasing}),e.createElement(H,{onOpenFilter:()=>g(!0),filters:l,filterTerm:a}),e.createElement(M,{id:"scorecard-page-content"},e.createElement(j,null,e.createElement(R,null,"API design scorecard"),e.createElement(W,null,"See the health of your API designs.")),e.createElement(q,null,e.createElement(h,null,e.createElement(S,null,"Scorecard status"),e.createElement(Q,null,e.createElement("div",null,e.createElement(p,null,r.total),e.createElement("br",null),"APIs"),e.createElement("div",null,Object.entries(r.levels).map(([t,c],k)=>e.createElement(U,{key:t},e.createElement(p,{style:{width:"40px",textAlign:"right"}},c),e.createElement(Y,{level:t,colorVariable:L(k,Object.values(r.levels).length)}))))),e.createElement(Z,{summary:r})),i&&e.createElement(h,null,e.createElement(S,null,`${T} APIs by ${n}`),e.createElement(K,null,P.slice(0,4).map((t,c)=>e.createElement(J,{key:c},e.createElement("span",{style:{flex:1,textAlign:"left"}},t.team),e.createElement(p,null,t.levels[T].apis))),m.length>4&&e.createElement(X,{onClick:()=>s("teams")},"See all (",m.length,")")))),e.createElement(G,{"data-component-name":"Scorecard/ModeSwitcherTabs"},Object.keys(b).map(t=>t&&e.createElement(z,{"data-component-name":"Scorecard/ModeSwitcherTab",key:t,isActive:o===t,onClick:()=>s(t)},b[t]))),e.createElement(d,{isActive:o==="apis"},e.createElement(ee,{data:v,levelNames:f.levelNames,hasTeam:i,hasPublishedAt:V,teamLabel:n})),e.createElement(d,{isActive:o==="rules"},e.createElement(re,{data:A})),i&&e.createElement(d,{isActive:o==="teams"},e.createElement(te,{data:m,levelNames:f.levelNames,filters:l,setActiveTab:s,teamLabel:n,teamProperty:w})))))}const le=N(_)`
|
|
2
2
|
display: none;
|
|
3
3
|
|
|
4
|
-
@media screen and (min-width: ${
|
|
4
|
+
@media screen and (min-width: ${B.medium}) {
|
|
5
5
|
display: flex;
|
|
6
6
|
}
|
|
7
7
|
--menu-container-padding-top: 0;
|
|
8
|
-
`;export{
|
|
8
|
+
`;export{Se as ScorecardDashboard};
|
|
@@ -64,4 +64,5 @@ export declare const LevelComplianceCardTitle: import("styled-components/dist/ty
|
|
|
64
64
|
}, never>>> & string;
|
|
65
65
|
export declare const ContentWithDotWrap: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never> & Partial<Pick<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>>> & string;
|
|
66
66
|
export declare const EmojiWrap: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, never> & Partial<Pick<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, never>>> & string;
|
|
67
|
+
export declare const LinkButton: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, keyof import("react").ButtonHTMLAttributes<HTMLButtonElement> | keyof import("react").ClassAttributes<HTMLButtonElement>> & import("react").ClassAttributes<HTMLButtonElement> & import("react").ButtonHTMLAttributes<HTMLButtonElement>, "about" | "accessKey" | "aria-activedescendant" | "aria-atomic" | "aria-autocomplete" | "aria-braillelabel" | "aria-brailleroledescription" | "aria-busy" | "aria-checked" | "aria-colcount" | "aria-colindex" | "aria-colindextext" | "aria-colspan" | "aria-controls" | "aria-current" | "aria-describedby" | "aria-description" | "aria-details" | "aria-disabled" | "aria-dropeffect" | "aria-errormessage" | "aria-expanded" | "aria-flowto" | "aria-grabbed" | "aria-haspopup" | "aria-hidden" | "aria-invalid" | "aria-keyshortcuts" | "aria-label" | "aria-labelledby" | "aria-level" | "aria-live" | "aria-modal" | "aria-multiline" | "aria-multiselectable" | "aria-orientation" | "aria-owns" | "aria-placeholder" | "aria-posinset" | "aria-pressed" | "aria-readonly" | "aria-relevant" | "aria-required" | "aria-roledescription" | "aria-rowcount" | "aria-rowindex" | "aria-rowindextext" | "aria-rowspan" | "aria-selected" | "aria-setsize" | "aria-sort" | "aria-valuemax" | "aria-valuemin" | "aria-valuenow" | "aria-valuetext" | "autoCapitalize" | "autoCorrect" | "autoFocus" | "autoSave" | "children" | "className" | "color" | "content" | "contentEditable" | "contextMenu" | "dangerouslySetInnerHTML" | "datatype" | "defaultChecked" | "defaultValue" | "dir" | "disabled" | "draggable" | "enterKeyHint" | "exportparts" | "form" | "formAction" | "formEncType" | "formMethod" | "formNoValidate" | "formTarget" | "hidden" | "id" | "inert" | "inlist" | "inputMode" | "is" | "itemID" | "itemProp" | "itemRef" | "itemScope" | "itemType" | "key" | "lang" | "name" | "nonce" | "onAbort" | "onAbortCapture" | "onAnimationEnd" | "onAnimationEndCapture" | "onAnimationIteration" | "onAnimationIterationCapture" | "onAnimationStart" | "onAnimationStartCapture" | "onAuxClick" | "onAuxClickCapture" | "onBeforeInput" | "onBeforeInputCapture" | "onBeforeToggle" | "onBlur" | "onBlurCapture" | "onCanPlay" | "onCanPlayCapture" | "onCanPlayThrough" | "onCanPlayThroughCapture" | "onChange" | "onChangeCapture" | "onClick" | "onClickCapture" | "onCompositionEnd" | "onCompositionEndCapture" | "onCompositionStart" | "onCompositionStartCapture" | "onCompositionUpdate" | "onCompositionUpdateCapture" | "onContextMenu" | "onContextMenuCapture" | "onCopy" | "onCopyCapture" | "onCut" | "onCutCapture" | "onDoubleClick" | "onDoubleClickCapture" | "onDrag" | "onDragCapture" | "onDragEnd" | "onDragEndCapture" | "onDragEnter" | "onDragEnterCapture" | "onDragExit" | "onDragExitCapture" | "onDragLeave" | "onDragLeaveCapture" | "onDragOver" | "onDragOverCapture" | "onDragStart" | "onDragStartCapture" | "onDrop" | "onDropCapture" | "onDurationChange" | "onDurationChangeCapture" | "onEmptied" | "onEmptiedCapture" | "onEncrypted" | "onEncryptedCapture" | "onEnded" | "onEndedCapture" | "onError" | "onErrorCapture" | "onFocus" | "onFocusCapture" | "onGotPointerCapture" | "onGotPointerCaptureCapture" | "onInput" | "onInputCapture" | "onInvalid" | "onInvalidCapture" | "onKeyDown" | "onKeyDownCapture" | "onKeyPress" | "onKeyPressCapture" | "onKeyUp" | "onKeyUpCapture" | "onLoad" | "onLoadCapture" | "onLoadStart" | "onLoadStartCapture" | "onLoadedData" | "onLoadedDataCapture" | "onLoadedMetadata" | "onLoadedMetadataCapture" | "onLostPointerCapture" | "onLostPointerCaptureCapture" | "onMouseDown" | "onMouseDownCapture" | "onMouseEnter" | "onMouseLeave" | "onMouseMove" | "onMouseMoveCapture" | "onMouseOut" | "onMouseOutCapture" | "onMouseOver" | "onMouseOverCapture" | "onMouseUp" | "onMouseUpCapture" | "onPaste" | "onPasteCapture" | "onPause" | "onPauseCapture" | "onPlay" | "onPlayCapture" | "onPlaying" | "onPlayingCapture" | "onPointerCancel" | "onPointerCancelCapture" | "onPointerDown" | "onPointerDownCapture" | "onPointerEnter" | "onPointerLeave" | "onPointerMove" | "onPointerMoveCapture" | "onPointerOut" | "onPointerOutCapture" | "onPointerOver" | "onPointerOverCapture" | "onPointerUp" | "onPointerUpCapture" | "onProgress" | "onProgressCapture" | "onRateChange" | "onRateChangeCapture" | "onReset" | "onResetCapture" | "onScroll" | "onScrollCapture" | "onScrollEnd" | "onScrollEndCapture" | "onSeeked" | "onSeekedCapture" | "onSeeking" | "onSeekingCapture" | "onSelect" | "onSelectCapture" | "onStalled" | "onStalledCapture" | "onSubmit" | "onSubmitCapture" | "onSuspend" | "onSuspendCapture" | "onTimeUpdate" | "onTimeUpdateCapture" | "onToggle" | "onTouchCancel" | "onTouchCancelCapture" | "onTouchEnd" | "onTouchEndCapture" | "onTouchMove" | "onTouchMoveCapture" | "onTouchStart" | "onTouchStartCapture" | "onTransitionCancel" | "onTransitionCancelCapture" | "onTransitionEnd" | "onTransitionEndCapture" | "onTransitionRun" | "onTransitionRunCapture" | "onTransitionStart" | "onTransitionStartCapture" | "onVolumeChange" | "onVolumeChangeCapture" | "onWaiting" | "onWaitingCapture" | "onWheel" | "onWheelCapture" | "part" | "popover" | "popoverTarget" | "popoverTargetAction" | "prefix" | "property" | "radioGroup" | "ref" | "rel" | "resource" | "results" | "rev" | "role" | "security" | "slot" | "spellCheck" | "style" | "suppressContentEditableWarning" | "suppressHydrationWarning" | "tabIndex" | "title" | "translate" | "type" | "typeof" | "unselectable" | "value" | "vocab"> & Partial<Pick<import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, keyof import("react").ButtonHTMLAttributes<HTMLButtonElement> | keyof import("react").ClassAttributes<HTMLButtonElement>> & import("react").ClassAttributes<HTMLButtonElement> & import("react").ButtonHTMLAttributes<HTMLButtonElement>, "about" | "accessKey" | "aria-activedescendant" | "aria-atomic" | "aria-autocomplete" | "aria-braillelabel" | "aria-brailleroledescription" | "aria-busy" | "aria-checked" | "aria-colcount" | "aria-colindex" | "aria-colindextext" | "aria-colspan" | "aria-controls" | "aria-current" | "aria-describedby" | "aria-description" | "aria-details" | "aria-disabled" | "aria-dropeffect" | "aria-errormessage" | "aria-expanded" | "aria-flowto" | "aria-grabbed" | "aria-haspopup" | "aria-hidden" | "aria-invalid" | "aria-keyshortcuts" | "aria-label" | "aria-labelledby" | "aria-level" | "aria-live" | "aria-modal" | "aria-multiline" | "aria-multiselectable" | "aria-orientation" | "aria-owns" | "aria-placeholder" | "aria-posinset" | "aria-pressed" | "aria-readonly" | "aria-relevant" | "aria-required" | "aria-roledescription" | "aria-rowcount" | "aria-rowindex" | "aria-rowindextext" | "aria-rowspan" | "aria-selected" | "aria-setsize" | "aria-sort" | "aria-valuemax" | "aria-valuemin" | "aria-valuenow" | "aria-valuetext" | "autoCapitalize" | "autoCorrect" | "autoFocus" | "autoSave" | "children" | "className" | "color" | "content" | "contentEditable" | "contextMenu" | "dangerouslySetInnerHTML" | "datatype" | "defaultChecked" | "defaultValue" | "dir" | "disabled" | "draggable" | "enterKeyHint" | "exportparts" | "form" | "formAction" | "formEncType" | "formMethod" | "formNoValidate" | "formTarget" | "hidden" | "id" | "inert" | "inlist" | "inputMode" | "is" | "itemID" | "itemProp" | "itemRef" | "itemScope" | "itemType" | "key" | "lang" | "name" | "nonce" | "onAbort" | "onAbortCapture" | "onAnimationEnd" | "onAnimationEndCapture" | "onAnimationIteration" | "onAnimationIterationCapture" | "onAnimationStart" | "onAnimationStartCapture" | "onAuxClick" | "onAuxClickCapture" | "onBeforeInput" | "onBeforeInputCapture" | "onBeforeToggle" | "onBlur" | "onBlurCapture" | "onCanPlay" | "onCanPlayCapture" | "onCanPlayThrough" | "onCanPlayThroughCapture" | "onChange" | "onChangeCapture" | "onClick" | "onClickCapture" | "onCompositionEnd" | "onCompositionEndCapture" | "onCompositionStart" | "onCompositionStartCapture" | "onCompositionUpdate" | "onCompositionUpdateCapture" | "onContextMenu" | "onContextMenuCapture" | "onCopy" | "onCopyCapture" | "onCut" | "onCutCapture" | "onDoubleClick" | "onDoubleClickCapture" | "onDrag" | "onDragCapture" | "onDragEnd" | "onDragEndCapture" | "onDragEnter" | "onDragEnterCapture" | "onDragExit" | "onDragExitCapture" | "onDragLeave" | "onDragLeaveCapture" | "onDragOver" | "onDragOverCapture" | "onDragStart" | "onDragStartCapture" | "onDrop" | "onDropCapture" | "onDurationChange" | "onDurationChangeCapture" | "onEmptied" | "onEmptiedCapture" | "onEncrypted" | "onEncryptedCapture" | "onEnded" | "onEndedCapture" | "onError" | "onErrorCapture" | "onFocus" | "onFocusCapture" | "onGotPointerCapture" | "onGotPointerCaptureCapture" | "onInput" | "onInputCapture" | "onInvalid" | "onInvalidCapture" | "onKeyDown" | "onKeyDownCapture" | "onKeyPress" | "onKeyPressCapture" | "onKeyUp" | "onKeyUpCapture" | "onLoad" | "onLoadCapture" | "onLoadStart" | "onLoadStartCapture" | "onLoadedData" | "onLoadedDataCapture" | "onLoadedMetadata" | "onLoadedMetadataCapture" | "onLostPointerCapture" | "onLostPointerCaptureCapture" | "onMouseDown" | "onMouseDownCapture" | "onMouseEnter" | "onMouseLeave" | "onMouseMove" | "onMouseMoveCapture" | "onMouseOut" | "onMouseOutCapture" | "onMouseOver" | "onMouseOverCapture" | "onMouseUp" | "onMouseUpCapture" | "onPaste" | "onPasteCapture" | "onPause" | "onPauseCapture" | "onPlay" | "onPlayCapture" | "onPlaying" | "onPlayingCapture" | "onPointerCancel" | "onPointerCancelCapture" | "onPointerDown" | "onPointerDownCapture" | "onPointerEnter" | "onPointerLeave" | "onPointerMove" | "onPointerMoveCapture" | "onPointerOut" | "onPointerOutCapture" | "onPointerOver" | "onPointerOverCapture" | "onPointerUp" | "onPointerUpCapture" | "onProgress" | "onProgressCapture" | "onRateChange" | "onRateChangeCapture" | "onReset" | "onResetCapture" | "onScroll" | "onScrollCapture" | "onScrollEnd" | "onScrollEndCapture" | "onSeeked" | "onSeekedCapture" | "onSeeking" | "onSeekingCapture" | "onSelect" | "onSelectCapture" | "onStalled" | "onStalledCapture" | "onSubmit" | "onSubmitCapture" | "onSuspend" | "onSuspendCapture" | "onTimeUpdate" | "onTimeUpdateCapture" | "onToggle" | "onTouchCancel" | "onTouchCancelCapture" | "onTouchEnd" | "onTouchEndCapture" | "onTouchMove" | "onTouchMoveCapture" | "onTouchStart" | "onTouchStartCapture" | "onTransitionCancel" | "onTransitionCancelCapture" | "onTransitionEnd" | "onTransitionEndCapture" | "onTransitionRun" | "onTransitionRunCapture" | "onTransitionStart" | "onTransitionStartCapture" | "onVolumeChange" | "onVolumeChangeCapture" | "onWaiting" | "onWaitingCapture" | "onWheel" | "onWheelCapture" | "part" | "popover" | "popoverTarget" | "popoverTargetAction" | "prefix" | "property" | "radioGroup" | "ref" | "rel" | "resource" | "results" | "rev" | "role" | "security" | "slot" | "spellCheck" | "style" | "suppressContentEditableWarning" | "suppressHydrationWarning" | "tabIndex" | "title" | "translate" | "type" | "typeof" | "unselectable" | "value" | "vocab">>> & string;
|
|
67
68
|
//# sourceMappingURL=index.styles.d.ts.map
|
|
@@ -55,7 +55,7 @@ import r from"styled-components";import{Popup as t}from"reactjs-popup";import{Bu
|
|
|
55
55
|
border: 1px solid var(--border-color-primary);
|
|
56
56
|
background-color: var(${o=>o.colorVariable});
|
|
57
57
|
margin-top: 1px;
|
|
58
|
-
`,
|
|
58
|
+
`,u=r.p`
|
|
59
59
|
margin: 16px 0 32px 0;
|
|
60
60
|
font-size: 16px;
|
|
61
61
|
color: var(--text-color-secondary);
|
|
@@ -88,7 +88,7 @@ import r from"styled-components";import{Popup as t}from"reactjs-popup";import{Bu
|
|
|
88
88
|
@media screen and (max-width: 767px) {
|
|
89
89
|
flex-direction: column;
|
|
90
90
|
}
|
|
91
|
-
`,
|
|
91
|
+
`,v=r.input`
|
|
92
92
|
border: var(--filter-input-border);
|
|
93
93
|
min-width: var(--filter-input-min-width);
|
|
94
94
|
width: 100%;
|
|
@@ -197,12 +197,12 @@ import r from"styled-components";import{Popup as t}from"reactjs-popup";import{Bu
|
|
|
197
197
|
text-align: center;
|
|
198
198
|
display: block;
|
|
199
199
|
}
|
|
200
|
-
`,
|
|
200
|
+
`,B=r(i)`
|
|
201
201
|
display: flex;
|
|
202
202
|
flex-direction: row;
|
|
203
203
|
justify-content: space-between;
|
|
204
204
|
gap: 10px;
|
|
205
|
-
`,
|
|
205
|
+
`,E=r.div`
|
|
206
206
|
display: flex;
|
|
207
207
|
flex-direction: row;
|
|
208
208
|
align-items: center;
|
|
@@ -217,4 +217,14 @@ import r from"styled-components";import{Popup as t}from"reactjs-popup";import{Bu
|
|
|
217
217
|
'Noto Color Emoji',
|
|
218
218
|
'EmojiOne Color';
|
|
219
219
|
vertical-align: middle;
|
|
220
|
-
|
|
220
|
+
`,D=r.button.attrs({type:"button"})`
|
|
221
|
+
padding: 0;
|
|
222
|
+
margin: 0;
|
|
223
|
+
border: 0;
|
|
224
|
+
background: none;
|
|
225
|
+
font: inherit;
|
|
226
|
+
font-weight: var(--link-font-weight);
|
|
227
|
+
color: var(--link-color-primary);
|
|
228
|
+
text-align: left;
|
|
229
|
+
cursor: pointer;
|
|
230
|
+
`;export{C as AppPageWrapper,f as CardRow,a as CardValue,b as CardsWrapper,u as CatalogDescription,n as CatalogPageWrapper,W as Code,E as ContentWithDotWrap,m as Dot,M as EmojiWrap,I as FilePreview,g as GaugeNumber,P as GroupTh,T as InstanceControlsWrap,$ as InstanceMessage,z as InstanceReference,j as InstanceWrap,B as LevelComplianceCardTitle,D as LinkButton,y as ModeSwitcherTab,h as ModeSwitcherTabs,x as ProblemsByStatusCardBody,s as ScoreCardStatusCardBody,c as ScorecardCard,i as ScorecardCardTitle,S as SortIcon,v as StyledInput,k as StyledPopup,w as TableWrap};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import*as e from"react";import{useCallback as H,useMemo as b,useState as G,useEffect as _}from"react";import{useLocation as T}from"react-router";import{Flex as U}from"@redocly/portal-legacy-ui";import{Button as x}from"@redocly/theme/components/Button/Button";import{AddIcon as I}from"@redocly/theme/icons/AddIcon/AddIcon";import{SubtractIcon as
|
|
1
|
+
import*as e from"react";import{useCallback as H,useMemo as b,useState as G,useEffect as _}from"react";import{useLocation as T}from"react-router";import{Flex as U}from"@redocly/portal-legacy-ui";import{Button as x}from"@redocly/theme/components/Button/Button";import{AddIcon as I}from"@redocly/theme/icons/AddIcon/AddIcon";import{SubtractIcon as K}from"@redocly/theme/icons/SubtractIcon/SubtractIcon";import{ArrowLeftIcon as D}from"@redocly/theme/icons/ArrowLeftIcon/ArrowLeftIcon";import{getScorecardColorVariable as z,withoutPathPrefix as O}from"@redocly/theme/core/utils";import{Link as P}from"../../../../client/app/Link";import N from"../../../../client/app/CircularProgress";import{isDefined as R}from"../../../../utils/guards/is-defined.js";import{removeLeadingSlash as Z}from"../../../../utils/url/remove-leading-slash.js";import{StatusByLevelWidget as J}from"./StatusByLevelWidget";import{OTHER_TEAMS_LABEL as Q,NON_CONFORMANT as X}from"./utils";import{LevelIndicator as Y}from"./LevelIndicator";import{AppPageWrapper as V,CardValue as v,CardsWrapper as j,CatalogDescription as ee,ModeSwitcherTab as te,ModeSwitcherTabs as re,CardRow as B,ProblemsByStatusCardBody as W,ScoreCardStatusCardBody as F,TableWrap as ne,LevelComplianceCardTitle as le,ContentWithDotWrap as C,ScorecardCard as S,ScorecardCardTitle as L,LinkButton as ae}from"./index.styles";import{ApiLevel as M,InstanceStatus as k,LevelStatus as $,RuleStatus as q}from"./components";import{Grid as A}from"./Grid/Grid";import{useDetailedScorecard as se}from"./useDetailedScorecard";import{Gauge as ce,GaugeValue as oe}from"./Gauge";function Ie(p){const u=T(),{data:d,levelNames:i,hasPublishedAt:n,hasTeam:s,teamLabel:l}=p,f=H((a,o,E)=>{const g=a.getValue(E)?new Date(a.getValue(E)).getTime():0,t=o.getValue(E)?new Date(o.getValue(E)).getTime():0;return g>t?1:-1},[]),m=b(()=>[{id:"title",header:"API",accessorKey:"api.title",size:200,cell:({getValue:a,row:o})=>e.createElement(P,{to:O(u.pathname)+"/apis/"+encodeURIComponent(Z(o.original.api.link))},a())},n?{header:"Published at",accessorKey:"api.publishedAt",sortingFn:f,cell:({getValue:a})=>{const o=a();return o?new Date(o).toLocaleDateString():"-"}}:void 0,s?{header:l,accessorKey:"api.team"}:void 0,{id:"level",header:"Level",accessorKey:"scorecard.scorecardLevel",cell:({getValue:a,row:o})=>e.createElement(M,{level:a(),colorVariable:z(o.original?.scorecard.scorecardLevelIdx,i.length+1)})},...i.map(a=>({id:a,header:`${a}`,accessorKey:"scorecard.levels",cell:({getValue:o,row:E})=>{const g=o(),t=E.original.api.link;return g?.[a]?e.createElement(Y,{key:t,uniqueErrors:g[a].uniqueErrors,uniqueWarnings:g[a].uniqueWarnings,id:t}):null}}))].filter(R),[f,i,u.pathname,n,s,l]);return e.createElement(A,{columns:m,data:d,sortBy:[{id:"title",desc:!1}]})}function Ke(p){const u=T(),{data:d}=p,i=b(()=>[{header:"Rules",accessorKey:"ruleId",cell:({getValue:n})=>e.createElement(P,{to:O(u.pathname)+"/rules/"+encodeURIComponent(n())},n())},{id:"status",header:"Status",accessorKey:"status",size:200,cell:({row:n})=>e.createElement(q,{errors:n.original.errorApisCount,warnings:n.original.warningApisCount})},{header:"Problem APIs",size:200,accessorKey:"apis",cell:({getValue:n})=>n().length,sortDescFirst:!0},{header:"Problem count",size:200,accessorKey:"count",sortDescFirst:!0}],[u.pathname]);return e.createElement(A,{columns:i,data:d,sortBy:[{id:"status",desc:!0}]})}function De(p){const{data:u,levelNames:d,filters:i,setActiveTab:n,teamLabel:s,teamProperty:l}=p,f=b(()=>[{id:"team",header:`API ${s}`,accessorKey:"team",size:200,cell:({getValue:m})=>e.createElement(ae,{onClick:()=>{n("apis"),i.find(a=>a.property===l)?.selectOption(m())}},m())},...[X,...d].map(m=>({id:m,header:`${m}`,accessorFn:a=>a.levels[m]?.apis}))],[i,d,n,s,l]);return e.createElement(A,{columns:f,data:u,sortBy:[{id:"team",desc:!1}],groupHeaderTitle:"APIs by level"})}function ie(p){const{data:u,title:d}=p,i=b(()=>[{id:"expand",maxSize:40,size:40,header:()=>null,enableSorting:!1,cell:({row:n})=>n.getCanExpand()?e.createElement(x,{onClick:n.getToggleExpandedHandler(),variant:"text",size:"medium",icon:n.getIsExpanded()?e.createElement(K,null):e.createElement(I,null)}):null},{header:"Rules",accessorKey:"ruleId",cell:({getValue:n,row:s})=>s.getCanExpand()?e.createElement("span",{onClick:s.getToggleExpandedHandler()},n()):null},{header:"Status",accessorKey:"status",size:200,cell:({getValue:n})=>{const s=n();return e.createElement(q,{errors:s?.errorsCount,warnings:s?.warningsCount})},enableSorting:!1},{header:"Problem count",accessorKey:"problemsCount",size:200,sortDescFirst:!0}],[]);return e.createElement(A,{columns:i,data:u,sortBy:[{id:"ruleId",desc:!1}],empty:e.createElement(e.Fragment,null,"\u2705 This API is compliant with ",e.createElement("strong",null,d)," level rules"),subRowKey:"problems"})}function ze(p){const{catalogSlug:u,slug:d,data:i,hasTeam:n,hasPublishedAt:s,teamLabel:l}=p,{apis:f,apisCount:m,warningApisCount:a,errorApisCount:o,levels:E,count:g}=i,t=f.length===0,h=t?void 0:{id:"expand",maxSize:40,size:40,header:()=>null,enableSorting:!1,cell:({row:r})=>r.getCanExpand()?e.createElement(x,{onClick:r.getToggleExpandedHandler(),variant:"text",size:"medium",icon:r.getIsExpanded()?e.createElement(K,null):e.createElement(I,null)}):null},w=b(()=>[h,{header:"API",accessorKey:"title"},s?{header:"Published at",accessorKey:"publishedAt",cell:({getValue:r})=>{const c=r();return c?new Date(c).toLocaleDateString():"-"}}:void 0,n?{header:l,accessorKey:"team",cell:({getValue:r})=>r()||Q}:void 0,{header:"Problem count",size:200,accessorKey:"count",cell:({getValue:r})=>r()||0,sortDescFirst:!0}].filter(R),[n,s,l,t]),y=b(()=>Object.entries(i.teams).sort((r,c)=>c[1]-r[1]),[i.teams]);return e.createElement(V,null,e.createElement(x,{icon:e.createElement(D,null),iconPosition:"left",variant:"ghost",size:"large",to:`${u}scorecard`},"Back to dashboard"),e.createElement("h1",null,"Rule ",d),e.createElement(j,null,e.createElement(S,null,e.createElement(L,null,"Rule status"),e.createElement(F,null,e.createElement("div",null,e.createElement(v,null,m),e.createElement("br",null),"APIs"),e.createElement("div",null,e.createElement(C,null,e.createElement(v,{style:{textAlign:"right"}},m-a-o),e.createElement(k,{severity:"Pass"})),e.createElement(C,null,e.createElement(v,{style:{textAlign:"right"}},a),e.createElement(k,{severity:"Warn"})),e.createElement(C,null,e.createElement(v,{style:{textAlign:"right"}},o),e.createElement(k,{severity:"Error"}))))),e.createElement(S,null,e.createElement(L,null,"Problems by level"),e.createElement(W,null,Object.entries(E).map(([r,c])=>e.createElement(B,{key:r},e.createElement("span",null,r),e.createElement(ce,{chunks:[{share:c.errors/g*100,colorVariable:"--scorecard-color-error"},{share:c.warnings/g*100,colorVariable:"--scorecard-color-warning"}]}),e.createElement(oe,null,c.errors+c.warnings))))),e.createElement(S,null,e.createElement(L,null,`Problems by ${l}`),e.createElement(W,null,y.slice(0,4).map(([r,c])=>e.createElement(B,{key:r},e.createElement("span",{style:{flex:1,textAlign:"left"}},r),e.createElement(v,null,c)))))),e.createElement(A,{columns:w,data:f,sortBy:[{id:"title",desc:!1}],subRowKey:"problems",slug:d}))}function Oe(p){const{slug:u,api:d,teamLabel:i,catalogSlug:n}=p,{api:s}=d||{},{scorecard:l,isLoading:f}=se(`/${u}`),m=l?.levels||{},[a,o]=G(Object.keys(m)[0]),E=b(()=>s?.publishedAt instanceof Date?s?.publishedAt.toLocaleDateString():s?.publishedAt,[s]);_(()=>{if(l){const t=l.levels||{};o(Object.keys(t)[0])}},[l]);const g=b(()=>{if(!l?.levels)return{};const t={};for(const h of Object.keys(l.levels)){const w=l.levels[h].problems.reduce((y,r)=>(y[r.ruleId]||(y[r.ruleId]=[]),y[r.ruleId].push(r),y),{});t[h]=Object.entries(w).map(([y,r])=>({ruleId:y,problems:[...r.filter(c=>c.severity==="error"),...r.filter(c=>c.severity==="warn")],problemsCount:r.length,status:{errorsCount:r.filter(c=>c.severity==="error").length,warningsCount:r.filter(c=>c.severity==="warn").length}}))}return t},[l?.levels]);return f?e.createElement(U,{justifyContent:"center",mt:"2em"},e.createElement(N,null)):l?e.createElement(V,null,e.createElement(x,{icon:e.createElement(D,null),iconPosition:"left",variant:"ghost",size:"large",to:`${n}scorecard`},"Back to dashboard"),e.createElement("h1",null,s?.title||u),e.createElement(ee,null,E&&e.createElement(e.Fragment,null,"Published at: ",new Date().toLocaleString(void 0,{timeZoneName:"short"}),e.createElement("br",null)),e.createElement(P,{to:u,external:!0},"Documentation")),e.createElement(j,null,e.createElement(S,null,e.createElement(le,null,e.createElement("span",null,"Scorecard level"),e.createElement(M,{level:l.scorecardLevel,colorVariable:z(l.scorecardLevelIdx,Object.keys(m).length)})),e.createElement(F,null,e.createElement("div",null,"Compliance by level"),e.createElement("div",null,Object.entries(l.levels).map(([t,h])=>e.createElement(C,{key:t},e.createElement(v,{style:{width:"100px",textAlign:"right"}},t),e.createElement($,{errors:h.errors,warnings:h.warnings})))))),e.createElement(J,{title:"Rules compliance",levels:Object.entries(l.levels).map(([t,h])=>({errors:h.uniqueErrors,warnings:h.uniqueWarnings,total:p.rulesPerLevel[t].length,name:t}))}),e.createElement(S,null,e.createElement(L,null,i),e.createElement(v,{style:{fontWeight:"normal"}},s?.team))),e.createElement(re,{style:{justifyContent:"flex-start"},"data-component-name":"Scorecard/ModeSwitcherTabs"},Object.keys(l.levels).map(t=>e.createElement(te,{"data-component-name":"Scorecard/ModeSwitcherTab",key:t,isActive:a===t,onClick:()=>o(t)},e.createElement(C,null,e.createElement("span",null,t)," ",e.createElement($,{errors:l.levels[t].errors,warnings:l.levels[t].warnings}))))),Object.keys(m).map(t=>e.createElement(ne,{key:t,isActive:a===t},e.createElement(ie,{title:t,data:g[t]})))):e.createElement("div",null,"Scorecard not found")}export{Ie as ApiListView,Oe as ApiPage,ie as ApiView,ze as RuleView,Ke as RulesView,De as TeamsView};
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{readdir as S,appendFile as A}from"node:fs/promises";import l from"node:path";import{createReadStream as v,existsSync as w}from"node:fs";import{createInterface as O}from"node:readline";import{SEARCH_GROUP_FACET_FIELD as C,SEARCH_PRODUCT_FIELD as N,SEARCH_VERSION_FIELD as j}from"../../../../../constants/common.js";import{SEARCH_INDEX_FIELDS as H,SEARCH_DATA_EXPORT_FOLDER as g,SEARCH_MAX_INMEMORY_DOCUMENTS_COUNT as L}from"../../../../constants/plugins/search.js";import{telemetryTraceStep as T}from"../../../../telemetry/helpers/trace-step.js";import{envConfig as M}from"../../../../config/env-config.js";import{ensureDir as u}from"../../../../utils/index.js";import{FlexSearchIndex as b}from"./search-index.js";const F=".jsonl";function R(m){return`${JSON.stringify(m)}
|
|
2
|
+
`}async function*P(m){const t=O({input:v(m,{encoding:"utf8"}),crlfDelay:1/0});for await(const s of t)s&&(yield JSON.parse(s))}class K{#e=new Map;#s;#t=0;async initIndexSchema(t){this.#s={document:{id:"id",tag:"tags",index:H},worker:!1,tokenize:"forward",context:{depth:2,resolution:9}}}#i(t,s){const n=this.#e.get(t);if(n)return n.find(i=>i.id===s)}#n(t,s){let n=this.#i(t,s);return n||(n=new b(s,this.#s),this.#e.set(t,[...this.#e.get(t)??[],n])),n}async addDocuments(t,s){if(t.length){const{group:n,locale:i,outDir:c}=s,o=this.#n(i,n);for(const r of t)o.add(r),M.isBuildMode&&(this.#t++,this.#t>=L&&await this.exportDocuments(c))}}getIndexesSize(){return this.#e.size}async search(t,s,n){return await T("com.redocly.search.performed",async i=>{i?.setAttribute("id","searchQueryId"),i?.setAttribute("object","searchQuery"),i?.setAttribute("uri","urn:redocly:realm:api:searchQuery:searchQueryId");const{query:c,locale:o,filter:r,loadMore:a}=t,d=this.#e.get(o)??[];let h=[],D="",y=["v:default"];if(i?.setAttribute("locale",o),r)for(const e of r)e.field===C?h=[...h,...e.values]:e.field===N?D=`p:${e.values[0]}`:e.field===j&&e.values.length&&e.values.length===2&&(y=[...y,`v:${e.values[0]}:${e.values[1]}`]);const _={auth:s,query:c,offset:0,SEARCH_GROUP_FACET_FIELD:C,product:D,versions:y},x=[];let f={facets:{},documents:{}};if(a){const e=this.#i(o,a.groupKey);e&&x.push(e.search({..._,offset:a.offset}))}else for(const e of d)h&&h.length?h.includes(e.id)&&x.push(e.search(_)):x.push(e.search(_));const E=await Promise.all(x),$=E.some(e=>e.hasCoveringHit);for(const e of E)if(!($&&!e.hasCoveringHit)){f.documents={...f.documents,...e.documents};for(const[p,I]of Object.entries(e.facets))f.facets[p]?f.facets[p]=[...f.facets[p],...I]:f.facets[p]=I}return f})}async exportDocuments(t){const s=u(l.join(t,g));for(const[n,i]of this.#e){const c=u(l.join(s,n));for(const o of i){const r=Array.from(o.documents,d=>R({document:d}));if(r.length===0)continue;const a=u(l.join(c,`${o.id}${F}`));await A(a,r.join(""),{encoding:"utf8"}),o.clearDocuments()}}this.#t=0}async exportIndexes(t){const s=u(l.join(t,g));for(const[n,i]of this.#e){const c=u(l.join(s,n));for(const o of i){const r=u(l.join(c,`${o.id}${F}`));await o.export((a,d)=>A(r,R({index:[String(a),d]}),{encoding:"utf8"}))}}this.#e.clear()}async import(t){const s=`${t}/${g}`;if(!w(s))return;const n=await S(s);for(const i of n){const c=await S(`${s}/${i}`);for(const o of c){const r=`${s}/${i}/${o}`,a=l.parse(o).name;await this.#n(i,a).import(P(r))}}}countFacets(t,s,n){const i={};for(const[c,o]of n)i[c]=o.values.map(r=>({value:r,count:0,isCounterVisible:!1}));return i}cleanupFacetValues(t){}}export{K as FlexSearch};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ExportHandler, IndexOptionsForDocumentSearch } from 'flexsearch';
|
|
2
|
-
import type {
|
|
2
|
+
import type { FlexSearchDataEntry, IndexedSearchDocument, SearchIndex, SearchParameters, SearchDocument } from '../../../../types';
|
|
3
3
|
import type { SearchResponse } from '../../../../../types/index.js';
|
|
4
4
|
/** One group's results plus whether any of them holds every query word in a single value. */
|
|
5
5
|
export type IndexSearchResponse = SearchResponse & {
|
|
@@ -13,7 +13,7 @@ export declare class FlexSearchIndex implements SearchIndex {
|
|
|
13
13
|
get documentsCount(): number;
|
|
14
14
|
clearDocuments(): void;
|
|
15
15
|
export(handler: ExportHandler<string | IndexedSearchDocument>): Promise<void>;
|
|
16
|
-
import(
|
|
16
|
+
import(entries: AsyncIterable<FlexSearchDataEntry>): Promise<void>;
|
|
17
17
|
add(document: SearchDocument): void;
|
|
18
18
|
search(params: SearchParameters): Promise<IndexSearchResponse>;
|
|
19
19
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import _ from"flexsearch";import{REDOCLY_TEAMS_RBAC as L}from"@redocly/config";import{DISABLE_DEEP_LINK_IF_FIELDS_EXIST as
|
|
1
|
+
import _ from"flexsearch";import{REDOCLY_TEAMS_RBAC as L}from"@redocly/config";import{DISABLE_DEEP_LINK_IF_FIELDS_EXIST as C,SEARCH_LIMIT as R}from"../../../../constants/plugins/search.js";import{telemetryTraceStep as b}from"../../../../telemetry/helpers/trace-step.js";import{highlightTextForSearch as m,markMatchedValue as D}from"../../../../utils/search/highlight-text-for-search.js";import{MIN_QUERY_WORD_LENGTH as M,containsQueryWord as S,matchableQueryWords as j}from"../../../../utils/search/text-match.js";function k(I){const{name:e,description:t,place:s,path:i,deepLink:r,example:n,enum:a}=I,o=r?.indexOf("#")??-1;return{name:e,description:t,place:s,...i&&{path:i},...r&&{deepLink:o>=0?r.slice(o+1):r},example:n,enum:a}}class T{#t;#e=new Map;#s=1;id;constructor(e,t){this.id=e,this.#t=new _.Document(t)}get documents(){return this.#e.entries()}get documentsCount(){return this.#s}clearDocuments(){this.#e.clear()}async export(e){await this.#t.export(e)}async import(e){this.#e.clear();for await(const t of e)if("document"in t){const[s,i]=t.document;this.#e.set(s,i)}else{const[s,i]=t.index;await this.#t.import(s,i)}}add(e){const t={...e,tags:e.tags??[],[L]:e[L],...e.parameters&&{parameters:e.parameters.map(k)}};this.#e.set(this.#s,t),this.#t.add(this.#s,t),this.#s++}async search(e){return await b("com.redocly.search.performed",async t=>{t?.setAttribute("id","searchQueryId"),t?.setAttribute("object","searchQuery"),t?.setAttribute("uri","urn:redocly:realm:api:searchQuery:searchQueryId");const{query:s,offset:i,auth:r,product:n,versions:a}=e,o=[],l=r.teams,p={limit:R,offset:i},c=this.#r(s);if(!c.length&&s.trim())return{documents:{[this.id]:[]},facets:{},hasCoveringHit:!1};let d=new Map,g=await this.#t.searchAsync(s,{...p,tag:l});if(n){const h=await this.#t.searchAsync(s,{...p,tag:n});g=this.#a(g,h),t?.setAttribute("product",n)}if(a&&a.length){const h=await this.#t.searchAsync(s,{...p,tag:a});g=this.#a(g,h),t?.setAttribute("versions",a.join(","))}for(const h of g)for(const u of h.result){const f=d.get(u)?.fields||[];d.set(u,{fields:h.field?[...f,h.field]:[...f]})}!i&&c.length&&!d.size&&(d=this.#l(c,l,n,a));const x=[];for(const[h,u]of d.entries()){const f=this.#e.get(h);f&&!this.#d(f,a)&&x.push({document:f,fields:u.fields,score:this.#m(c,f)})}const y=x.filter(h=>h.score>=c.length),A=y.length?y:x;A.sort((h,u)=>u.score-h.score);for(const h of A.slice(0,R))o.push({document:this.#o(h.document,s,h.fields),highlight:this.#h(h.document,s,h.fields)});return{documents:{[this.id]:o},facets:{},hasCoveringHit:y.length>0}})}#o(e,t,s){return this.#g(e,t,s)}#h(e,t,s){const i={};let r=!1;for(const n of s)if(n==="path")i.path=e.path?e.path.map(a=>m(t,a)):[];else if(n.includes("parameters")){if(!r){const a=n.split(":")[1],o=this.#n(t,a,e.parameters);o&&(i.parameters=[{name:m(t,o.name),description:m(t,o.description),place:m(t,o.place),path:o.path?o.path.map(l=>m(t,l)):[],...this.#c(t,o)}],r=!0)}}else n!=="httpMethod"&&(i[n]=m(t,e[n]));return i}#c(e,t){return{enum:D(e,(t.enum??[]).join(", ")),example:D(e,t.example??"")}}#r(e){return j(e)}#l(e,t,s,i){const r=new Map;if(!e.length)return r;for(const[n,a]of this.#e)this.#p(a,t,s,i)&&this.#f(e,a)&&r.set(n,{fields:this.#u(e,a)});return r}#f(e,t){const s=i=>{if(i==null)return!1;const r=(Array.isArray(i)?i.join(" "):String(i)).toLowerCase();return!!r&&e.every(n=>S(r,n))};return s(t.title)||s(t.text)||s(t.httpPath)||s(t.path)?!0:(t.parameters??[]).some(i=>s(i.name)||s(i.description)||s(i.example)||s(i.enum))}#p(e,t,s,i){const r=new Set(e.tags??[]);return!(t.length&&!t.some(n=>r.has(n))||s&&!r.has(s)||i&&i.length&&!i.some(n=>r.has(n)))}#u(e,t){const s=r=>{if(r==null)return!1;const n=(Array.isArray(r)?r.join(" "):String(r)).toLowerCase();return e.some(a=>S(n,a))},i=[];s(t.title)&&i.push("title"),s(t.text)&&i.push("text"),s(t.path)&&i.push("path"),t.httpMethod&&e.some(r=>r.length>=M&&t.httpMethod?.toLowerCase().startsWith(r))&&i.push("httpMethod"),s(t.httpPath)&&i.push("httpPath");for(const r of["name","description","path","example","enum"])t.parameters?.some(n=>s(n[r]))&&i.push(`parameters[]:${r}`);return i}#i(e,t){const s=t.toLowerCase().replace(/\s+/g," "),i=e.filter(n=>S(s,n)).length;let r=0;for(let n=1;n<e.length;n++)s.includes(`${e[n-1]} ${e[n]}`)&&r++;return i+r/e.length}#m(e,t){let s=0;const i=r=>{if(r==null)return;const n=this.#i(e,String(r));n>s&&(s=n)};if(i(t.title),i(t.text),i(t.httpPath),i(t.path?.join(" ")),t.httpMethod){const r=t.httpMethod.toLowerCase(),n=e.filter(a=>a.length>=M&&r.startsWith(a)).length;n>s&&(s=n)}for(const r of t.parameters??[])i([r.name,r.description,r.place,r.example,r.enum?.join(" ")].filter(Boolean).join(" "));return s}#n(e,t,s){const i=this.#r(e);let r,n=0;for(const a of s??[]){const o=a[t],l=(Array.isArray(o)?o:[o]).filter(c=>c!=null).map(c=>String(c)).join(" "),p=this.#i(i,l);p>n&&(n=p,r=a)}return r}#a(e,t){const s=[];for(const i of e){const r=[];for(const n of t)for(const a of i.result){const o=n.result.find(l=>l===a);o&&r.push(o)}r.length&&s.push({result:r,field:i.field})}return s}#d(e,t){return!!(t&&t.length&&e.isDefaultVersion&&e.versionFolderId&&e.version&&t.some(s=>s.includes(e.versionFolderId??""))&&!t.some(s=>s.includes(e.version??"")))}#g(e,t,s){for(const r of C)if(s.some(n=>n===r))return e;let i;for(const r of s)if(r.includes("parameters")){const n=r.split(":")[1],a=this.#n(t,n,e.parameters);if(a){i=a.deepLink;break}}return i?{...e,url:`${e.url}#${i}`}:e}}export{T as FlexSearchIndex};
|
|
@@ -31,7 +31,7 @@ export type SearchIndex = {
|
|
|
31
31
|
add(document: SearchDocument): void;
|
|
32
32
|
search(params: SearchParameters): Promise<SearchResponse>;
|
|
33
33
|
export(handler: ExportHandler<string | IndexedSearchDocument>): void;
|
|
34
|
-
import(
|
|
34
|
+
import(entries: AsyncIterable<FlexSearchDataEntry>): Promise<void>;
|
|
35
35
|
clearDocuments(): void;
|
|
36
36
|
};
|
|
37
37
|
export type AddDocumentsParams = {
|
|
@@ -39,9 +39,11 @@ export type AddDocumentsParams = {
|
|
|
39
39
|
locale: string;
|
|
40
40
|
outDir: string;
|
|
41
41
|
};
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
/** One line of an exported FlexSearch group file: a stored document or one FlexSearch export key. */
|
|
43
|
+
export type FlexSearchDataEntry = {
|
|
44
|
+
document: [number, IndexedSearchDocument];
|
|
45
|
+
} | {
|
|
46
|
+
index: [string, string];
|
|
45
47
|
};
|
|
46
48
|
export type TypesenseSearchData = {
|
|
47
49
|
documents: SearchDocument[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{DEFAULT_SEARCH_ENGINE as
|
|
1
|
+
import{DEFAULT_SEARCH_ENGINE as o}from"@redocly/config";import{logger as e}from"../../tools/notifiers/logger.js";import{SearchEngine as h}from"../../plugins/search/engines/search-engine.js";function l(a){let i;const c=async()=>{e.info("Loading search data...");const t=e.startTiming();try{const n=a.config?.search?.engine??o,r=new h(n,a.globalData.l10n);await r.initIndexSchema(a.searchFacets),await r.import(a.outdir),a.setSearchEngine(r),e.infoTime(t,"Search data loaded")}catch(n){throw e.error("Failed to load search data: %s",n),n}};return async(t,n)=>{!a.searchEngine&&!a.config?.search?.hide&&(i??=c().finally(()=>{i=void 0}),await i),await n()}}export{l as ensureSearchData};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import
|
|
2
|
-
Usage: ${e}/https://api.example.com/path`);const
|
|
1
|
+
import L from"node:dns";import{isIP as H}from"node:net";import{Agent as $}from"undici";import{withPathPrefix as M}from"@redocly/theme/core/utils";import{ServerRoutes as D}from"../../../constants/api.js";import{envConfig as y}from"../../config/env-config.js";import{getRequestOrigin as b}from"../utils/get-request-origin.js";import{SsrfBlockedError as N}from"../utils/ssrf-blocklist.js";import{createSsrfSafeLookup as W}from"../utils/ssrf-safe-lookup.js";const z=new Set(["connection","keep-alive","proxy-authenticate","proxy-connection","proxy-authorization","te","trailer","transfer-encoding","upgrade","host"]),U=new Set(["cookie","cookie2","accept-encoding"]),Y=new Set(["set-cookie","set-cookie2","content-encoding","content-length"]),S="x-redocly-proxy-streaming",x="x-http-method-override",P="x-redocly-cookie",v="Requests to private network addresses are not allowed",F=new $({connect:{lookup:W()}});function ue(n,e=M(D.CORS_PROXY)){return async t=>{const r=new URL(t.req.url).pathname;if(r===e||r===`${e}/`)return t.text(`Realm CORS proxy endpoint.
|
|
2
|
+
Usage: ${e}/https://api.example.com/path`);const s=ne(t.req.url,e);if(!s)return t.text("Invalid proxied URL",400);const a=n?.getConfig().corsProxy?.allowedTargets;if(a&&a.length>0&&!a.some(f=>ee(s,f)))return t.text("Target URL is not in the allowed list for CORS proxy",403);const m=b(t),g=s.origin===m,w=s.pathname===e||s.pathname.startsWith(`${e}/`);if(g&&!w)return new Response("Please use a direct request",{status:308,headers:{Location:s.toString(),Vary:"origin","Cache-Control":"private"}});const u=await j(s.hostname),p=!y.isDevelopMode||y.isReunite;if(p&&u&&J(u))return t.text(v,403);const i=new Headers,A=T(t.req.raw.headers);for(const[o,f]of t.req.raw.headers)A.has(o.toLowerCase())||U.has(o.toLowerCase())||i.append(o,f);const R=i.get(P);if(R){const o=t.req.raw.headers.get("cookie")||"";i.set("cookie",o?`${o}; ${R}`:R),i.delete(P)}const O=t.req.raw.headers.get("origin")||"";X(O)&&i.delete("origin");let l=t.req.method;const E=i.get(x);E&&(l=E.toUpperCase(),i.delete(x));const h={method:l,headers:i,redirect:"manual"};p&&(h.dispatcher=F),l!=="GET"&&l!=="HEAD"&&t.req.raw.body&&(h.body=t.req.raw.body,h.duplex="half");let c;try{c=await fetch(s,h)}catch(o){if(o instanceof Error&&o.cause instanceof N)return t.text(v,403);const f=o instanceof Error?o.message:"unknown error",q=o instanceof Error&&o.cause instanceof Error?`: ${o.cause.message}`:"";return t.text(`Failed to proxy request: ${f}${q}`,502)}const _=c.headers.get("content-type")||"";if(te(_)&&t.req.raw.headers.get("sec-fetch-mode")==="navigate")return t.text("Direct browser navigation to proxied HTML or JavaScript content is not allowed",403);const d=new Headers(c.headers),k=T(c.headers);for(const o of k)d.delete(o);for(const o of Y)d.delete(o);return d.set(S,"1"),d.set("x-content-type-options","nosniff"),d.has("content-type")||d.set("content-type","text/plain"),new Response(c.body,{status:c.status,statusText:c.statusText,headers:d})}}function B(n){try{return decodeURIComponent(n)}catch{return n}}function G(n){return n.replace(/^(https?):\/(?!\/)/i,"$1://")}function V(n,e){return e?n.includes("?")?e==="?"?n:`${n.endsWith("?")||n.endsWith("&")?n:`${n}&`}${e.slice(1)}`:`${n}${e}`:n}function T(n){const e=new Set(z),t=n.get("connection");if(!t)return e;for(const r of t.split(",")){const s=r.trim().toLowerCase();s&&e.add(s)}return e}function X(n){const e=n.toLowerCase();return e.includes(".redocly.app")||e.includes("localhost")}async function j(n){const e=C(n);if(H(e))return e;try{const{address:t}=await L.promises.lookup(e);return t}catch{return null}}function J(n){const e=C(n).toLowerCase();if(!H(e))return!0;const t=K(e);return t?I(t):e.includes(":")?Q(e):I(e)}function C(n){return n.startsWith("[")&&n.endsWith("]")?n.slice(1,-1):n}function K(n){const e=n.match(/^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/i);if(e){const r=parseInt(e[1],16),s=parseInt(e[2],16);return[r>>8&255,r&255,s>>8&255,s&255].join(".")}return n.match(/^::ffff:(\d+\.\d+\.\d+\.\d+)$/i)?.[1]??null}function I(n){const e=n.split(".").map(Number);if(e.length!==4||e.some(s=>isNaN(s)))return!0;const[t,r]=e;return t===0||t===10||t===127||t===172&&r>=16&&r<=31||t===192&&r===168||t===169&&r===254||t===100&&r>=64&&r<=127}function Q(n){const e=Z(n);return n==="::1"||n==="::"||e!==null&&(e&65024)===64512||e!==null&&(e&65472)===65152}function Z(n){const[e]=n.split(":");if(!e)return null;const t=parseInt(e,16);return Number.isNaN(t)?null:t}function ee(n,e){let t;try{t=new URL(e)}catch{return!1}if(n.origin!==t.origin)return!1;const r=t.pathname.endsWith("/")?t.pathname:`${t.pathname}/`;return n.pathname.startsWith(r)||n.pathname===t.pathname}function te(n){const e=n.toLowerCase();return e.includes("text/html")||e.includes("javascript")||e.includes("application/xhtml")||e.includes("application/xml")||e.includes("image/svg")}function ne(n,e){const t=new URL(n),r=t.pathname===e,s=t.pathname.startsWith(`${e}/`);if(!r&&!s)return null;const a=t.pathname.slice(e.length).replace(/^\/+/,"");if(!a)return null;const m=[a,B(a)];for(const g of m){const w=G(g),u=V(w,t.search);try{const p=new URL(u);if(p.protocol==="http:"||p.protocol==="https:")return p}catch{continue}}return null}const le=S;export{le as CORS_PROXY_STREAM_HEADER,ue as corsProxyHandler,J as isPrivateIp,ne as resolveCorsProxyTarget};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@redocly/realm",
|
|
3
|
-
"version": "0.138.0-next.
|
|
3
|
+
"version": "0.138.0-next.7",
|
|
4
4
|
"description": "",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -33,13 +33,13 @@
|
|
|
33
33
|
"@opentelemetry/sdk-trace-web": "2.8.0",
|
|
34
34
|
"@opentelemetry/semantic-conventions": "1.40.0",
|
|
35
35
|
"@redocly/ajv": "8.18.0",
|
|
36
|
-
"@redocly/api-docs": "0.3.0-next.
|
|
37
|
-
"@redocly/config": "0.61.
|
|
36
|
+
"@redocly/api-docs": "0.3.0-next.5",
|
|
37
|
+
"@redocly/config": "0.61.1",
|
|
38
38
|
"@redocly/openapi-core": "2.55.0",
|
|
39
39
|
"@redocly/portal-legacy-ui": "0.19.0",
|
|
40
40
|
"@redocly/portal-plugin-mock-server": "0.23.0-next.0",
|
|
41
41
|
"@redocly/realm-asyncapi-sdk": "0.16.0-next.2",
|
|
42
|
-
"@redocly/theme": "0.70.0-next.
|
|
42
|
+
"@redocly/theme": "0.70.0-next.5",
|
|
43
43
|
"@shikijs/transformers": "3.21.0",
|
|
44
44
|
"@tanstack/react-query": "5.62.3",
|
|
45
45
|
"@tanstack/react-table": "8.21.3",
|
|
File without changes
|
|
File without changes
|
/package/dist/server/{plugins/mcp/gateway-mcp/fetch → web-server/utils}/ssrf-safe-lookup.d.ts
RENAMED
|
File without changes
|
|
File without changes
|