@redocly/redoc 0.132.0-next.8 → 0.132.0
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 +106 -0
- package/dist/bin.d.ts +0 -1
- package/dist/bin.js +1 -1
- package/dist/client/app/Link.js +1 -1
- package/dist/client/app/search/message-handlers.js +1 -1
- package/dist/client/types/ai-search.d.ts +6 -2
- package/dist/server/config/env-schema.d.ts +3 -3
- package/dist/server/config/env-schemas/auth.d.ts +1 -1
- package/dist/server/config/env-schemas/auth.js +1 -1
- package/dist/server/plugins/enforce-login/index.js +1 -1
- package/dist/server/plugins/mcp/auth/auth-handlers.d.ts +1 -0
- package/dist/server/plugins/mcp/auth/auth-handlers.js +1 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/search.js +2 -2
- package/dist/server/plugins/mcp/handlers/docs-mcp-handler.js +1 -1
- package/dist/server/plugins/mcp/servers/docs-server.js +1 -1
- package/dist/server/plugins/mcp/types.d.ts +1 -0
- package/dist/server/plugins/nav-utils.js +1 -1
- package/dist/server/plugins/openapi-docs/utils.js +1 -1
- package/dist/server/web-server/auth.js +1 -1
- package/dist/server/web-server/routes/cors-proxy.d.ts +2 -1
- package/dist/server/web-server/routes/cors-proxy.js +2 -2
- package/dist/server/web-server/routes/index.js +1 -1
- package/dist/server/web-server/routes/mcp-oauth.js +1 -1
- package/package.json +10 -11
- package/dist/server/node-fetch-polyfill.d.ts +0 -2
- package/dist/server/node-fetch-polyfill.js +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,99 @@
|
|
|
1
1
|
# @redocly/redoc
|
|
2
2
|
|
|
3
|
+
## 0.132.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- e756f2aad5: Added a `palette` configuration option that applies one of built-in color palettes to the project.
|
|
8
|
+
- ae3272861b: Added support for `x-badges` in OpenAPI and AsyncAPI parameters and schema properties.
|
|
9
|
+
Badges can now be rendered before and after field names.
|
|
10
|
+
- ce5a165177: Added support for `or` functions in RBAC conditions within Markdoc content.
|
|
11
|
+
|
|
12
|
+
### Patch Changes
|
|
13
|
+
|
|
14
|
+
- 65bdca2d07: Fixed an issue where `Typesense` search ignored OpenAPI paths.
|
|
15
|
+
- ce5a165177: Fixed a bug where Markdoc content wrapped in an RBAC condition did not appear in search results for users with access.
|
|
16
|
+
- 60b9b77bc3: Fixed a bug that caused search result highlighting to break in Flexsearch when the query contained duplicate words.
|
|
17
|
+
- a09344768f: Fixed an issue where pressing the `Q` key in the terminal in preview mode would not stop the preview.
|
|
18
|
+
- 2cc0ed2399: Fixed an issue where images referenced by the `img` Markdoc tag appeared broken after changing `src` and moving the file, requiring a manual page reload.
|
|
19
|
+
- 2bb8cf6c82: Fixed an issue where URLs starting with the same characters as API reference, AsyncAPI, Scorecards, Catalog, or Developer Onboarding page slugs served data for those pages instead of showing a 404.
|
|
20
|
+
- 86a3b76a9b: Fixed an issue where files with identical names but different extensions in the same folder resolved to a single URL, causing pages to be missing from the deployed project.
|
|
21
|
+
- b3e65a364b: Fixed out-of-memory error in the search indexer that occurred when indexing deeply nested schemas.
|
|
22
|
+
- c336f96cb6: Updated `@redocly/openapi-core` to version `2.25.2`.
|
|
23
|
+
- e5f1e611f7: Fixed an issue where badges in `sidebars.yaml` were not rendering on API reference pages.
|
|
24
|
+
- 76b78a806c: Improved keyboard navigation across Replay's input components for more consistent and predictable focus behavior.
|
|
25
|
+
- 15ab3dcb39: Fixed incorrect RBAC validation that caused authenticated MCP tool calls to be handled improperly.
|
|
26
|
+
- 849199c430: Fixed an issue where complex AI search queries might have resulted with an error.
|
|
27
|
+
- a09344768f: Fixed an issue where the process did not terminate after certain short-lived CLI commands were executed.
|
|
28
|
+
- 3ad1692502: Fixed an issue where clicking asset download links redirected to a 404 page.
|
|
29
|
+
- d54ca044f0: Fixed an issue where filters on code walkthrough pages overlapped the **Search** dialog.
|
|
30
|
+
- 1f95c1a87f: Improved performance when building AI search documents for Markdown.
|
|
31
|
+
- 87a9752112: Fixed an issue where `partial` Markdoc tags in OpenAPI and AsyncAPI `description` fields did not resolve when Windows-style path separators were used.
|
|
32
|
+
- f156e27486: Fixed an issue where navigating to a page through an anchor link from another page occasionally failed to scroll to the anchor.
|
|
33
|
+
- Updated dependencies [623eb1bd10]
|
|
34
|
+
- Updated dependencies [933422fcd9]
|
|
35
|
+
- Updated dependencies [e897bbb1ea]
|
|
36
|
+
- Updated dependencies [2bc33c6758]
|
|
37
|
+
- Updated dependencies [8f8430a807]
|
|
38
|
+
- Updated dependencies [f69e101a44]
|
|
39
|
+
- Updated dependencies [c336f96cb6]
|
|
40
|
+
- Updated dependencies [ed553fa138]
|
|
41
|
+
- Updated dependencies [8710b00b3e]
|
|
42
|
+
- Updated dependencies [037535441a]
|
|
43
|
+
- Updated dependencies [e88064ce2d]
|
|
44
|
+
- Updated dependencies [e756f2aad5]
|
|
45
|
+
- Updated dependencies [ae3272861b]
|
|
46
|
+
- Updated dependencies [849199c430]
|
|
47
|
+
- Updated dependencies [c3d4cd955d]
|
|
48
|
+
- Updated dependencies [d54ca044f0]
|
|
49
|
+
- Updated dependencies [87a9752112]
|
|
50
|
+
- Updated dependencies [b24ffd4d9f]
|
|
51
|
+
- @redocly/openapi-docs@3.20.0
|
|
52
|
+
- @redocly/realm-asyncapi-sdk@0.10.0
|
|
53
|
+
- @redocly/theme@0.64.0
|
|
54
|
+
- @redocly/asyncapi-docs@1.9.0
|
|
55
|
+
- @redocly/graphql-docs@1.9.0
|
|
56
|
+
- @redocly/portal-plugin-mock-server@0.17.0
|
|
57
|
+
- @redocly/portal-legacy-ui@0.15.0
|
|
58
|
+
|
|
59
|
+
## 0.132.0-next.11
|
|
60
|
+
|
|
61
|
+
### Patch Changes
|
|
62
|
+
|
|
63
|
+
- e5f1e611f7f: Fixed an issue where badges in `sidebars.yaml` were not rendering on API reference pages.
|
|
64
|
+
- 3ad1692502c: Fixed an issue where clicking asset download links redirected to a 404 page.
|
|
65
|
+
- Updated dependencies [623eb1bd109]
|
|
66
|
+
- Updated dependencies [e897bbb1ea8]
|
|
67
|
+
- Updated dependencies [c3d4cd955d1]
|
|
68
|
+
- @redocly/openapi-docs@3.20.0-next.8
|
|
69
|
+
- @redocly/realm-asyncapi-sdk@0.10.0-next.3
|
|
70
|
+
- @redocly/theme@0.64.0-next.6
|
|
71
|
+
- @redocly/asyncapi-docs@1.9.0-next.8
|
|
72
|
+
- @redocly/graphql-docs@1.9.0-next.8
|
|
73
|
+
- @redocly/portal-plugin-mock-server@0.17.0-next.8
|
|
74
|
+
|
|
75
|
+
## 0.132.0-next.10
|
|
76
|
+
|
|
77
|
+
### Patch Changes
|
|
78
|
+
|
|
79
|
+
- 907e21434dc: Improved CORS proxy security by injecting `X-Content-Type-Options: no-sniff` into proxied responses.
|
|
80
|
+
- 15ab3dcb393: Fixed incorrect RBAC validation that caused authenticated MCP tool calls to be handled improperly.
|
|
81
|
+
- 849199c4300: Fixed an issue where complex AI search queries might have resulted with an error.
|
|
82
|
+
- Updated dependencies [2bc33c6758e]
|
|
83
|
+
- Updated dependencies [849199c4300]
|
|
84
|
+
- @redocly/realm-asyncapi-sdk@0.10.0-next.2
|
|
85
|
+
- @redocly/theme@0.64.0-next.5
|
|
86
|
+
- @redocly/asyncapi-docs@1.9.0-next.7
|
|
87
|
+
- @redocly/graphql-docs@1.9.0-next.7
|
|
88
|
+
- @redocly/openapi-docs@3.20.0-next.7
|
|
89
|
+
- @redocly/portal-plugin-mock-server@0.17.0-next.7
|
|
90
|
+
|
|
91
|
+
## 0.132.0-next.9
|
|
92
|
+
|
|
93
|
+
### Patch Changes
|
|
94
|
+
|
|
95
|
+
- 3367cbdaba3: Fixed `residency` configuration causing build failures.
|
|
96
|
+
|
|
3
97
|
## 0.132.0-next.8
|
|
4
98
|
|
|
5
99
|
### Patch Changes
|
|
@@ -141,6 +235,18 @@
|
|
|
141
235
|
- @redocly/openapi-docs@3.20.0-next.0
|
|
142
236
|
- @redocly/theme@0.64.0-next.0
|
|
143
237
|
|
|
238
|
+
## 0.131.4
|
|
239
|
+
|
|
240
|
+
### Patch Changes
|
|
241
|
+
|
|
242
|
+
- a0b5d17c1f: Improved CORS proxy security by injecting `X-Content-Type-Options: no-sniff` into proxied responses.
|
|
243
|
+
|
|
244
|
+
## 0.131.3
|
|
245
|
+
|
|
246
|
+
### Patch Changes
|
|
247
|
+
|
|
248
|
+
- 4afca06580: Fixed a Realm CORS proxy security issue that could allow requests to private network addresses and unsafe direct navigation to proxied HTML or JavaScript content.
|
|
249
|
+
|
|
144
250
|
## 0.131.2
|
|
145
251
|
|
|
146
252
|
### Patch Changes
|
package/dist/bin.d.ts
CHANGED
package/dist/bin.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import"./server/utils/set-execution-mode.js";import"./cli/utils/node-version-check.js";import o from"mri";import*as r from"node:path";import{tmpdir as T}from"node:os";import*as u from"node:fs";import
|
|
2
|
+
import"./server/utils/set-execution-mode.js";import"./cli/utils/node-version-check.js";import o from"mri";import*as r from"node:path";import{tmpdir as T}from"node:os";import*as u from"node:fs";import{cliCommandNames as C}from"./constants/common.js";import{initPlugins as S}from"./server/plugins/lifecycle.js";import{loadEnvVariables as k}from"./server/utils/envs/load-env-variables.js";import{PORTAL_VERSION as I}from"./server/version.js";import{logger as i}from"./server/tools/notifiers/logger.js";import{reporter as t}from"./server/tools/notifiers/reporter.js";import{sha as V}from"./server/utils/crypto/sha.js";import{envConfig as L}from"./server/config/env-config.js";import{PACKAGE_NAME as w}from"./config/product-gates.js";import{develop as R}from"./cli/develop.js";import{eject as _}from"./cli/eject/index.js";import{beforeCommand as E}from"./server/utils/lifecycle-hooks.js";import{Store as j}from"./server/store.js";import{build as M}from"./cli/build/index.js";import{fromCurrentDir as N}from"./server/utils/paths.js";import{translationsCliOpts as F}from"./cli/translations/options.js";import{generateTranslations as U}from"./cli/translations/index.js";import{EntitlementsProvider as $}from"./server/entitlements/entitlements-provider.js";import{isValidPlan as B}from"./server/entitlements/is-valid-plan.js";import{stopAllCompilers as G}from"./server/esbuild/esbuild.js";import{copyLibsqlPrebuiltBinary as q}from"./cli/build/libsql/copy-prebuilt-binary.js";import{telemetry as f}from"./cli/telemetry/index.js";import{stats as K}from"./cli/stats/index.js";import{statsCliOpts as Y}from"./cli/stats/options.js";const c=process.argv[2];let a;const v={alias:{d:"project-dir",p:"port"},default:{"project-dir":L.REDOCLY_CONTENT_DIR||process.cwd(),outdir:"public"}},z={alias:v.alias,default:{...v.default,plan:"enterprise"}},H={alias:{d:"buildDir"},default:{buildDir:"public"}},J={boolean:["force"],alias:{f:"force",d:"project-dir"},default:{"project-dir":process.cwd()}};process.on("uncaughtException",async function(e){e?.code==="ERR_INVALID_STATE"?console.log("Ignore premature close error"):(i.error("Uncaught exception occurred. Stopping compilers."),await G(),i.error("Exiting due to uncaught exception"),await t.panic(e))});try{c||await t.panicOnContentError("Command not specified.");const e=$.instance();switch(["build","prepare","serve","stats"].includes(c)&&await e.init(),["eject","translate"].includes(c)&&await e.init({developModePlan:"enterprise"}),c){case"develop":case"preview":const s=o(process.argv.slice(3),z),O=r.resolve(s["project-dir"]),h=encodeURIComponent(V(O)),p=r.join(T(),"redocly-public-"+h);u.existsSync(p)&&(i.verbose("Cleaning temporary output directory..."),u.rmSync(p,{recursive:!0,force:!0}),i.verbose("Temporary output directory cleaned."));const m=s.plan.toLowerCase();B(m)||await t.panicOnContentError(`Invalid --plan argument value '${m}'.`),await e.init({developModePlan:m}),a=new j({contentDir:r.resolve(s["project-dir"]),outdir:p,serverOutDir:N(import.meta.url,"./server/esbuild/cache/server")}),await E(C.DEVELOP,s,a),await R(s,a);break;case"build":case"prepare":const n=o(process.argv.slice(3),v),g=r.resolve(r.join(n.outdir,"server"));a=new j({contentDir:r.resolve(n["project-dir"]),outdir:r.resolve(n.outdir,"client"),serverOutDir:g}),await E(C.BUILD,n,a),q(g),await M(n,a);break;case"serve":await k();const A=o(process.argv.slice(3),H),D=r.resolve(A.buildDir);f.sendServeCliCommandExecutedMessage();const b=r.join(D,"server","index.mjs");u.existsSync(b)||await t.panic(`Server not found. Please run \`${w} build\` first (or \`${w} prepare\` for the deprecated command)`),import(b).catch(async l=>{await t.panic("Failed to load server",l)});break;case"eject":e.canAccessFeature("themeEjecting")||await t.panicOnContentError('The "eject" command is not available for this project');const d=o(process.argv.slice(3),J),{lifecycleContext:{getConfig:y,fs:P}}=await S({outdir:"",contentDir:r.resolve(d["project-dir"]),setGlobalConfig:()=>null});P.dispose(),f.sendCliCommandEjectExecutedMessage([{object:"cli_command",arguments:d}]),await _({...d,config:await y()}),i.clearAllTimeouts();break;case"translate":if(e.canAccessFeature("l10n")){const l=o(process.argv.slice(3),F);f.sendCliCommandTranslateExecutedMessage({arguments:l}),await U(l)}else await t.panicOnContentError('The "translate" command is not available for this project');break;case"stats":const x=o(process.argv.slice(3),Y);await K(x);break;case"--version":console.log(I);break;default:await t.panicOnContentError(`Unknown command "${c}"`)}}catch(e){i.error("Exiting due to uncaught exception"),await t.panic(e)}
|
package/dist/client/app/Link.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import*as
|
|
1
|
+
import*as s from"react";import p from"path";import{Link as A,useNavigate as b,useLocation as O}from"react-router-dom";import{getPathnameForLocale as U,withPathPrefix as z}from"@redocly/theme/core/utils";import{removeTrailingSlash as D}from"../../utils/url/remove-trailing-slash";import{normalizeRouteSlug as h}from"../../utils/path/normalize-route-slug";import{isAbsoluteUrl as F}from"../../utils/url/is-absolute-url";import{isAssetsLink as M}from"../../utils/path/is-assets-link";import{useL10nConfig as S}from"./hooks/index.js";import{loadAndNavigate as W}from"./utils/loadAndNavigate.js";import{isForcedNavigationLinkClick as I}from"../utils/utils.js";async function g(r,t){if(F(r))return;await(typeof window<"u"?window:global).__LOADER.tryLoad(r,void 0,t)}function Y(r){const{to:t,children:l,className:L,style:a,innerRef:i,target:w,external:c,languageInsensitive:v,onClick:m,active:T,rel:y,...k}=r,P=w||(c?"_blank":"_self"),R=c||t.match(/^(https?:\/\/|mailto:)/),f=y||(R?"noreferrer":void 0),n={className:L,children:l,target:P,...f&&{rel:f},onClick:m,...k},{defaultLocale:C,locales:E,currentLocale:N}=S(),_=O();let e=t;e.startsWith(".")&&(e=p.resolve(p.dirname(h(_.pathname)),h(t))),e=e.startsWith("#")?e:z(v?e:U(e,C,N,E));const o=e!=="/"?D(e):e,x=b(),d=typeof window<"u"?new URL(o,window.location.origin+window.location.pathname).search:void 0;return typeof t=="string"&&t.match(/^(https?:\/\/|mailto:)/)?s.createElement("a",{...n,ref:i,style:a,href:t,onMouseOver:async()=>g(t,d)}):M(o)?s.createElement("a",{...n,ref:i,style:a,href:o}):s.createElement(A,{...n,ref:i,style:a,to:o,onClick:u=>{m?.(),!I(u,n.target)&&(u.preventDefault(),W({navigate:x,to:o}))},onMouseOver:async()=>g(o,d)})}export{Y as Link};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{AiSearchConversationRole as o,AiSearchError as
|
|
1
|
+
import{AiSearchConversationRole as o,AiSearchError as i}from"@redocly/theme/core/constants";import{SSE_EVENTS as s,MAX_DISPLAYED_RESOURCES as a}from"../../constants";function l(e,n){if(e.length===0)return e;const t=e[e.length-1];return t.role===o.ASSISTANT&&!t.messageId?[...e.slice(0,-1),{...t,messageId:n}]:e}function S(e,n){if(e.length===0)return e;const t=e.findIndex(u=>u.id===n.toolCallId);if(t===-1)return e;const r=[...e];return r[t]={...r[t],result:n},r}function d(e,n){return e.type!==s.MESSAGE_ID?{}:(n.setConversation(t=>l(t,e.messageId)),{messageId:e.messageId})}function f(e,n){if(e.type!==s.SOURCES)return{};const t=e.sources.slice(0,a).map(({url:r,title:u})=>({url:r,title:u}));return n.setState(r=>r.status==="loading"?{...r,resources:t}:r),{resources:t}}function c(e,n){if(e.type!==s.ANSWER)return{};const t=n.accumulatedResponse+e.answer;return n.setState(r=>r.status==="loading"?{...r,response:t}:r),{accumulatedResponse:t}}function E(e,n){return e.type!==s.TOOL_CALL?{}:(n.setToolCalls(t=>[...t,{...e.toolCall,position:n.accumulatedResponse.length}]),{})}function R(e,n){return e.type!==s.TOOL_RESULT?{}:(n.setToolCalls(t=>S(t,e.result)),{})}function A(e,n){return e.type!==s.ERROR?{}:(n.setState(t=>t.status==="loading"?{status:"error",question:t.question,error:i.ErrorProcessingResponse}:t),{})}const h={[s.MESSAGE_ID]:d,[s.SOURCES]:f,[s.ANSWER]:c,[s.TOOL_CALL]:E,[s.TOOL_RESULT]:R,[s.ERROR]:A};function T(e,n){const t=h[e.type];return t?t(e,n):{}}export{T as handleSSEMessage};
|
|
@@ -24,6 +24,7 @@ export type SSEAnswer = {
|
|
|
24
24
|
export type SSEToolCall = {
|
|
25
25
|
type: typeof SSE_EVENTS.TOOL_CALL;
|
|
26
26
|
toolCall: {
|
|
27
|
+
id: string;
|
|
27
28
|
name: string;
|
|
28
29
|
args: unknown;
|
|
29
30
|
};
|
|
@@ -33,7 +34,8 @@ export type SSEToolResult = {
|
|
|
33
34
|
toolName: string;
|
|
34
35
|
args: unknown;
|
|
35
36
|
result: {
|
|
36
|
-
|
|
37
|
+
toolCallId: string;
|
|
38
|
+
documentCount?: number;
|
|
37
39
|
};
|
|
38
40
|
};
|
|
39
41
|
export type SSEError = {
|
|
@@ -44,11 +46,13 @@ export type SSEError = {
|
|
|
44
46
|
};
|
|
45
47
|
export type SSEMessage = SSEMessageId | SSESources | SSEAnswer | SSEToolCall | SSEToolResult | SSEError;
|
|
46
48
|
export type ToolCallState = {
|
|
49
|
+
id: string;
|
|
47
50
|
name: string;
|
|
48
51
|
args: unknown;
|
|
49
52
|
position: number;
|
|
50
53
|
result?: {
|
|
51
|
-
|
|
54
|
+
toolCallId: string;
|
|
55
|
+
documentCount?: number;
|
|
52
56
|
};
|
|
53
57
|
};
|
|
54
58
|
export type AiSearchOptions = {
|
|
@@ -42,7 +42,7 @@ export declare const envSchema: z.ZodObject<{
|
|
|
42
42
|
LOCALHOST_LOGIN: z.ZodOptional<z.ZodEnum<["true", "false"]>>;
|
|
43
43
|
REDOCLY_OAUTH_USE_INTROSPECT: z.ZodOptional<z.ZodString>;
|
|
44
44
|
REDOCLY_ENFORCE_LOGIN: z.ZodOptional<z.ZodEnum<["true", "false"]>>;
|
|
45
|
-
REDOCLY_ENFORCE_RESIDENCY: z.ZodOptional<z.ZodString
|
|
45
|
+
REDOCLY_ENFORCE_RESIDENCY: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodLiteral<"">]>>;
|
|
46
46
|
} & {
|
|
47
47
|
REDOCLY_SSR_RENDER_MODE: z.ZodOptional<z.ZodEnum<["worker", "main"]>>;
|
|
48
48
|
REDOCLY_SSR_WORKERS_MIN: z.ZodOptional<z.ZodNumber>;
|
|
@@ -124,7 +124,7 @@ export declare const envSchema: z.ZodObject<{
|
|
|
124
124
|
LOCALHOST_LOGIN: z.ZodOptional<z.ZodEnum<["true", "false"]>>;
|
|
125
125
|
REDOCLY_OAUTH_USE_INTROSPECT: z.ZodOptional<z.ZodString>;
|
|
126
126
|
REDOCLY_ENFORCE_LOGIN: z.ZodOptional<z.ZodEnum<["true", "false"]>>;
|
|
127
|
-
REDOCLY_ENFORCE_RESIDENCY: z.ZodOptional<z.ZodString
|
|
127
|
+
REDOCLY_ENFORCE_RESIDENCY: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodLiteral<"">]>>;
|
|
128
128
|
} & {
|
|
129
129
|
REDOCLY_SSR_RENDER_MODE: z.ZodOptional<z.ZodEnum<["worker", "main"]>>;
|
|
130
130
|
REDOCLY_SSR_WORKERS_MIN: z.ZodOptional<z.ZodNumber>;
|
|
@@ -206,7 +206,7 @@ export declare const envSchema: z.ZodObject<{
|
|
|
206
206
|
LOCALHOST_LOGIN: z.ZodOptional<z.ZodEnum<["true", "false"]>>;
|
|
207
207
|
REDOCLY_OAUTH_USE_INTROSPECT: z.ZodOptional<z.ZodString>;
|
|
208
208
|
REDOCLY_ENFORCE_LOGIN: z.ZodOptional<z.ZodEnum<["true", "false"]>>;
|
|
209
|
-
REDOCLY_ENFORCE_RESIDENCY: z.ZodOptional<z.ZodString
|
|
209
|
+
REDOCLY_ENFORCE_RESIDENCY: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodLiteral<"">]>>;
|
|
210
210
|
} & {
|
|
211
211
|
REDOCLY_SSR_RENDER_MODE: z.ZodOptional<z.ZodEnum<["worker", "main"]>>;
|
|
212
212
|
REDOCLY_SSR_WORKERS_MIN: z.ZodOptional<z.ZodNumber>;
|
|
@@ -15,7 +15,7 @@ export declare const authSchema: z.ZodObject<{
|
|
|
15
15
|
LOCALHOST_LOGIN: z.ZodOptional<z.ZodEnum<["true", "false"]>>;
|
|
16
16
|
REDOCLY_OAUTH_USE_INTROSPECT: z.ZodOptional<z.ZodString>;
|
|
17
17
|
REDOCLY_ENFORCE_LOGIN: z.ZodOptional<z.ZodEnum<["true", "false"]>>;
|
|
18
|
-
REDOCLY_ENFORCE_RESIDENCY: z.ZodOptional<z.ZodString
|
|
18
|
+
REDOCLY_ENFORCE_RESIDENCY: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodLiteral<"">]>>;
|
|
19
19
|
}, "strip", z.ZodTypeAny, {
|
|
20
20
|
JWT_SECRET_KEY?: string | undefined;
|
|
21
21
|
AUTH_URL?: string | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{z as o}from"zod";const n=o.object({JWT_SECRET_KEY:o.string().optional(),AUTH_URL:o.string().url().optional(),BH_API_URL:o.string().url().optional(),ENTITLEMENTS_JWKS_CDN_URL:o.string().url().optional(),OAUTH_CLIENT_ID:o.string().optional(),OAUTH_CLIENT_SECRET:o.string().optional(),OIDC_CLIENT_ID:o.string().optional(),OIDC_CLIENT_SECRET:o.string().optional(),OIDC_ISSUER_URL:o.string().url().optional(),LOCALHOST_LOGIN:o.enum(["true","false"]).optional(),REDOCLY_OAUTH_USE_INTROSPECT:o.string().optional(),REDOCLY_ENFORCE_LOGIN:o.enum(["true","false"]).optional(),REDOCLY_ENFORCE_RESIDENCY:o.string().url().optional()});export{n as authSchema};
|
|
1
|
+
import{z as o}from"zod";const n=o.object({JWT_SECRET_KEY:o.string().optional(),AUTH_URL:o.string().url().optional(),BH_API_URL:o.string().url().optional(),ENTITLEMENTS_JWKS_CDN_URL:o.string().url().optional(),OAUTH_CLIENT_ID:o.string().optional(),OAUTH_CLIENT_SECRET:o.string().optional(),OIDC_CLIENT_ID:o.string().optional(),OIDC_CLIENT_SECRET:o.string().optional(),OIDC_ISSUER_URL:o.string().url().optional(),LOCALHOST_LOGIN:o.enum(["true","false"]).optional(),REDOCLY_OAUTH_USE_INTROSPECT:o.string().optional(),REDOCLY_ENFORCE_LOGIN:o.enum(["true","false"]).optional(),REDOCLY_ENFORCE_RESIDENCY:o.union([o.string().url(),o.literal("")]).optional()});export{n as authSchema};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{envConfig as
|
|
1
|
+
import{envConfig as o}from"../../config/env-config.js";async function u(E){return{id:"enforce-login",async processContent(r){const e=!!o.REDOCLY_ENFORCE_RESIDENCY,s=o.REDOCLY_ENFORCE_LOGIN==="true";if(!e&&!s)return;const n=r.getConfig(),i=t=>!!t&&Object.keys(t).length>0,f=i(n.access?.rbac)||i(n.rbac),c=s&&!f;!e&&!c||r.setGlobalConfig({...c&&"rbac"in n&&{rbac:void 0},...c&&"requiresLogin"in n&&{requiresLogin:void 0},...e&&"residency"in n&&{residency:void 0},access:{...n.access,...e&&{residency:o.REDOCLY_ENFORCE_RESIDENCY},...c&&{requiresLogin:!0,rbac:void 0}}})}}}export{u as enforceLoginPlugin};
|
|
@@ -4,6 +4,7 @@ export declare function handleMcpAuth(request: Request, context: ApiFunctionsCon
|
|
|
4
4
|
isAuthenticated: boolean;
|
|
5
5
|
isTokenValid?: boolean;
|
|
6
6
|
currentUser?: ApiFunctionsUser;
|
|
7
|
+
accessToken?: string;
|
|
7
8
|
}>;
|
|
8
9
|
export declare function constructUnauthorizedResponse(baseUrl: string): Response;
|
|
9
10
|
export declare function constructInvalidTokenResponse(): Response;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{extractTokenFromAuthHeader as u}from"../../../plugins/mcp/utils/jwt.js";import{getUserParamsFromCookies as d}from"../../../web-server/auth.js";import{DEFAULT_ANONYMOUS_VISITOR_TEAM as
|
|
1
|
+
import{extractTokenFromAuthHeader as u}from"../../../plugins/mcp/utils/jwt.js";import{getUserParamsFromCookies as d}from"../../../web-server/auth.js";import{DEFAULT_ANONYMOUS_VISITOR_TEAM as i,RBAC_ALL_OTHER_TEAMS as a,ServerRoutes as l}from"../../../../constants/common.js";import{withPathPrefix as h}from"@redocly/theme/core/utils";function c(e){return!e||typeof e!="object"||Object.keys(e).length===0?!1:!(e[i]&&e[i]!=="none"||e[a]&&e[a]!=="none")}function k(e,t){if(!t||Object.keys(t).length===0)return e;const r=t.content;if(r&&Object.keys(r).length>0&&Object.values(r).some(c))return!0;const s=t.teamFoldersBaseRoles;return c(s)?!0:e}async function R(e,t){const r=e.headers.get("Authorization");if(!r)return{isAuthenticated:!1};const s=u(r),o=t?.config?.ssoDirect||{},n=s?await d(o,{authorization:s}):{};return s&&n&&n.isAuthenticated?{isAuthenticated:!0,isTokenValid:!0,currentUser:{teams:n.teams||[],email:n.email||"",claims:n,isAuthenticated:!0,idpAccessToken:n.idpAccessToken||void 0,idpId:n.idpId||void 0},accessToken:s}:{isAuthenticated:!1,isTokenValid:!1}}function O(e){return new Response(JSON.stringify({error:"unauthorized",message:"Authentication required"}),{status:401,headers:{"Content-Type":"application/json","WWW-Authenticate":`Bearer realm="${e}${l.MCP_OAUTH_PROTECTED_RESOURCE}${h("/mcp")}"`,"Access-Control-Allow-Origin":"*"}})}function _(){return new Response(JSON.stringify({error:"invalid_token",message:"Invalid or expired token"}),{status:401,headers:{"Content-Type":"application/json","WWW-Authenticate":'Bearer error="invalid_token", error_description="Invalid or expired token"',"Access-Control-Allow-Origin":"*"}})}export{_ as constructInvalidTokenResponse,O as constructUnauthorizedResponse,R as handleMcpAuth,k as shouldHandleMcpAuth};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import{withPathPrefix as
|
|
1
|
+
import{withPathPrefix as p}from"@redocly/theme/core/utils";import{ServerRoutes as h}from"../../../../../constants/common.js";const f=async(a,t)=>{const{query:c,product:u}=a,l=JSON.stringify({query:c,product:u});let e=`${t.baseUrl}${p(h.SEMANTIC_SEARCH)}`;e.startsWith("http://")&&(e=e.replace(/^http:\/\//,"https://"));const o=t.accessToken?`authorization=${String(t.accessToken).replace(/^Bearer /,"")}`:"";try{const s=await fetch(e,{method:"POST",credentials:"include",headers:{"Content-Type":"application/json",...o?{Cookie:o}:{}},body:l});if(!s.ok)return{content:[{type:"text",text:"Error retrieving search results."}],isError:!0};const r=await s.json();if(!r||r.length===0)return{content:[{type:"text",text:"No results found."}]};const i=r.map(n=>`### [${n.title}](${new URL(n.url,t.baseUrl).toString()})
|
|
2
2
|
|
|
3
3
|
${n.content}
|
|
4
4
|
`).join(`
|
|
5
5
|
|
|
6
|
-
`).trim();return{content:[{type:"text",text:i.length?i:"No results found."}]}}catch{return{content:[{type:"text",text:"Error retrieving search results."}],isError:!0}}};var m={search:
|
|
6
|
+
`).trim();return{content:[{type:"text",text:i.length?i:"No results found."}]}}catch{return{content:[{type:"text",text:"Error retrieving search results."}],isError:!0}}};var m={search:f};export{m as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{toFetchResponse as
|
|
1
|
+
import{toFetchResponse as w,toReqRes as y}from"fetch-to-node";import{createDocsMcpServer as C}from"../servers/docs-server.js";import{filterApiDescriptionsByRbac as D}from"../utils.js";import{createMethodNotAllowedError as T,withErrorHandling as v}from"./errors.js";import{McpServerType as A}from"../constants.js";import{constructInvalidTokenResponse as S,constructUnauthorizedResponse as U,handleMcpAuth as b,shouldHandleMcpAuth as k}from"../auth/auth-handlers.js";const L=async(o,e,u)=>{const c=!!e?.config?.access?.requiresLogin,a=e?.config?.access?.rbac||{};let p;if(k(c,a)){const{isAuthenticated:s,isTokenValid:t,currentUser:n,accessToken:i}=await b(o,e);if(!s)return U(new URL(o.url).origin);if(!t)return S();n&&(e.user=n),p=i}let r;const l=async()=>{r&&(await r.cleanup(),r=void 0)};return await v(async()=>{if(o.method==="GET")return new Response(JSON.stringify({error:"Method Not Allowed",message:`In order to use this MCP server, you need register it in your MCP Client (VS Code, Cursor, Claude Code, etc.) using that URL: ${o.url}`}),{status:405,headers:{"Content-Type":"application/json"}});if(o.method!=="POST")return T();const s=u,t=s?.props?.config?.apiDescriptionsMap||{},n=s?.props?.config?.mcpDocsServerName||"Docs MCP server",{config:{mcp:i={}}}=e,f=D(t,e.user,a,c),m=e.config.products?Object.values(e.config.products).map(R=>R?.name):[],g=i.docs?.name||n;r=await C({name:g,tools:s?.props?.tools||[],context:{...e,accessToken:p,outdir:e.outdir||"",baseUrl:e.baseUrl||new URL(o.url).origin,apiDescriptionsMap:f,products:m}});const h=await o.json(),{req:M,res:d}=y(o);return await r.transport.handleRequest(M,d,h),w(d)},A.Docs,l)};var O=L;export{O as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{McpServer as p}from"@redocly/mcp-typescript-sdk/server/mcp.js";import{StreamableHTTPServerTransport as l}from"@redocly/mcp-typescript-sdk/server/streamableHttp.js";import{logger as m}from"../../../tools/notifiers/logger.js";import{mcpToolWorkers as f,MCP_TOOL_WORKER_KEY as d}from"../../../workers/mcp-tool-worker-pool.js";async function
|
|
1
|
+
import{McpServer as p}from"@redocly/mcp-typescript-sdk/server/mcp.js";import{StreamableHTTPServerTransport as l}from"@redocly/mcp-typescript-sdk/server/streamableHttp.js";import{logger as m}from"../../../tools/notifiers/logger.js";import{mcpToolWorkers as f,MCP_TOOL_WORKER_KEY as d}from"../../../workers/mcp-tool-worker-pool.js";async function k({name:e,tools:a,context:n}){const o=new p({name:e,version:new Date().toISOString().slice(0,10)},{capabilities:{logging:{}}}),s=new l({sessionIdGenerator:void 0});for(const r of a){const i=async(t,c)=>{m.info(`MCP tool called: ${r.name}`);const u={toolName:r.name,args:t,context:g(n),extra:I(c)};return await f.exec(d,[u],{timeout:6e4})};o.tool(r.name,r.description,r.schema,i)}return await o.connect(s),{server:o,transport:s,cleanup:async()=>{s.close()}}}function I(e){return{sessionId:e.sessionId,authInfo:e.authInfo,requestId:e.requestId,requestInfo:e.requestInfo,_meta:e._meta}}function g(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,products:e.products,accessToken:e.accessToken}}export{k as createDocsMcpServer};
|
|
@@ -77,6 +77,7 @@ export type McpToolExtra = {
|
|
|
77
77
|
export type McpToolContext = Omit<ApiFunctionsContext, 'telemetry' | 'getKv' | keyof ApiFunctionsContextMethods> & {
|
|
78
78
|
apiDescriptionsMap: Record<string, ApiDescriptionInfo>;
|
|
79
79
|
products?: string[];
|
|
80
|
+
accessToken?: string;
|
|
80
81
|
};
|
|
81
82
|
export type McpToolHandler<TArgs extends Record<string, unknown> = Record<string, unknown>> = (args: TArgs, context: McpToolContext, extra: McpToolExtra) => Promise<McpToolWorkerResponse>;
|
|
82
83
|
export type McpToolExecutionParams = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import*as v from"path";import{REDOCLY_ROUTE_RBAC as b,REDOCLY_TEAMS_RBAC as p}from"@redocly/config";import{VERSION_SEPARATOR as M}from"../constants/common.js";import{DEFAULT_LOCALE_PLACEHOLDER as _}from"../../constants/common.js";import{removeTrailingSlash as j}from"../../utils/url/remove-trailing-slash.js";import{isPrimitive as W}from"../../utils/guards/is-primitive.js";import{slash as w}from"../../utils/path/slash.js";import{isAbsoluteUrl as z}from"../../utils/url/is-absolute-url.js";import{normalizeRouteSlug as U}from"../../utils/path/normalize-route-slug.js";import{parsePathVersions as R}from"../../utils/path/parse-path-versions.js";import{logger as A}from"../tools/notifiers/logger.js";import{reporter as S}from"../tools/notifiers/reporter.js";import{shaDirPathShort as C}from"../utils/crypto/sha-dir-path-short.js";import{copyStaticFile as H,FileNotFoundError as E}from"../utils/fs.js";import{isIconPath as J,resolveAssetPath as Y}from"../utils/index.js";import{resolveSrcSet as G}from"../utils/resolve-src-set.js";import{isL10nPath as B}from"../fs/utils/is-l10n-path.js";import{getLocaleFromRelativePath as q}from"../fs/utils/get-locale-from-relative-path.js";async function D(e,s,n,t,a){if(!e)return;const f={...a,ignoreCustomSidebar:!0};if(W(e)){if(typeof e=="string"){const r=F(n.contentDir,s,a,e,t.fs);if(t.fs.exists(r)){if(n.getRouteByFsPath(r))return K({page:e},s,n,t,f);{const g=t.fs.getFileInfo(r);return g?H(n.contentDir,g.realRelativePath,n.outdir):void 0}}}return e}return Array.isArray(e)?I(N(e),s,n,t,f):Object.fromEntries(await Promise.all(Object.entries(e).map(async([r,l])=>[r,await D(l,s,n,t,a)])))}function N(e){return e.map(s=>({...s,items:s.items?N(s.items):void 0}))}async function I(e,s,n,t,a){if(Array.isArray(e))return(await Promise.all(e.map(f=>K(f,s,n,t,a)))).flatMap(f=>f)}async function P(e,s,n,t){let a,f;if(typeof e.icon=="object"){if("srcSet"in e.icon)try{a=await G(e.icon.srcSet,n.fs,{fromFileRelativePath:t.navFile,contentDir:s.contentDir,outdir:s.outdir})}catch(d){d instanceof E?await S.panicOnBuildContentError(`Cannot resolve "item.icon.srcSet" from ${t.navFile}: ${d.message}`):await S.panicOnBuild(`Cannot resolve "item.icon.srcSet" from ${t.navFile}: ${d.message}`)}}else if(typeof e.icon=="string")if(z(e.icon)||J(e.icon))try{f=await Y(e.icon,n.fs,{fromFileRelativePath:t.navFile,contentDir:s.contentDir,outdir:s.outdir})}catch(d){d instanceof E?await S.panicOnBuildContentError(`Cannot resolve "item.icon" from ${t.navFile}: file ${f} does not exist`):await S.panicOnBuild(`Cannot resolve "item.icon" from ${t.navFile}: ${d.message}`)}else f=e.icon;return{icon:f,srcSet:a}}function Q(e){return s=>{if(s.type==="link"||s.type==="group"){const n=s.metadata;return n?Object.entries(e).every(([t,a])=>Array.isArray(a)?a.some(f=>n[t]===f):n[t]===a):!1}return!0}}async function K(e,s,n,t,a){if(e?.directory&&e.items?.length)return{type:"error",label:`Can't have both "directory" and "items" in the nav item: ${JSON.stringify(e)}`};e?.directory&&e?.group&&(e={...e,directory:void 0,items:[{directory:e.directory}]});const f=e?.directory?F(n.contentDir,s,a,e.directory,t.fs):void 0;if(f!==void 0){const i=f===""?"":f+"/",{locale:u,ignoredRoutes:o}=a;let h=n.getAllRoutesForLocale(u).filter(c=>!o?.has(c.baseSlug||"")&&c.fsPath.startsWith(i)&&!c.excludeFromSidebar).sort((c,y)=>c.fsPath===y.fsPath?0:c.baseSlug.localeCompare(y.baseSlug,void 0,{numeric:!0}));const m=e.includeByMetadata?Q(e.includeByMetadata):Boolean;if(!h.length)return[];const $=(await Promise.all(h.map(async c=>{const y=c.versions?.find(x=>x.active),L=y&&{version:y.version,isDefault:y.default,versionFolderId:y.folderId},V=ee(v.posix.relative(f,c.fsPath)),O=c.getSidebar?.(c);return!a.ignoreCustomSidebar&&O?.length?{type:"group",fsPath:c.fsPath,metadata:c.metadata,link:c.slug,routeSlug:c.slug,label:await c.getNavText?.()||c.slug,[p]:c[p],[b]:c[b],sidebarItems:k(O,L,c[p],c[b]),...L,relativePathFromDirectory:v.relative(f,c.fsPath).replace(/@[^\/]+\//,"")}:{type:"link",fsPath:c.fsPath,metadata:c.metadata,[p]:c[p],[b]:c[b],label:await c.getNavText?.()||c.slug,link:c.slug,routeSlug:c.slug,...L,relativePathFromDirectory:V}}))).filter(m);return e.flatten?T($,a):Z($,a)}let d=typeof e=="string"?e:e?.page,r,l;if(d){if(d.includes("#")){const[i,u]=d.split("#");u?l=u:A.warn(`Invalid heading anchor format in sidebar: "${u}". Heading anchors should contain only alphanumeric characters, hyphens, and underscores.`),d=i}if(d=j(d),a.locale&&a.locale!==_){const i=U(v.join(a.locale.toLowerCase(),d));r=n.getRouteBySlug(i)}r||(r=n.getRouteBySlug(d)),r||(r=n.getRouteByFsPath(F(n.contentDir,s,a,d,t.fs)))}const g=r?.metadata;if(e?.$ref){let i=F(n.contentDir,s,a,e.$ref,t.fs);if(a.ref!==void 0&&(i=v.posix.join(a.ref,e.$ref)),!t.fs.exists(i))return await S.panicOnBuildContentError(`Failed to load ${i} file. Make sure sidebar $ref path is correct.`),[];const u=await t.cache.load(i,"yaml"),o=v.dirname(i);return await I(u.data,s,n,t,{...a,navFile:i,ref:o})||[]}if(!r){const i=a.excludedFromLinkCheckerPatterns?.catalog.some(o=>o.test(d||"")),u=a.excludedFromLinkCheckerPatterns?.apiFunctions.some(o=>o.test(d||e.href||""));(u||i)&&(e={...e,href:d||e.href,page:void 0,target:e.target??(u?"_blank":void 0)}),await X(e,a,t,s)}if(r&&!e.disconnect&&!a.ignoreCustomSidebar&&(l||r?.getSidebar)){const i=r.versions?.find(o=>o.active),u=i&&{version:i.version,isDefault:i.default,versionFolderId:i.folderId};if(l){let o=[];if(r.getSidebar&&(o=r.getSidebar(r,{...e,...await P(e,n,t,a)}),o&&o.length>0)){const h=o[0];h&&h.link&&(h.link=`${h.link}#${l}`)}if(!o||o.length===0){let h=e.group||e.label||l;o=[{type:"link",fsPath:r.fsPath,metadata:r.metadata,link:`${r.slug}#${l}`,routeSlug:r.slug,label:h,labelTranslationKey:e.labelTranslationKey,...await P(e,n,t,a),[p]:r[p],[b]:{slug:r.slug,fsPath:r.fsPath},...u}]}return k(o,u,r[p],r[b])}if(r?.getSidebar){const o=r.getSidebar(r,{...e,...await P(e,n,t,a)}),h=e.group&&o?.[0]?.routeSlug===r.slug?o.slice(1):o;return k(a.groupCustomSidebars||e.group?[{type:"group",fsPath:r.fsPath,link:r.slug,routeSlug:r.slug,label:e.group||e.label||await r.getNavText?.()||r.slug,items:h,labelTranslationKey:e.labelTranslationKey,metadata:g,...await P(e,n,t,a)}]:o,u,r[p],r[b])}}if(r&&!e.group){const i=l?`${r.slug}#${l}`:r.slug;let u=e.label||l||"";u||(u=await r.getNavText?.()||r.slug);const o=r.versions?.find(m=>m.active),h=o&&{version:o.version,isDefault:o.default,versionFolderId:o.folderId};return{type:"link",fsPath:r.fsPath,linkedSidebars:e.linkedSidebars,metadata:g,[p]:e?.rbac||r[p],[b]:{slug:r.slug,fsPath:r.fsPath},label:u,labelTranslationKey:e.labelTranslationKey,link:i,items:await I(e.items,s,n,t,a),separatorLine:e.separatorLine,linePosition:e.linePosition,routeSlug:e.disconnect?void 0:i,external:e.external,target:e.target,badges:e.badges,...await P(e,n,t,a),...h,additionalProps:e.additionalProps}}else if(e?.group){const i=r?.versions?.find(o=>o.active),u=R(a?.navFile);return{type:"group",fsPath:r?.fsPath,linkedSidebars:e.linkedSidebars,metadata:g,version:i?.version||u?.versionName,versionFolderId:i?.folderId||(u?.versionFolderPath?C(u.versionFolderPath):void 0),label:e.group,link:r?.slug,routeSlug:r?.slug,badges:e.badges,labelTranslationKey:e.groupTranslationKey,items:await I(e.items,s,n,t,a),expanded:e.expanded?e.expanded.toString():void 0,selectFirstItemOnExpand:e.selectFirstItemOnExpand,menuStyle:e.menuStyle,separatorLine:e.separatorLine,linePosition:e.linePosition,...await P(e,n,t,a),[p]:e?.rbac,[b]:{slug:r?.slug||"",fsPath:r?.fsPath||""},additionalProps:e.additionalProps}}else{if(e?.href||e?.label)return{type:"link",metadata:g,link:e.href||"",label:e?.label||e?.href||"",labelTranslationKey:e.labelTranslationKey,external:e.external,target:e.target,separatorLine:e.separatorLine,linePosition:e.linePosition,badges:e.badges,...await P(e,n,t,a),[p]:e?.rbac,additionalProps:e.additionalProps};if(e?.separator!=null||e?.separatorLine!=null){const i=R(a?.navFile);return{type:"separator",metadata:g,version:i?.versionName,versionFolderId:i?.versionFolderPath?C(i.versionFolderPath):void 0,label:e.separator,labelTranslationKey:e.separatorTranslationKey,separatorLine:e.separatorLine,linePosition:e.linePosition,...await P(e,n,t,a),[p]:e?.rbac,additionalProps:e.additionalProps}}else{const i=R(a?.navFile);return{type:"error",label:`Can't resolve page: ${JSON.stringify(e)}`,version:i?.versionName,versionFolderId:i?.versionFolderPath?C(i.versionFolderPath):void 0}}}}async function X(e,s,n,t){const{href:a,page:f}=e;if(a||!f)return;const d=F(n.fs.cwd,t,s,f,n.fs),r=n.fs.exists(d),l=await n.isPathIgnored(d),g=(r?"The page is ignored: ":"Can't resolve page: ")+f;(!r||l)&&S.reportBrokenLink({type:"BROKEN_LINK",brokenLinkType:"LINK",title:e.label||e.group||"",link:d,rawLink:f,message:g,sourceFileRelativePath:s.navFile,sourceFileLocation:{line:0}})}function F(e,s,n,t="",a){if(n.ref!==void 0)return w(v.relative(e,v.resolve(e,v.join(n.ref,t))));if(t.startsWith("/")){const f=B(s)?q(s):void 0,d=f?`${a.localizationFolder}/${f}/`:"",r=t.slice(1);return B(r)?r:d+w(r)}return w(v.relative(e,v.resolve(e,s,t)))}function Z(e,s){const n={};for(const r of e){const l=v.dirname(r.relativePathFromDirectory),g=r.version?M+r.version:"",i=v.basename(r.relativePathFromDirectory)+g;d(l,r,i)}const t=f(a(n));return T(t,s);function a(r){const l=[];for(const g of Object.keys(r)){const i=r[g];l.push({...i,items:i.items?a(i.items):void 0})}return l}function f(r){return r.sort((l,g)=>{const i=typeof l=="string"?l.toLowerCase():l.relativePathFromDirectory||l.label||"",u=typeof g=="string"?g.toLowerCase():g.relativePathFromDirectory||g.label||"";return i.startsWith("index.")?-1:u.startsWith("index.")?1:i.localeCompare(u,void 0,{numeric:!0})})}function d(r,l,g){r==="."&&(r="");const i=r.split("/").filter(Boolean);let u=n;for(const o of i){const h=o+(l?.version||"");u[h]||(u[h]={type:"group",version:l?.version,label:o,isDefault:l?.isDefault,versionFolderId:l.versionFolderId,items:{}}),u=u[h].items}u[g]=l}}function T(e,s){return e.flatMap(n=>n?.sidebarItems?s.groupCustomSidebars?{...n,items:n.sidebarItems,sidebarItems:void 0,relativePathFromDirectory:void 0}:n.sidebarItems:{...n,items:n.items?T(n.items,s):void 0})}function k(e,s,n,t){return e.map(a=>({...a,...s,[p]:a[p]||n,[b]:a[b]||t,items:a.type==="group"&&a.items?k(a.items,s,n):a.items}))}function ee(e){return e.replace(/@[^\/]+\//,"")}async function Pe(e,s,n,t){const a=(e?.items||[]).filter(r=>r.linkedSidebars?.length).map(r=>({...r,items:void 0})),f=await D(a,s.contentDir,s,n,t),d=new Map;for(const r of f)if(r.linkedSidebars?.length)for(const l of r.linkedSidebars){if(d.has(l)){A.warn(`Only one navbar item can belong to sidebar. "${l}" on 'linkedSidebars' property on "${r.label}" will be ignored.`);continue}d.set(l,{label:r.label,link:r.link})}return d}export{Pe as collectItemsLinkedToSidebars,N as normalizeItems,K as resolveItem,I as resolveItems,D as resolveLinksFromConfig};
|
|
1
|
+
import*as v from"path";import{REDOCLY_ROUTE_RBAC as b,REDOCLY_TEAMS_RBAC as p}from"@redocly/config";import{VERSION_SEPARATOR as M}from"../constants/common.js";import{DEFAULT_LOCALE_PLACEHOLDER as _}from"../../constants/common.js";import{removeTrailingSlash as j}from"../../utils/url/remove-trailing-slash.js";import{isPrimitive as W}from"../../utils/guards/is-primitive.js";import{slash as w}from"../../utils/path/slash.js";import{isAbsoluteUrl as z}from"../../utils/url/is-absolute-url.js";import{normalizeRouteSlug as U}from"../../utils/path/normalize-route-slug.js";import{parsePathVersions as R}from"../../utils/path/parse-path-versions.js";import{logger as A}from"../tools/notifiers/logger.js";import{reporter as S}from"../tools/notifiers/reporter.js";import{shaDirPathShort as C}from"../utils/crypto/sha-dir-path-short.js";import{copyStaticFile as H,FileNotFoundError as E}from"../utils/fs.js";import{isIconPath as J,resolveAssetPath as Y}from"../utils/index.js";import{resolveSrcSet as G}from"../utils/resolve-src-set.js";import{isL10nPath as B}from"../fs/utils/is-l10n-path.js";import{getLocaleFromRelativePath as q}from"../fs/utils/get-locale-from-relative-path.js";async function D(e,s,n,t,a){if(!e)return;const f={...a,ignoreCustomSidebar:!0};if(W(e)){if(typeof e=="string"){const r=F(n.contentDir,s,a,e,t.fs);if(t.fs.exists(r)){if(n.getRouteByFsPath(r))return K({page:e},s,n,t,f);{const g=t.fs.getFileInfo(r);return g?H(n.contentDir,g.realRelativePath,n.outdir):void 0}}}return e}return Array.isArray(e)?I(N(e),s,n,t,f):Object.fromEntries(await Promise.all(Object.entries(e).map(async([r,l])=>[r,await D(l,s,n,t,a)])))}function N(e){return e.map(s=>({...s,items:s.items?N(s.items):void 0}))}async function I(e,s,n,t,a){if(Array.isArray(e))return(await Promise.all(e.map(f=>K(f,s,n,t,a)))).flatMap(f=>f)}async function P(e,s,n,t){let a,f;if(typeof e.icon=="object"){if("srcSet"in e.icon)try{a=await G(e.icon.srcSet,n.fs,{fromFileRelativePath:t.navFile,contentDir:s.contentDir,outdir:s.outdir})}catch(d){d instanceof E?await S.panicOnBuildContentError(`Cannot resolve "item.icon.srcSet" from ${t.navFile}: ${d.message}`):await S.panicOnBuild(`Cannot resolve "item.icon.srcSet" from ${t.navFile}: ${d.message}`)}}else if(typeof e.icon=="string")if(z(e.icon)||J(e.icon))try{f=await Y(e.icon,n.fs,{fromFileRelativePath:t.navFile,contentDir:s.contentDir,outdir:s.outdir})}catch(d){d instanceof E?await S.panicOnBuildContentError(`Cannot resolve "item.icon" from ${t.navFile}: file ${f} does not exist`):await S.panicOnBuild(`Cannot resolve "item.icon" from ${t.navFile}: ${d.message}`)}else f=e.icon;return{icon:f,srcSet:a}}function Q(e){return s=>{if(s.type==="link"||s.type==="group"){const n=s.metadata;return n?Object.entries(e).every(([t,a])=>Array.isArray(a)?a.some(f=>n[t]===f):n[t]===a):!1}return!0}}async function K(e,s,n,t,a){if(e?.directory&&e.items?.length)return{type:"error",label:`Can't have both "directory" and "items" in the nav item: ${JSON.stringify(e)}`};e?.directory&&e?.group&&(e={...e,directory:void 0,items:[{directory:e.directory}]});const f=e?.directory?F(n.contentDir,s,a,e.directory,t.fs):void 0;if(f!==void 0){const i=f===""?"":f+"/",{locale:u,ignoredRoutes:o}=a;let h=n.getAllRoutesForLocale(u).filter(c=>!o?.has(c.baseSlug||"")&&c.fsPath.startsWith(i)&&!c.excludeFromSidebar).sort((c,y)=>c.fsPath===y.fsPath?0:c.baseSlug.localeCompare(y.baseSlug,void 0,{numeric:!0}));const m=e.includeByMetadata?Q(e.includeByMetadata):Boolean;if(!h.length)return[];const $=(await Promise.all(h.map(async c=>{const y=c.versions?.find(x=>x.active),L=y&&{version:y.version,isDefault:y.default,versionFolderId:y.folderId},V=ee(v.posix.relative(f,c.fsPath)),O=c.getSidebar?.(c);return!a.ignoreCustomSidebar&&O?.length?{type:"group",fsPath:c.fsPath,metadata:c.metadata,link:c.slug,routeSlug:c.slug,label:await c.getNavText?.()||c.slug,[p]:c[p],[b]:c[b],sidebarItems:k(O,L,c[p],c[b]),...L,relativePathFromDirectory:v.relative(f,c.fsPath).replace(/@[^\/]+\//,"")}:{type:"link",fsPath:c.fsPath,metadata:c.metadata,[p]:c[p],[b]:c[b],label:await c.getNavText?.()||c.slug,link:c.slug,routeSlug:c.slug,...L,relativePathFromDirectory:V}}))).filter(m);return e.flatten?T($,a):Z($,a)}let d=typeof e=="string"?e:e?.page,r,l;if(d){if(d.includes("#")){const[i,u]=d.split("#");u?l=u:A.warn(`Invalid heading anchor format in sidebar: "${u}". Heading anchors should contain only alphanumeric characters, hyphens, and underscores.`),d=i}if(d=j(d),a.locale&&a.locale!==_){const i=U(v.join(a.locale.toLowerCase(),d));r=n.getRouteBySlug(i)}r||(r=n.getRouteBySlug(d)),r||(r=n.getRouteByFsPath(F(n.contentDir,s,a,d,t.fs)))}const g=r?.metadata;if(e?.$ref){let i=F(n.contentDir,s,a,e.$ref,t.fs);if(a.ref!==void 0&&(i=v.posix.join(a.ref,e.$ref)),!t.fs.exists(i))return await S.panicOnBuildContentError(`Failed to load ${i} file. Make sure sidebar $ref path is correct.`),[];const u=await t.cache.load(i,"yaml"),o=v.dirname(i);return await I(u.data,s,n,t,{...a,navFile:i,ref:o})||[]}if(!r){const i=a.excludedFromLinkCheckerPatterns?.catalog.some(o=>o.test(d||"")),u=a.excludedFromLinkCheckerPatterns?.apiFunctions.some(o=>o.test(d||e.href||""));(u||i)&&(e={...e,href:d||e.href,page:void 0,target:e.target??(u?"_blank":void 0)}),await X(e,a,t,s)}if(r&&!e.disconnect&&!a.ignoreCustomSidebar&&(l||r?.getSidebar)){const i=r.versions?.find(o=>o.active),u=i&&{version:i.version,isDefault:i.default,versionFolderId:i.folderId};if(l){let o=[];if(r.getSidebar&&(o=r.getSidebar(r,{...e,...await P(e,n,t,a)}),o&&o.length>0)){const h=o[0];h&&h.link&&(h.link=`${h.link}#${l}`)}if(!o||o.length===0){let h=e.group||e.label||l;o=[{type:"link",fsPath:r.fsPath,metadata:r.metadata,link:`${r.slug}#${l}`,routeSlug:r.slug,label:h,labelTranslationKey:e.labelTranslationKey,...await P(e,n,t,a),[p]:r[p],[b]:{slug:r.slug,fsPath:r.fsPath},...u}]}return k(o,u,r[p],r[b])}if(r?.getSidebar){const o=r.getSidebar(r,{...e,...await P(e,n,t,a)}),h=e.group&&o?.[0]?.routeSlug===r.slug?o.slice(1):o;return k(a.groupCustomSidebars||e.group?[{type:"group",fsPath:r.fsPath,link:r.slug,routeSlug:r.slug,label:e.group||e.label||await r.getNavText?.()||r.slug,items:h,labelTranslationKey:e.labelTranslationKey,metadata:g,badges:e.badges,...await P(e,n,t,a)}]:o,u,r[p],r[b])}}if(r&&!e.group){const i=l?`${r.slug}#${l}`:r.slug;let u=e.label||l||"";u||(u=await r.getNavText?.()||r.slug);const o=r.versions?.find(m=>m.active),h=o&&{version:o.version,isDefault:o.default,versionFolderId:o.folderId};return{type:"link",fsPath:r.fsPath,linkedSidebars:e.linkedSidebars,metadata:g,[p]:e?.rbac||r[p],[b]:{slug:r.slug,fsPath:r.fsPath},label:u,labelTranslationKey:e.labelTranslationKey,link:i,items:await I(e.items,s,n,t,a),separatorLine:e.separatorLine,linePosition:e.linePosition,routeSlug:e.disconnect?void 0:i,external:e.external,target:e.target,badges:e.badges,...await P(e,n,t,a),...h,additionalProps:e.additionalProps}}else if(e?.group){const i=r?.versions?.find(o=>o.active),u=R(a?.navFile);return{type:"group",fsPath:r?.fsPath,linkedSidebars:e.linkedSidebars,metadata:g,version:i?.version||u?.versionName,versionFolderId:i?.folderId||(u?.versionFolderPath?C(u.versionFolderPath):void 0),label:e.group,link:r?.slug,routeSlug:r?.slug,badges:e.badges,labelTranslationKey:e.groupTranslationKey,items:await I(e.items,s,n,t,a),expanded:e.expanded?e.expanded.toString():void 0,selectFirstItemOnExpand:e.selectFirstItemOnExpand,menuStyle:e.menuStyle,separatorLine:e.separatorLine,linePosition:e.linePosition,...await P(e,n,t,a),[p]:e?.rbac,[b]:{slug:r?.slug||"",fsPath:r?.fsPath||""},additionalProps:e.additionalProps}}else{if(e?.href||e?.label)return{type:"link",metadata:g,link:e.href||"",label:e?.label||e?.href||"",labelTranslationKey:e.labelTranslationKey,external:e.external,target:e.target,separatorLine:e.separatorLine,linePosition:e.linePosition,badges:e.badges,...await P(e,n,t,a),[p]:e?.rbac,additionalProps:e.additionalProps};if(e?.separator!=null||e?.separatorLine!=null){const i=R(a?.navFile);return{type:"separator",metadata:g,version:i?.versionName,versionFolderId:i?.versionFolderPath?C(i.versionFolderPath):void 0,label:e.separator,labelTranslationKey:e.separatorTranslationKey,separatorLine:e.separatorLine,linePosition:e.linePosition,...await P(e,n,t,a),[p]:e?.rbac,additionalProps:e.additionalProps}}else{const i=R(a?.navFile);return{type:"error",label:`Can't resolve page: ${JSON.stringify(e)}`,version:i?.versionName,versionFolderId:i?.versionFolderPath?C(i.versionFolderPath):void 0}}}}async function X(e,s,n,t){const{href:a,page:f}=e;if(a||!f)return;const d=F(n.fs.cwd,t,s,f,n.fs),r=n.fs.exists(d),l=await n.isPathIgnored(d),g=(r?"The page is ignored: ":"Can't resolve page: ")+f;(!r||l)&&S.reportBrokenLink({type:"BROKEN_LINK",brokenLinkType:"LINK",title:e.label||e.group||"",link:d,rawLink:f,message:g,sourceFileRelativePath:s.navFile,sourceFileLocation:{line:0}})}function F(e,s,n,t="",a){if(n.ref!==void 0)return w(v.relative(e,v.resolve(e,v.join(n.ref,t))));if(t.startsWith("/")){const f=B(s)?q(s):void 0,d=f?`${a.localizationFolder}/${f}/`:"",r=t.slice(1);return B(r)?r:d+w(r)}return w(v.relative(e,v.resolve(e,s,t)))}function Z(e,s){const n={};for(const r of e){const l=v.dirname(r.relativePathFromDirectory),g=r.version?M+r.version:"",i=v.basename(r.relativePathFromDirectory)+g;d(l,r,i)}const t=f(a(n));return T(t,s);function a(r){const l=[];for(const g of Object.keys(r)){const i=r[g];l.push({...i,items:i.items?a(i.items):void 0})}return l}function f(r){return r.sort((l,g)=>{const i=typeof l=="string"?l.toLowerCase():l.relativePathFromDirectory||l.label||"",u=typeof g=="string"?g.toLowerCase():g.relativePathFromDirectory||g.label||"";return i.startsWith("index.")?-1:u.startsWith("index.")?1:i.localeCompare(u,void 0,{numeric:!0})})}function d(r,l,g){r==="."&&(r="");const i=r.split("/").filter(Boolean);let u=n;for(const o of i){const h=o+(l?.version||"");u[h]||(u[h]={type:"group",version:l?.version,label:o,isDefault:l?.isDefault,versionFolderId:l.versionFolderId,items:{}}),u=u[h].items}u[g]=l}}function T(e,s){return e.flatMap(n=>n?.sidebarItems?s.groupCustomSidebars?{...n,items:n.sidebarItems,sidebarItems:void 0,relativePathFromDirectory:void 0}:n.sidebarItems:{...n,items:n.items?T(n.items,s):void 0})}function k(e,s,n,t){return e.map(a=>({...a,...s,[p]:a[p]||n,[b]:a[b]||t,items:a.type==="group"&&a.items?k(a.items,s,n):a.items}))}function ee(e){return e.replace(/@[^\/]+\//,"")}async function Pe(e,s,n,t){const a=(e?.items||[]).filter(r=>r.linkedSidebars?.length).map(r=>({...r,items:void 0})),f=await D(a,s.contentDir,s,n,t),d=new Map;for(const r of f)if(r.linkedSidebars?.length)for(const l of r.linkedSidebars){if(d.has(l)){A.warn(`Only one navbar item can belong to sidebar. "${l}" on 'linkedSidebars' property on "${r.label}" will be ignored.`);continue}d.set(l,{label:r.label,link:r.link})}return d}export{Pe as collectItemsLinkedToSidebars,N as normalizeItems,K as resolveItem,I as resolveItems,D as resolveLinksFromConfig};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{REDOCLY_TEAMS_RBAC as i}from"@redocly/config";import{combineUrls as
|
|
1
|
+
import{REDOCLY_TEAMS_RBAC as i}from"@redocly/config";import{combineUrls as p}from"@redocly/theme/core/utils";import{FEEDBACK_TYPES as c}from"../../../constants/common.js";import{normalizeRouteSlug as h}from"../../../utils/path/normalize-route-slug.js";function u(t){const{contentItems:o,sidebarItems:n,routeSlug:r,navItem:s}=t;let b=!0;for(const e of o){let a;switch(e.type){case"group":n.push({type:"separator",label:e.name,[i]:e[i]}),u({...t,contentItems:e.items,sidebarItems:n});break;case"tag":a=p(r,e.href);const m={type:"group",label:e.name,items:[],link:a,routeSlug:a,[i]:e[i]};n.push(m),u({routeSlug:r,contentItems:e.items,sidebarItems:m.items||[],navItem:s});break;case"operation":case"schema":case"rsrc":case"prompt":case"tool":e.isWebhook&&b&&(n.push({type:"separator",label:"Webhooks",variant:"secondary"}),b=!1),a=p(r,e.href),n.push({type:"link",label:e.name,httpVerb:e.type==="operation"?e.httpVerb:e.type,routeSlug:h(a),badges:e.badges,link:a,deprecated:e.deprecated,isAdditionalOperation:e.isAdditionalOperation,[i]:e[i]});break;case"section":if(e.depth===-1)continue;a=p(r,e.href);const l=e.href==="/",g={type:e.items.length?"group":"link",label:l&&s?.label?s.label:e.name,labelTranslationKey:s?.labelTranslationKey,routeSlug:a.split("#")[0]===r?r:h(a),link:a,items:[],...l&&s?.icon&&{icon:typeof s.icon=="object"?s.icon.srcSet:s.icon},...l&&s?.badges&&{badges:s.badges}};n.push(g),e.items.length&&u({routeSlug:r,contentItems:e.items,sidebarItems:g.items});break}}}function S({item:t}){return t.id===""?!0:t.type!=="group"||t.description!==""}const I=t=>(typeof t=="string"?t:t?.raw)?.replace(/\[(.*?)\][\[\(].*?[\]\)]/g,"$1")||"";function A(t){if(!t)return;let o="";const{type:n,settings:r}=t;switch(n){case c.RATING:o="Rate this section";break;case c.SENTIMENT:o="Was this section helpful?";break;case c.MOOD:o="Was this section helpful?";break;case c.COMMENT:o="Share your feedback about this section";break;case c.SCALE:o="How would you rate this section?";break}return{...t,settings:{...r,label:r?.label||o}}}function E(t){return(typeof t=="string"?t:t?.raw||"").replace(/<[^>]*>/g,"").replace(/```([\s\S]*?)```/g,"$1").replace(/`([^`]+)`/g,"$1").replace(/\*\*(.*?)\*\*/g,"$1").replace(/\*(.*?)\*/g,"$1").trim()}export{u as convertOpenAPIDocs2Sidebar,A as normalizeFeedbackOptions,I as removeMarkdownLinks,S as shouldAddRoute,E as stripFormatting};
|
|
@@ -9,4 +9,4 @@ import"../node-crypto-polyfill.js";import{DOMParser as b}from"@xmldom/xmldom";im
|
|
|
9
9
|
<samlp:NameIDPolicy
|
|
10
10
|
AllowCreate="true"
|
|
11
11
|
Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"/>
|
|
12
|
-
</samlp:AuthnRequest>`,s=ye(a);return{loginUrl:ee(t.ssoUrl,{SAMLRequest:s,RelayState:JSON.stringify({idpId:t.idpId,redirectTo:r,inviteCode:n,source:"portal"})})}}function ye(e){return ae(H(new TextEncoder().encode(e)).buffer)}function Ge(e){const t=P(e);if(t.startsWith("<samlp:Response")||t.indexOf("<saml2p:Response")>-1)return t;const r=J(new Uint8Array(atob(e).split("").map(n=>n.charCodeAt(0))));return new TextDecoder().decode(r)}function Ze(e){try{return JSON.parse(P(e||""))}catch{throw new Error("Invalid OAuth2 state")}}function et(e){const t=new b().parseFromString(e,"application/xml"),n=i(t,"//*[local-name(.)='StatusCode']/@Value")[0]?.nodeValue?.endsWith("Success")||!1,a=i(t,"//*[local-name(.)='Response']/@Destination")[0]?.nodeValue||"",s=i(t,"//*[local-name(.)='Assertion']//*[local-name(.)='Issuer']/text()")[0],l=s&&s.nodeValue||void 0,m=i(t,"//*[local-name(.)='Audience']/text()")[0],A=m&&m.nodeValue||void 0,c=i(t,"//*[local-name(.)='Assertion']//*[local-name(.)='X509Certificate']/text()")[0]?.nodeValue||"",f=i(t,"//*[local-name(.)='Subject']//*[local-name(.)='NameID']/text()")[0],_=f&&f.nodeValue||"",h=i(t,"//*[local-name(.)='Subject']//*[local-name(.)='NameID']/@Format")[0],d=h&&h.nodeValue||"",x=i(t,"//*[local-name(.)='Conditions']/@NotOnOrAfter")[0],g=we(x),M={},C=i(t,"//*[local-name(.)='AttributeStatement']//*[local-name(.)='Attribute']");if(C.length)for(const T of C){const D=i(T,"./@Name")[0];if(D.nodeValue){const O=i(T,"./*[local-name(.)='AttributeValue']/text()")[0];O?.nodeValue&&(M[D.nodeValue]=O.nodeValue)}}return{uid:_,success:n,expiresAt:g,issuerId:l,entityId:A,attrs:M,cert:c,nameFormat:d,destination:a}}function we(e){const t=typeof e?.nodeValue=="string"&&L(Date.parse(e.nodeValue)),r=L(Date.now()),n=L(Date.now()+720*60*1e3);return t?t>r&&t<n?n:t:r}function L(e){return Math.floor(e/1e3)}const k={},w={jwks:{}};async function V(e,t){if(!k[e]){const r=t.configurationUrl?await $(t.configurationUrl):t.configuration;k[e]=Se()?Ae(r):r}return k[e]}function Se(){const e=Q.REDOCLY_ENFORCE_RESIDENCY;return!!e&&e.includes("host.docker.internal")}function Ae(e){if(typeof e!="object"||e===null)return e;const t={...e};for(const r of Object.keys(t)){const n=t[r];typeof n=="string"&&n.includes("://localhost")&&(t[r]=n.replace("://localhost","://host.docker.internal"))}return t}async function _e(e){for(const t of Object.keys(e)){const r=e[t];if(!E(r))continue;const n=await V(t,r);if(n.jwks_uri){const o=await $(n.jwks_uri);for(const a of o.keys)w.jwks[a.kid]={...a,idpId:t}}}}async function $(e){return fetch(e,{headers:{Accept:"application/json"}}).then(t=>t.json())}async function tt(e){return fetch(`${Y}/oidc/userinfo`,{headers:{Accept:"application/json",Authorization:`Bearer ${e}`}}).then(t=>t.status===200?t.json():void 0).catch(()=>{})}function nt(e){if(!e.configurationUrl)return!1;const t=new URL(e.configurationUrl);return["localhost","127.0.0.1","blueharvest.cloud","bhstage.cloud","cloud.redocly.com","beta.redocly.com","cloud.eu.redocly.com","beta.eu.redocly.com","cba.au.redocly.com"].some(n=>xe(t.hostname,n))}function xe(e,t){return e===t||e.endsWith(`.${t}`)}async function rt(e,t){const r=new b().parseFromString(e),n=i(r,"//*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']")[0];if(!n)throw new Error("Cannot find Signature in the SAML response");const o=ie(t),a=new B({publicCert:o});a.loadSignature(n);try{return a.checkSignature(e)}catch{return!1}}function ot(e,t,r,n){t==="urn:oasis:names:tc:SAML:2.0:nameid-format:transient"&&(e=r["http://schemas.microsoft.com/identity/claims/objectidentifier"]);let o;(t==="urn:oasis:names:tc:SAML:2.0:nameid-format:email"||t==="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress")&&(o=e),t==="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"&&e?.match(/.+@.+/)&&(o=e);const a=r["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"],s=a?.match(/.+@.+/);return o=o||r["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"]||(s?a:void 0),o=o?.toLowerCase(),{sub:e,given_name:r["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname"],family_name:r["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname"],name:r["http://schemas.microsoft.com/identity/claims/displayname"]||a,email:o,email_verified:!0,teams:n?oe(r[n]):[]}}function z(e,t={}){return e.map(r=>t[r]||r)}async function at(e,t){if(!t)return{};const r=t.authorization;if(!r)return{};try{const n=p.decode(r);if(n.header.alg===y.RS256){w.jwks[n.header.kid]===void 0&&await _e(e);const m=w.jwks[n.header.kid];if(!m)return w.jwks[n.header.kid]=null,{};await p.verify(r,m,y.RS256)}else await p.verify(r,I,y.HS256);const o=n.payload.idpId||w.jwks[n.header.kid]?.idpId,a=e[o]||{},s=Le(a),l=Ie(a);return{...n.payload,email:n.payload.email?.toLowerCase(),idpId:o,teams:Array.from(new Set([...z(n.payload.teams||[],l),..."defaultTeams"in a&&a.defaultTeams||[],...z("teamsClaimName"in a&&n.payload[s||""]||[],l),Z])),name:ge(n.payload),isAuthenticated:!0,idpAccessToken:n.payload.idp_access_token||t.idp_access_token,federatedAccessToken:t.federated_access_token,federatedIdToken:t.federated_id_token,authCookie:r}}catch(n){n instanceof re||te.error("Malformed JWT token: %s",n.message)}return{}}function ge(e){return(e.firstName&&e.lastName?`${e.firstName} ${e.lastName}`:e.name||e.given_name||e.firstName||e.lastName)||e.email}function Ie(e){switch(e.type){case u.SAML2:return e.teamsAttributeMap;case u.OIDC:return e.teamsClaimMap;default:return}}function Le(e){switch(e.type){case u.SAML2:return e.teamsAttributeName;case u.OIDC:return e.teamsClaimName;default:return K}}function i(e,t){return F.select(t,e)||[]}export{Xe as buildLoginUrl,me as buildOidcLoginUrl,We as buildOidcLogoutUrl,he as buildSAML2LoginUrl,Ke as createMcpAuthorizationCode,Qe as createMcpSessionResource,Ge as decodeSamlResponse,ye as encodeSAML2,ot as extractUserClaims,Je as getAuthProviderLoginParams,ue as getOidcLoginParams,V as getOidcMetadata,tt as getRedoclyTokenPayload,de as getSaml2LoginParams,at as getUserParamsFromCookies,ge as getUsernameFromPayload,E as isOidcProviderConfig,nt as isRedoclySso,ce as isSaml2ProviderConfig,qe as oidcExchangeCodeForToken,w as oidcJwksCache,k as oidcMetadataCache,Ze as parseOidcState,le as parsePreviewBranch,et as parseSamlResponse,j as rewritePreviewAuthRedirectUri,Ye as verifyMcpAuthorizationCode,rt as verifySAMLResponse};
|
|
12
|
+
</samlp:AuthnRequest>`,s=ye(a);return{loginUrl:ee(t.ssoUrl,{SAMLRequest:s,RelayState:JSON.stringify({idpId:t.idpId,redirectTo:r,inviteCode:n,source:"portal"})})}}function ye(e){return ae(H(new TextEncoder().encode(e)).buffer)}function Ge(e){const t=P(e);if(t.startsWith("<samlp:Response")||t.indexOf("<saml2p:Response")>-1)return t;const r=J(new Uint8Array(atob(e).split("").map(n=>n.charCodeAt(0))));return new TextDecoder().decode(r)}function Ze(e){try{return JSON.parse(P(e||""))}catch{throw new Error("Invalid OAuth2 state")}}function et(e){const t=new b().parseFromString(e,"application/xml"),n=i(t,"//*[local-name(.)='StatusCode']/@Value")[0]?.nodeValue?.endsWith("Success")||!1,a=i(t,"//*[local-name(.)='Response']/@Destination")[0]?.nodeValue||"",s=i(t,"//*[local-name(.)='Assertion']//*[local-name(.)='Issuer']/text()")[0],l=s&&s.nodeValue||void 0,m=i(t,"//*[local-name(.)='Audience']/text()")[0],A=m&&m.nodeValue||void 0,c=i(t,"//*[local-name(.)='Assertion']//*[local-name(.)='X509Certificate']/text()")[0]?.nodeValue||"",f=i(t,"//*[local-name(.)='Subject']//*[local-name(.)='NameID']/text()")[0],_=f&&f.nodeValue||"",h=i(t,"//*[local-name(.)='Subject']//*[local-name(.)='NameID']/@Format")[0],d=h&&h.nodeValue||"",x=i(t,"//*[local-name(.)='Conditions']/@NotOnOrAfter")[0],g=we(x),M={},C=i(t,"//*[local-name(.)='AttributeStatement']//*[local-name(.)='Attribute']");if(C.length)for(const T of C){const D=i(T,"./@Name")[0];if(D.nodeValue){const O=i(T,"./*[local-name(.)='AttributeValue']/text()")[0];O?.nodeValue&&(M[D.nodeValue]=O.nodeValue)}}return{uid:_,success:n,expiresAt:g,issuerId:l,entityId:A,attrs:M,cert:c,nameFormat:d,destination:a}}function we(e){const t=typeof e?.nodeValue=="string"&&L(Date.parse(e.nodeValue)),r=L(Date.now()),n=L(Date.now()+720*60*1e3);return t?t>r&&t<n?n:t:r}function L(e){return Math.floor(e/1e3)}const k={},w={jwks:{}};async function V(e,t){if(!k[e]){const r=t.configurationUrl?await $(t.configurationUrl):t.configuration;k[e]=Se()?Ae(r):r}return k[e]}function Se(){const e=Q.REDOCLY_ENFORCE_RESIDENCY;return!!e&&e.includes("host.docker.internal")}function Ae(e){if(typeof e!="object"||e===null)return e;const t={...e};for(const r of Object.keys(t)){const n=t[r];typeof n=="string"&&n.includes("://localhost")&&(t[r]=n.replace("://localhost","://host.docker.internal"))}return t}async function _e(e){for(const t of Object.keys(e)){const r=e[t];if(!E(r))continue;const n=await V(t,r);if(n.jwks_uri){const o=await $(n.jwks_uri);for(const a of o.keys)w.jwks[a.kid]={...a,idpId:t}}}}async function $(e){return fetch(e,{headers:{Accept:"application/json"}}).then(t=>t.json())}async function tt(e){return fetch(`${Y}/oidc/userinfo`,{headers:{Accept:"application/json",Authorization:`Bearer ${e}`}}).then(t=>t.status===200?t.json():void 0).catch(()=>{})}function nt(e){if(!e.configurationUrl)return!1;const t=new URL(e.configurationUrl);return["localhost","127.0.0.1","blueharvest.cloud","bhstage.cloud","cloud.redocly.com","beta.redocly.com","cloud.eu.redocly.com","beta.eu.redocly.com","cba.au.redocly.com"].some(n=>xe(t.hostname,n))}function xe(e,t){return e===t||e.endsWith(`.${t}`)}async function rt(e,t){const r=new b().parseFromString(e,"application/xml"),n=i(r,"//*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']")[0];if(!n)throw new Error("Cannot find Signature in the SAML response");const o=ie(t),a=new B({publicCert:o});a.loadSignature(n);try{return a.checkSignature(e)}catch{return!1}}function ot(e,t,r,n){t==="urn:oasis:names:tc:SAML:2.0:nameid-format:transient"&&(e=r["http://schemas.microsoft.com/identity/claims/objectidentifier"]);let o;(t==="urn:oasis:names:tc:SAML:2.0:nameid-format:email"||t==="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress")&&(o=e),t==="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"&&e?.match(/.+@.+/)&&(o=e);const a=r["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"],s=a?.match(/.+@.+/);return o=o||r["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"]||(s?a:void 0),o=o?.toLowerCase(),{sub:e,given_name:r["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname"],family_name:r["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname"],name:r["http://schemas.microsoft.com/identity/claims/displayname"]||a,email:o,email_verified:!0,teams:n?oe(r[n]):[]}}function z(e,t={}){return e.map(r=>t[r]||r)}async function at(e,t){if(!t)return{};const r=t.authorization;if(!r)return{};try{const n=p.decode(r);if(n.header.alg===y.RS256){w.jwks[n.header.kid]===void 0&&await _e(e);const m=w.jwks[n.header.kid];if(!m)return w.jwks[n.header.kid]=null,{};await p.verify(r,m,y.RS256)}else await p.verify(r,I,y.HS256);const o=n.payload.idpId||w.jwks[n.header.kid]?.idpId,a=e[o]||{},s=Le(a),l=Ie(a);return{...n.payload,email:n.payload.email?.toLowerCase(),idpId:o,teams:Array.from(new Set([...z(n.payload.teams||[],l),..."defaultTeams"in a&&a.defaultTeams||[],...z("teamsClaimName"in a&&n.payload[s||""]||[],l),Z])),name:ge(n.payload),isAuthenticated:!0,idpAccessToken:n.payload.idp_access_token||t.idp_access_token,federatedAccessToken:t.federated_access_token,federatedIdToken:t.federated_id_token,authCookie:r}}catch(n){n instanceof re||te.error("Malformed JWT token: %s",n.message)}return{}}function ge(e){return(e.firstName&&e.lastName?`${e.firstName} ${e.lastName}`:e.name||e.given_name||e.firstName||e.lastName)||e.email}function Ie(e){switch(e.type){case u.SAML2:return e.teamsAttributeMap;case u.OIDC:return e.teamsClaimMap;default:return}}function Le(e){switch(e.type){case u.SAML2:return e.teamsAttributeName;case u.OIDC:return e.teamsClaimName;default:return K}}function i(e,t){return F.select(t,e)||[]}export{Xe as buildLoginUrl,me as buildOidcLoginUrl,We as buildOidcLogoutUrl,he as buildSAML2LoginUrl,Ke as createMcpAuthorizationCode,Qe as createMcpSessionResource,Ge as decodeSamlResponse,ye as encodeSAML2,ot as extractUserClaims,Je as getAuthProviderLoginParams,ue as getOidcLoginParams,V as getOidcMetadata,tt as getRedoclyTokenPayload,de as getSaml2LoginParams,at as getUserParamsFromCookies,ge as getUsernameFromPayload,E as isOidcProviderConfig,nt as isRedoclySso,ce as isSaml2ProviderConfig,qe as oidcExchangeCodeForToken,w as oidcJwksCache,k as oidcMetadataCache,Ze as parseOidcState,le as parsePreviewBranch,et as parseSamlResponse,j as rewritePreviewAuthRedirectUri,Ye as verifyMcpAuthorizationCode,rt as verifySAMLResponse};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Context } from 'hono';
|
|
2
|
-
|
|
2
|
+
import type { Store } from '../../store.js';
|
|
3
|
+
export declare function corsProxyHandler(store?: Store, proxyBasePath?: string): (ctx: Context) => Promise<Response>;
|
|
3
4
|
export declare function isPrivateIp(ip: string): boolean;
|
|
4
5
|
export declare function resolveCorsProxyTarget(requestUrl: string, proxyBasePath: string): URL | null;
|
|
5
6
|
export declare const CORS_PROXY_STREAM_HEADER = "x-redocly-proxy-streaming";
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import
|
|
2
|
-
Usage: ${
|
|
1
|
+
import x from"node:dns";import{isIP as $}from"node:net";import{withPathPrefix as D}from"@redocly/theme/core/utils";import{ServerRoutes as L}from"../../../constants/common.js";import{envConfig as E}from"../../config/env-config.js";import{getRequestOrigin as k}from"../utils/get-request-origin.js";const A=new Set(["connection","keep-alive","proxy-authenticate","proxy-connection","proxy-authorization","te","trailer","transfer-encoding","upgrade","host"]),I=new Set(["cookie","cookie2","accept-encoding"]),M=new Set(["set-cookie","set-cookie2","content-encoding","content-length"]),y="x-redocly-proxy-streaming",H="x-http-method-override",S="x-redocly-cookie";function ee(o,e=D(L.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=j(t.req.url,e);if(!s)return t.text("Invalid proxied URL",400);const a=o?.getConfig().corsProxy?.allowedTargets;if(a&&a.length>0&&!a.some(u=>X(s,u)))return t.text("Target URL is not in the allowed list for CORS proxy",403);const f=k(t),h=s.origin===f,m=s.pathname===e||s.pathname.startsWith(`${e}/`);if(h&&!m)return new Response("Please use a direct request",{status:308,headers:{Location:s.toString(),Vary:"origin","Cache-Control":"private"}});const l=await N(s.hostname);if((!E.isDevelopMode||E.isReunite)&&l&&Y(l))return t.text("Requests to private network addresses are not allowed",403);const i=new Headers,P=v(t.req.raw.headers);for(const[n,u]of t.req.raw.headers)P.has(n.toLowerCase())||I.has(n.toLowerCase())||i.append(n,u);const g=i.get(S);if(g){const n=t.req.raw.headers.get("cookie")||"";i.set("cookie",n?`${n}; ${g}`:g),i.delete(S)}const O=t.req.raw.headers.get("origin")||"";z(O)&&i.delete("origin");let p=t.req.method;const R=i.get(H);R&&(p=R.toUpperCase(),i.delete(H));const w={method:p,headers:i,redirect:"manual"};p!=="GET"&&p!=="HEAD"&&t.req.raw.body&&(w.body=t.req.raw.body,w.duplex="half");let c;try{c=await fetch(s,w)}catch(n){const u=n instanceof Error?n.message:"unknown error",_=n instanceof Error&&n.cause instanceof Error?`: ${n.cause.message}`:"";return t.text(`Failed to proxy request: ${u}${_}`,502)}const T=c.headers.get("content-type")||"";if(V(T)&&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),q=v(c.headers);for(const n of q)d.delete(n);for(const n of M)d.delete(n);return d.set(y,"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 W(o){try{return decodeURIComponent(o)}catch{return o}}function b(o){return o.replace(/^(https?):\/(?!\/)/i,"$1://")}function U(o,e){return e?o.includes("?")?e==="?"?o:`${o.endsWith("?")||o.endsWith("&")?o:`${o}&`}${e.slice(1)}`:`${o}${e}`:o}function v(o){const e=new Set(A),t=o.get("connection");if(!t)return e;for(const r of t.split(",")){const s=r.trim().toLowerCase();s&&e.add(s)}return e}function z(o){const e=o.toLowerCase();return e.includes(".redocly.app")||e.includes("localhost")}async function N(o){if($(o))return o;try{const{address:e}=await x.promises.lookup(o);return e}catch{return null}}function Y(o){const e=o.match(/^::ffff:(\d+\.\d+\.\d+\.\d+)$/i);return e?C(e[1]):o.includes(":")?F(o):C(o)}function C(o){const e=o.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 F(o){const e=o.toLowerCase();return e==="::1"||e==="::"||e.startsWith("fc")||e.startsWith("fd")||e.startsWith("fe80")}function X(o,e){let t;try{t=new URL(e)}catch{return!1}if(o.origin!==t.origin)return!1;const r=t.pathname.endsWith("/")?t.pathname:`${t.pathname}/`;return o.pathname.startsWith(r)||o.pathname===t.pathname}function V(o){const e=o.toLowerCase();return e.includes("text/html")||e.includes("javascript")||e.includes("application/xhtml")||e.includes("application/xml")||e.includes("image/svg")}function j(o,e){const t=new URL(o),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 f=[a,W(a)];for(const h of f){const m=b(h),l=U(m,t.search);try{const i=new URL(l);if(i.protocol==="http:"||i.protocol==="https:")return i}catch{continue}}return null}const te=y;export{te as CORS_PROXY_STREAM_HEADER,ee as corsProxyHandler,Y as isPrivateIp,j as resolveCorsProxyTarget};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{serveStatic as C}from"hono/serve-static";import{withPathPrefix as e,withoutPathPrefix as H}from"@redocly/theme/core/utils";import{ServerRoutes as i}from"../../../constants/common.js";import{PUBLIC_STATIC_FOLDER as c}from"../../constants/common.js";import{envConfig as L}from"../../config/env-config.js";import{authMiddleware as S}from"../middleware/authMiddleware.js";import{ensureSearchData as g}from"../middleware/ensureSearchData.js";import{dynamicMiddleware as P}from"../middleware/dynamic-middleware/dynamic-middleware.js";import{installRoutes as I}from"../../plugins/dev-onboarding/api/routes/index.js";import{authorizeHandler as D,oidcCallbackHandler as h,logoutHandler as O,postLogoutHandler as M,idpLoginHandler as N,redoclyLoginCallbackHandler as v,samlCallbackHandler as B,redoclyTokenLoginHandler as w,inviteHandler as U}from"./auth.js";import{appDataHandler as G}from"./app-data.js";import{searchFacetsHandler as F,searchHandler as y}from"./search.js";import{dynamicRouteHandler as K}from"./dynamic-route.js";import{pageDataHandler as Y,sharedPageDataHandler as k}from"./page-data.js";import{pathPrefixRedirectHandler as b}from"./path-prefix-redirect.js";import{getRoutesByLineHandler as _,resolvePathHandler as E,resolvePathsHandler as V,resolveSlugHandler as T}from"./resolve-route.js";import{feedbackHandler as x}from"./feedback.js";import{loggerMiddleware as $}from"../middleware/loggerMiddleware.js";import{responseHeadersMiddleware as z}from"../middleware/responseHeadersMiddleware.js";import{idleTimeoutMiddleware as Z}from"../middleware/idleTimeoutMiddleware.js";import{otelTracesHandler as X}from"./otel/otel.js";import{healthCheckHandler as q}from"./health.js";import{askAiHandler as W}from"./ask-ai.js";import{semanticSearchHandler as j}from"./semantic-search.js";import{replayOauth2RedirectCallbackHandler as J}from"./replay-oauth2-redirect.js";import{corsProxyHandler as r}from"./cors-proxy.js";import{mcpOAuthProtectedResourceHandler as Q,mcpOAuthAuthorizationServerHandler as u,mcpDynamicClientRegistrationHandler as aa,mcpAuthorizationHandler as ea,mcpTokenPortalHandler as ia,mcpCallbackHandler as f}from"./mcp-oauth.js";import{corsMiddleware as d}from"../middleware/corsMiddleware.js";import{installApiRoutes as la}from"./api-routes/api-routes.js";import{cookieMiddleware as ta}from"../middleware/cookieMiddleware.js";import{staticContentHandler as ma}from"../routes/static-content.js";import{infoHandler as
|
|
1
|
+
import{serveStatic as C}from"hono/serve-static";import{withPathPrefix as e,withoutPathPrefix as H}from"@redocly/theme/core/utils";import{ServerRoutes as i}from"../../../constants/common.js";import{PUBLIC_STATIC_FOLDER as c}from"../../constants/common.js";import{envConfig as L}from"../../config/env-config.js";import{authMiddleware as S}from"../middleware/authMiddleware.js";import{ensureSearchData as g}from"../middleware/ensureSearchData.js";import{dynamicMiddleware as P}from"../middleware/dynamic-middleware/dynamic-middleware.js";import{installRoutes as I}from"../../plugins/dev-onboarding/api/routes/index.js";import{authorizeHandler as D,oidcCallbackHandler as h,logoutHandler as O,postLogoutHandler as M,idpLoginHandler as N,redoclyLoginCallbackHandler as v,samlCallbackHandler as B,redoclyTokenLoginHandler as w,inviteHandler as U}from"./auth.js";import{appDataHandler as G}from"./app-data.js";import{searchFacetsHandler as F,searchHandler as y}from"./search.js";import{dynamicRouteHandler as K}from"./dynamic-route.js";import{pageDataHandler as Y,sharedPageDataHandler as k}from"./page-data.js";import{pathPrefixRedirectHandler as b}from"./path-prefix-redirect.js";import{getRoutesByLineHandler as _,resolvePathHandler as E,resolvePathsHandler as V,resolveSlugHandler as T}from"./resolve-route.js";import{feedbackHandler as x}from"./feedback.js";import{loggerMiddleware as $}from"../middleware/loggerMiddleware.js";import{responseHeadersMiddleware as z}from"../middleware/responseHeadersMiddleware.js";import{idleTimeoutMiddleware as Z}from"../middleware/idleTimeoutMiddleware.js";import{otelTracesHandler as X}from"./otel/otel.js";import{healthCheckHandler as q}from"./health.js";import{askAiHandler as W}from"./ask-ai.js";import{semanticSearchHandler as j}from"./semantic-search.js";import{replayOauth2RedirectCallbackHandler as J}from"./replay-oauth2-redirect.js";import{corsProxyHandler as r}from"./cors-proxy.js";import{mcpOAuthProtectedResourceHandler as Q,mcpOAuthAuthorizationServerHandler as u,mcpDynamicClientRegistrationHandler as aa,mcpAuthorizationHandler as ea,mcpTokenPortalHandler as ia,mcpCallbackHandler as f}from"./mcp-oauth.js";import{corsMiddleware as d}from"../middleware/corsMiddleware.js";import{installApiRoutes as la}from"./api-routes/api-routes.js";import{cookieMiddleware as ta}from"../middleware/cookieMiddleware.js";import{staticContentHandler as ma}from"../routes/static-content.js";import{infoHandler as R}from"./info.js";import{catalogHandler as na}from"./catalog/catalog.js";import{catalogRelationsHandler as da}from"./catalog/catalog-relations.js";import{bffCatalogHandler as oa}from"./catalog/bff-catalog.js";import{bffCatalogRevisionsHandler as pa}from"./catalog/bff-catalog-revisions.js";import{bffCatalogRelatedEntitiesHandler as Aa}from"./catalog/bff-catalog-related-entities.js";import{catalogAuthMiddleware as t}from"../middleware/catalogAuthMiddleware.js";import{telemetryMiddleware as Oa}from"../middleware/telemetry-middleware.js";import{errorHandler as _a}from"./error.js";function ae(a,l,m){const{resolveRouteData:o,readStaticAsset:p}=m;a.use("*",Z()),a.use("*",ta()),a.use("*",P(l)),a.use("*",S(l)),a.use("*",$()),a.use("*",z(l)),a.use("*",Oa()),a.use(e("*"),C({root:`./${c}`,getContent:(n,s)=>ma(n,s,l,p),rewriteRequestPath:n=>H(n)})),a.use(e(i.FEEDBACK),d({allowMethods:["POST"]})),a.use(e(i.ASK_AI),d({allowMethods:["POST"]})),a.use(e(i.SEMANTIC_SEARCH),d({allowMethods:["POST"]})),a.use("*",Ea(l));const A=g(l);a.use(e(i.INFO),R()),L.NEW_CATALOG_ENABLED==="true"&&(a.use(e(i.CATALOG_ENTITIES),t({serverOutDir:l.serverOutDir}),na(l)),a.use(e(i.CATALOG_ENTITIES_RELATIONS),t({serverOutDir:l.serverOutDir}),da(l)),a.get(e(i.BFF_CATALOG_ENTITIES),t({serverOutDir:l.serverOutDir,protectReadMethods:!1}),oa(l)),a.get(e(i.BFF_CATALOG_RELATED_ENTITIES),t({serverOutDir:l.serverOutDir,protectReadMethods:!1}),Aa(l)),a.get(e(i.BFF_CATALOG_REVISIONS),t({serverOutDir:l.serverOutDir,protectReadMethods:!1}),pa(l))),a.get(e(i.SHARED_PAGE_DATA),k(l)),a.get(e(i.PAGE_DATA),Y(l,o)),a.get(e(i.APP_DATA),G(l)),a.post(e(i.SEARCH),A,y(l)),a.post(e(i.SEARCH_FACETS),A,F(l)),a.post(e(i.AUTHORIZATION),D),a.post(e(i.LOGOUT),O(l)),a.get(e(i.LOGOUT),O(l)),a.get(e(i.POST_LOGOUT),M(l)),a.get(e(i.OIDC_CALLBACK),h(l)),a.get(e(i.REDOCLY_TOKEN_LOGIN),w(l)),a.get(e(i.REDOCLY_LOGIN_CALLBACK),v()),a.get(e(i.IDP_LOGIN),N(l)),a.post(e(i.SAML_CALLBACK),B(l)),a.get(e(i.INVITE),U(l)),a.get(e(i.HEALTH),q),a.get(`${i.MCP_OAUTH_PROTECTED_RESOURCE}${e("/mcp")}`,Q()),a.get(i.MCP_OAUTH_AUTHORIZATION_SERVER,u()),a.post(e(i.MCP_DYNAMIC_CLIENT_REGISTRATION),aa()),a.get(e(i.MCP_AUTHORIZATION),ea()),a.post(e(i.MCP_TOKEN_PORTAL),ia()),a.get(e(i.MCP_CALLBACK),f()),a.get(e(`${i.MCP_CALLBACK}/*`),f()),I(a,l),a.all(e(i.CORS_PROXY),r(l)),a.all(e(`${i.CORS_PROXY}/*`),r(l)),la(a,l),a.post(e(i.FEEDBACK),x(l)),a.post(e(i.RESOLVE_ROUTE_BY_PATH),E(l)),a.post(e(i.RESOLVE_ROUTES_BY_PATHS),V(l)),a.post(e(i.RESOLVE_ROUTE_BY_SLUG),T(l)),a.post(e(i.ASK_AI),W(l)),a.post(e(i.SEMANTIC_SEARCH),j(l)),a.get(e(i.GET_ROUTES_BY_LINE),_(l)),a.post(e(i.OTEL_TRACES),X),a.get(e(i.REPLAY_OAUTH2_CALLBACK),J),a.all(e("/*"),K(l,o,p)),a.get("*",b),a.onError(_a)}function Ea(a){return async(l,m)=>{await a.waitForPluginsLifecycle(),await m()}}function ee(a,l){a.get(e(i.INFO),R()),a.post(e(i.RESOLVE_ROUTE_BY_PATH),E(l)),a.post(e(i.RESOLVE_ROUTE_BY_SLUG),T(l)),a.get(e(i.GET_ROUTES_BY_LINE),_(l))}export{ee as installDevRoutes,ae as installProdRoutes,Ea as waitForPluginsLifecycle};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{getCookie as
|
|
1
|
+
import{getCookie as f}from"hono/cookie";import{ulid as S}from"ulid";import{AUTH_URL as k,JWT_SECRET_KEY as y}from"../../constants/common.js";import{ServerRoutes as p}from"../../../constants/common.js";import{withPathPrefix as l}from"@redocly/theme/core/utils";import{telemetry as _}from"../../telemetry/index.js";import{envConfig as C}from"../../config/env-config.js";import{createMcpAuthorizationCode as w,verifyMcpAuthorizationCode as A,createMcpSessionResource as u}from"../auth.js";import*as m from"../jwt/jwt.js";import{AlgorithmTypes as T}from"../jwt/types.js";import{getRequestOrigin as M}from"../utils/get-request-origin.js";const n=(e,r,o=200,a)=>e.json(r,o,{"Content-Type":"application/json",...a??{}});async function I(e){const r=Math.floor(Date.now()/1e3);return m.sign({type:"mcp_context",...e,iat:r,exp:r+600},y,T.HS256)}async function P(e){await m.verify(e,y,T.HS256);const{payload:r}=m.decode(e);if(r.type!=="mcp_context")throw new Error("Invalid context token type");return r}function q(){return async e=>{if(e.req.method!=="GET")return n(e,{error:"Method not allowed"},405,{Allow:"GET"});const r=M(e);return n(e,{resource:`${r}${l("/mcp")}`,authorization_servers:[r],bearer_methods_supported:["header"],resource_documentation:`${r}${p.MCP_OAUTH_AUTHORIZATION_SERVER}`,scopes_supported:["openid","profile","email","offline_access"],bearer_token_types_supported:["Bearer"]})}}function b(){return async e=>{const r=M(e);return n(e,{issuer:k||"",authorization_endpoint:`${r}${l(p.MCP_AUTHORIZATION)}`,token_endpoint:`${r}${l(p.MCP_TOKEN_PORTAL)}`,jwks_uri:`${k||""}/.well-known/jwks.json`,registration_endpoint:`${r}${l(p.MCP_DYNAMIC_CLIENT_REGISTRATION)}`,scopes_supported:["openid","profile","email","offline_access"],response_types_supported:["code"],grant_types_supported:["authorization_code","refresh_token","client_credentials"],subject_types_supported:["public"],id_token_signing_alg_values_supported:["RS256"],code_challenge_methods_supported:["S256"]})}}function N(){return async e=>{if(e.req.method!=="POST")return n(e,{error:"Method not allowed"},405);try{return n(e,{client_id:C.OAUTH_CLIENT_ID||"",client_name:"MCP Client",redirect_uris:[],grant_types:["authorization_code","refresh_token"],response_types:["code"],scope:"openid offline email",subject_type:"public",token_endpoint_auth_method:"none",created_at:new Date().toISOString(),updated_at:new Date().toISOString()},201)}catch(r){return n(e,{error:"invalid_request",error_description:r?.message||"Unable to register client"},500)}}}function j(){return async e=>{const r=new URL(e.req.url),{searchParams:o}=r,a=o.get("redirect_uri"),t=S();_.sendMcpAuthorizationStartedMessage([{...u(t),redirect_uri:a||null}]);const i=M(e),c={isMcpFlow:!0,originalRedirectUri:a,mcpClientId:o.get("client_id"),mcpState:o.get("state"),mcpSessionId:t,timestamp:Date.now()};try{const s=await I(c),d=new URL(l(p.IDP_LOGIN),i);return d.searchParams.set("redirectTo",`${p.MCP_CALLBACK}/${s}`),d.searchParams.set("idpId","oidc"),e.redirect(d.toString())}catch(s){const d=s instanceof Error?s.message:String(s),h=s instanceof Error?s.stack:String(s);_.sendMcpAuthorizationFailedMessage([{...u(t),error:d,error_details:h}]);const g=new URL(l(`${k}/oauth2/auth`));return g.search=o.toString(),e.redirect(g.toString())}}}function F(){return async e=>{if(e.req.method!=="POST")return n(e,{error:"Method not allowed"},405);try{const r=await e.req.formData(),o=r.get("grant_type"),a=r.get("code"),t=r.get("redirect_uri")||void 0;if(o!=="authorization_code"||!a)return n(e,{error:"invalid_request",error_description:"Invalid grant type or missing authorization code"},400);try{const i=await A(a);if(t&&t!==i.redirect_uri)return n(e,{error:"invalid_grant",error_description:"redirect_uri mismatch"},400);if(C.OAUTH_CLIENT_ID&&i.client_id&&i.client_id!==C.OAUTH_CLIENT_ID)return n(e,{error:"invalid_client",error_description:"Client mismatch"},400);const c=i.id_token;if(typeof c!="string"||c.length===0)return n(e,{error:"invalid_grant",error_description:"Missing id_token in authorization code"},400);let s=c;if(i.idp_access_token){const{payload:h,header:{kid:g}}=m.decode(c);s=await m.sign({...h,idp_access_token:i.idp_access_token},y,T.HS256,g)}return n(e,{access_token:s,token_type:"Bearer",expires_in:3600,scope:"openid profile email",id_token:c},200,{"Cache-Control":"no-store",Pragma:"no-cache"})}catch{return n(e,{error:"invalid_grant",error_description:"Invalid authorization code"},400)}}catch(r){const o=r instanceof Error?r.message:String(r);return n(e,{error:"server_error",error_description:"Failed to process token request",error_details:o},500)}}}function B(){return async e=>{const r=new URL(e.req.url);let o=r.searchParams.get("context");if(!o&&r.pathname.startsWith(l(`${p.MCP_CALLBACK}/`))){const t=r.pathname.split("/");o=t[t.length-1]}if(!o)return _.sendMcpAuthorizationFailedMessage([{...u(null),error:"Missing context parameter",error_details:null}]),e.text("Missing context parameter",400);let a=null;try{const t=await P(o);if(a=t.mcpSessionId||null,!t.isMcpFlow||!t.originalRedirectUri)throw new Error("Invalid MCP context");const i=f(e,"idp_id_token")||f(e,"authorization"),c=f(e,"idp_access_token"),s=await w({idToken:i||"",idpAccessToken:c||void 0,clientId:t.mcpClientId||"",redirectUri:t.originalRedirectUri,ttlSec:600}),d=new URL(t.originalRedirectUri);return d.searchParams.set("code",s),t.mcpState&&d.searchParams.set("state",t.mcpState),_.sendMcpAuthorizationCompletedMessage([{...u(a),redirect_uri:t.originalRedirectUri||null}]),e.redirect(d.toString())}catch(t){const i=t instanceof Error?t.message:String(t),c=t instanceof Error?t.stack:String(t);return _.sendMcpAuthorizationFailedMessage([{...u(a),error:i,error_details:c}]),e.text(`Invalid MCP callback: ${i}`,400)}}}export{I as createMcpContextToken,j as mcpAuthorizationHandler,B as mcpCallbackHandler,N as mcpDynamicClientRegistrationHandler,b as mcpOAuthAuthorizationServerHandler,q as mcpOAuthProtectedResourceHandler,F as mcpTokenPortalHandler,P as verifyAndParseMcpContextToken};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@redocly/redoc",
|
|
3
|
-
"version": "0.132.0
|
|
3
|
+
"version": "0.132.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"@tanstack/react-virtual": "3.13.0",
|
|
37
37
|
"@redocly/mcp-typescript-sdk": "1.18.1",
|
|
38
38
|
"@wojtekmaj/react-datetimerange-picker": "6.0.0",
|
|
39
|
-
"@xmldom/xmldom": "0.
|
|
39
|
+
"@xmldom/xmldom": "0.9.9",
|
|
40
40
|
"ajv-formats": "^3.0.1",
|
|
41
41
|
"anser": "^2.3.2",
|
|
42
42
|
"babel-plugin-styled-components": "2.1.4",
|
|
@@ -62,7 +62,6 @@
|
|
|
62
62
|
"minimatch": "10.2.4",
|
|
63
63
|
"mri": "1.2.0",
|
|
64
64
|
"nanoid": "5.0.9",
|
|
65
|
-
"node-fetch": "3.3.1",
|
|
66
65
|
"nprogress": "0.2.0",
|
|
67
66
|
"openapi-sampler": "^1.7.2",
|
|
68
67
|
"os-browserify": "0.3.0",
|
|
@@ -91,14 +90,14 @@
|
|
|
91
90
|
"xpath": "0.0.34",
|
|
92
91
|
"yaml-ast-parser": "0.0.43",
|
|
93
92
|
"zod": "^3.25.76",
|
|
94
|
-
"@redocly/
|
|
95
|
-
"@redocly/
|
|
96
|
-
"@redocly/
|
|
97
|
-
"@redocly/
|
|
98
|
-
"@redocly/portal-
|
|
99
|
-
"@redocly/
|
|
100
|
-
"@redocly/
|
|
101
|
-
"@redocly/
|
|
93
|
+
"@redocly/config": "0.48.0",
|
|
94
|
+
"@redocly/graphql-docs": "1.9.0",
|
|
95
|
+
"@redocly/openapi-docs": "3.20.0",
|
|
96
|
+
"@redocly/portal-legacy-ui": "0.15.0",
|
|
97
|
+
"@redocly/portal-plugin-mock-server": "0.17.0",
|
|
98
|
+
"@redocly/realm-asyncapi-sdk": "0.10.0",
|
|
99
|
+
"@redocly/theme": "0.64.0",
|
|
100
|
+
"@redocly/asyncapi-docs": "1.9.0"
|
|
102
101
|
},
|
|
103
102
|
"peerDependencies": {
|
|
104
103
|
"react": "^19.2.4",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import e,{Headers as s,Request as l,Response as o}from"node-fetch";globalThis.fetch||(globalThis.fetch=e,globalThis.Headers=s,globalThis.Request=l,globalThis.Response=o);
|