@redocly/realm 0.136.0-next.3 → 0.136.0-next.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/dist/client/ErrorBoundary.js +1 -1
  3. package/dist/client/app/l10n/hooks/useTranslate.js +1 -1
  4. package/dist/client/app/l10n/initL10n.js +1 -1
  5. package/dist/client/app/usePreloadHistory.d.ts +2 -2
  6. package/dist/client/app/usePreloadHistory.js +1 -1
  7. package/dist/client/app/utils/loadAndNavigate.js +1 -1
  8. package/dist/client/browser-entry.js +2 -2
  9. package/dist/client/templates/openapi-docs/helpers.d.ts +1 -1
  10. package/dist/client/templates/openapi-docs/helpers.js +2 -2
  11. package/dist/constants/common.d.ts +3 -0
  12. package/dist/constants/common.js +1 -1
  13. package/dist/server/config/env-config.d.ts +2 -4
  14. package/dist/server/config/env-schema.d.ts +5 -10
  15. package/dist/server/config/env-schemas/feature-flags.d.ts +4 -8
  16. package/dist/server/config/env-schemas/feature-flags.js +1 -1
  17. package/dist/server/constants/common.d.ts +2 -0
  18. package/dist/server/constants/common.js +1 -1
  19. package/dist/server/constants/entitlements.js +1 -1
  20. package/dist/server/plugins/config-parser/loaders/utils/read-and-validate-config.js +1 -1
  21. package/dist/server/plugins/markdown/search/create-render-tag-fn.d.ts +2 -1
  22. package/dist/server/plugins/markdown/search/create-render-tag-fn.js +1 -1
  23. package/dist/server/plugins/markdown/search/get-ai-search-documents.js +9 -9
  24. package/dist/server/plugins/mcp/codemode/tools/execute.js +1 -1
  25. package/dist/server/plugins/mcp/gateway-mcp/elicitation.d.ts +25 -0
  26. package/dist/server/plugins/mcp/gateway-mcp/elicitation.js +2 -0
  27. package/dist/server/plugins/mcp/gateway-mcp/eligibility.d.ts +4 -15
  28. package/dist/server/plugins/mcp/gateway-mcp/eligibility.js +1 -1
  29. package/dist/server/plugins/mcp/gateway-mcp/fetch/allowed-hosts.d.ts +8 -8
  30. package/dist/server/plugins/mcp/gateway-mcp/fetch/allowed-hosts.js +1 -1
  31. package/dist/server/plugins/mcp/gateway-mcp/fetch/fetch-bridge.d.ts +15 -1
  32. package/dist/server/plugins/mcp/gateway-mcp/fetch/fetch-bridge.js +1 -1
  33. package/dist/server/plugins/mcp/gateway-mcp/fetch/ssrf-blocklist.d.ts +10 -0
  34. package/dist/server/plugins/mcp/gateway-mcp/fetch/ssrf-blocklist.js +1 -0
  35. package/dist/server/plugins/mcp/gateway-mcp/fetch/ssrf-guard.d.ts +1 -1
  36. package/dist/server/plugins/mcp/gateway-mcp/fetch/ssrf-guard.js +1 -1
  37. package/dist/server/plugins/mcp/gateway-mcp/fetch/ssrf-safe-lookup.d.ts +11 -0
  38. package/dist/server/plugins/mcp/gateway-mcp/fetch/ssrf-safe-lookup.js +1 -0
  39. package/dist/server/plugins/mcp/gateway-mcp/fetch-capability.d.ts +8 -1
  40. package/dist/server/plugins/mcp/gateway-mcp/fetch-capability.js +1 -1
  41. package/dist/server/plugins/mcp/gateway-mcp/secret-store.d.ts +24 -0
  42. package/dist/server/plugins/mcp/gateway-mcp/secret-store.js +1 -0
  43. package/dist/server/plugins/mcp/gateway-mcp/upstream-auth-scheme.d.ts +18 -0
  44. package/dist/server/plugins/mcp/gateway-mcp/upstream-auth-scheme.js +1 -0
  45. package/dist/server/plugins/mcp/gateway-mcp/upstream-auth.d.ts +10 -0
  46. package/dist/server/plugins/mcp/gateway-mcp/upstream-auth.js +1 -0
  47. package/dist/server/plugins/mcp/handlers/docs-mcp-handler.js +1 -1
  48. package/dist/server/plugins/mcp/handlers/errors.d.ts +3 -3
  49. package/dist/server/plugins/mcp/handlers/errors.js +1 -1
  50. package/dist/server/plugins/mcp/handlers/handle-mcp-request.js +1 -1
  51. package/dist/server/plugins/mcp/handlers/mcp-credentials-handler.d.ts +5 -0
  52. package/dist/server/plugins/mcp/handlers/mcp-credentials-handler.js +101 -0
  53. package/dist/server/plugins/mcp/index.d.ts +1 -0
  54. package/dist/server/plugins/mcp/index.js +1 -1
  55. package/dist/server/plugins/mcp/servers/docs-server.d.ts +3 -2
  56. package/dist/server/plugins/mcp/servers/docs-server.js +1 -1
  57. package/dist/server/plugins/mcp/servers/mcp-server.d.ts +11 -2
  58. package/dist/server/plugins/mcp/servers/mcp-server.js +1 -1
  59. package/dist/server/plugins/mcp/servers/session-manager.d.ts +15 -0
  60. package/dist/server/plugins/mcp/servers/session-manager.js +1 -0
  61. package/dist/server/plugins/mcp/types.d.ts +6 -12
  62. package/dist/server/plugins/mcp/utils/jwt.d.ts +0 -9
  63. package/dist/server/plugins/mcp/utils/jwt.js +1 -1
  64. package/dist/server/plugins/mcp/utils/mode.d.ts +12 -2
  65. package/dist/server/plugins/mcp/utils/mode.js +1 -1
  66. package/dist/server/plugins/mcp/workers/execute-mcp-tool.js +1 -1
  67. package/dist/server/plugins/openapi-docs/search/get-ai-search-documents.js +16 -16
  68. package/dist/server/plugins/sso/index.js +1 -1
  69. package/dist/server/sandbox/types.d.ts +3 -2
  70. package/dist/server/sandbox/utils/execution-budget.d.ts +4 -3
  71. package/dist/server/sandbox/utils/execution-budget.js +1 -1
  72. package/dist/server/ssr/render.js +1 -1
  73. package/dist/server/types/plugins/markdown.d.ts +2 -2
  74. package/dist/server/utils/crypto/constants.d.ts +5 -0
  75. package/dist/server/utils/crypto/constants.js +1 -0
  76. package/dist/server/utils/crypto/decrypt-aes-gcm.d.ts +6 -0
  77. package/dist/server/utils/crypto/decrypt-aes-gcm.js +1 -0
  78. package/dist/server/utils/crypto/decrypt-claim-value.d.ts +6 -0
  79. package/dist/server/utils/crypto/decrypt-claim-value.js +1 -0
  80. package/dist/server/utils/crypto/derive-key.d.ts +5 -0
  81. package/dist/server/utils/crypto/derive-key.js +1 -0
  82. package/dist/server/utils/crypto/encrypt-aes-gcm.d.ts +6 -0
  83. package/dist/server/utils/crypto/encrypt-aes-gcm.js +1 -0
  84. package/dist/server/utils/crypto/encrypt-claim-value.d.ts +6 -0
  85. package/dist/server/utils/crypto/encrypt-claim-value.js +1 -0
  86. package/dist/server/utils/l10n/get-build-translate-context.d.ts +7 -0
  87. package/dist/server/utils/l10n/get-build-translate-context.js +1 -0
  88. package/dist/server/utils/rbac.js +1 -1
  89. package/dist/server/web-server/auth.d.ts +33 -3
  90. package/dist/server/web-server/auth.js +3 -3
  91. package/dist/server/web-server/handle-api-route-request.js +1 -1
  92. package/dist/server/web-server/routes/api-routes/api-routes.js +1 -1
  93. package/dist/server/web-server/routes/auth.js +1 -1
  94. package/dist/server/web-server/routes/mcp-routes/mcp-oauth.d.ts +5 -2
  95. package/dist/server/web-server/routes/mcp-routes/mcp-oauth.js +1 -1
  96. package/dist/server/web-server/routes/mcp-routes/mcp-routes.js +1 -1
  97. package/dist/types/entitlements.d.ts +3 -1
  98. package/dist/utils/l10n/build-i18n-config.d.ts +24 -0
  99. package/dist/utils/l10n/build-i18n-config.js +1 -0
  100. package/dist/utils/l10n/create-translate.d.ts +19 -0
  101. package/dist/utils/l10n/create-translate.js +1 -0
  102. package/package.json +11 -10
@@ -1,5 +1,5 @@
1
- import{REDOCLY_TEAMS_RBAC as w}from"@redocly/config";import{basename as _,join as q}from"node:path";import C from"@markdoc/markdoc";import{joinSectionContent as J}from"../../../plugins/markdown/search/join-section-content.js";import{toMarkdown as G}from"../../../plugins/markdown/search/to-markdown.js";import{AstToSearchNodeTransformer as z}from"../../../plugins/markdown/search/walk-sections.js";import{createRenderTagFn as B}from"../../../plugins/markdown/search/create-render-tag-fn.js";import{canDownloadApiDefinition as v,isResourcePubliclyAccessible as V}from"../../../utils/rbac.js";import{PUBLIC_API_DEFINITIONS_FOLDER as Y}from"../../../constants/common.js";import{DEFAULT_ANONYMOUS_VISITOR_TEAM as H}from"../../../../constants/common.js";import{getLlmsTxtMdPathBySlug as I}from"../../../utils/llmstxt/get-llms-txt-md-path-by-slug.js";import{AiSearchIndexer as K}from"../ai-search-indexer.js";import{getLocaleFromRelativePath as Q}from"../../../fs/utils/get-locale-from-relative-path.js";import{extractDocumentSearchFacets as W}from"./search-facets.js";import{formatDocumentMetadata as X}from"../../search/utils.js";import{llmsTxtLink as M}from"../../search/llmstxt/index.js";import{replaceFileExtension as Z}from"../store-definition-bundles.js";const k=new Map,xe=({parser:s,options:c,info:n,tagOperations:r,relativePath:t,openapiContentItem:e,metadata:i,getSearchFacets:u,includeInLLMsTxt:a,excludeFromSearch:f})=>async(o,p,l,j)=>{if(f)return;const P=await o.getNavText?.()||_(o.fsPath),D=new K(s,c,o.baseSlug||o.slug),d=D.addItem(e);if(!d)return;const O=await l.getConfig(),b=Array.isArray(d.title)?d.title.join(" "):d.title;let g,m,y=k.get(t);if((e.type==="tag"||e.type==="section"&&e.infoDefinition)&&!y){const{all:A,publiclyAccessible:$}=ae(r.tagged,D,O),{all:S,publiclyAccessible:T}=ue(r.untagged,D,O);k.set(t,{taggedSearchDocuments:new Map(A),untaggedSearchDocuments:S,publiclyAccessibleTaggedSearchDocuments:new Map($),publiclyAccessibleUntaggedSearchDocuments:T})}y=k.get(t);const h="#";switch(e.type){case"operation":const A=D.getOperation(e);g=m=se({title:b,security:s.definition.security,document:d,version:d.version||n.version,headingLevel:h,operation:A});break;case"section":if(e.infoDefinition){y=k.get(t),m=await N({parser:s,info:n,staticData:p,relativePath:t,headingLevel:h,pageName:P,config:O}),m+=`
2
- `;for(const[S,T]of y?.publiclyAccessibleTaggedSearchDocuments?.entries()||[]){if(!T.length)continue;const U=s.definition.tags?.find(L=>L.name===S);m+=x({title:U?.["x-displayName"]||S,description:U?.description,operationSearchDocuments:T,headingLevel:`${h}#`})}const $=y?.publiclyAccessibleUntaggedSearchDocuments||[];$.length&&(m+=x({title:"Other",description:void 0,operationSearchDocuments:$,headingLevel:`${h}#`})),g=await N({parser:s,info:n,staticData:p,relativePath:t,headingLevel:h,pageName:P,config:O})}else if(e.ast){const $=new C.Ast.Node("document",{},e.ast),S=Array.from(new z({ast:$,partials:{},renderTag:B(j.markdocOptions.tags),getInnerContent:G,skipConditionals:!0}).transform());m=g=J(S)}break;case"tag":m=x({title:b,description:e.description,operationSearchDocuments:y?.publiclyAccessibleTaggedSearchDocuments.get(e.name)||[],headingLevel:h}),g=x({title:b,description:e.description,operationSearchDocuments:[],headingLevel:h});break;case"rsrc":case"prompt":case"tool":m=ce({title:b,description:e.description,name:e.name,xMcpConfig:s.definition["x-mcp"],headingLevel:h}),g=m;break}return{async getLLMsTxts(){return[{title:e.name,description:e.type==="tag"?e.description:void 0,content:m||"",slug:o.slug,fsPath:o.fsPath,includeInLLMsTxt:a}]},async getSearchDocuments(){if(e.type==="operation"||e.type==="section"&&(e.infoDefinition||e.ast)||e.type==="tag"){const A=Q(o.fsPath),$=W({...d,...i},n,u);return[{title:b,description:Array.isArray(d.text)?d.text.join(" "):d.text,content:g||"",url:d.url??o.slug,fsPath:o.fsPath,locale:A,product:o.product?.name,rbacTeams:d.rbacTeams,facets:$}]}return[]}}};async function N({parser:s,info:c,staticData:n,relativePath:r,pageName:t,headingLevel:e,config:i}){const u=X(c["x-metadata"]);let a=c.title?`${e} ${c.title}
1
+ import{REDOCLY_TEAMS_RBAC as x}from"@redocly/config";import{basename as C,join as _}from"node:path";import q from"@markdoc/markdoc";import{joinSectionContent as G}from"../../../plugins/markdown/search/join-section-content.js";import{toMarkdown as J}from"../../../plugins/markdown/search/to-markdown.js";import{AstToSearchNodeTransformer as B}from"../../../plugins/markdown/search/walk-sections.js";import{createRenderTagFn as z}from"../../../plugins/markdown/search/create-render-tag-fn.js";import{getBuildTranslateContext as v}from"../../../utils/l10n/get-build-translate-context.js";import{canDownloadApiDefinition as V,isResourcePubliclyAccessible as Y}from"../../../utils/rbac.js";import{PUBLIC_API_DEFINITIONS_FOLDER as H}from"../../../constants/common.js";import{DEFAULT_ANONYMOUS_VISITOR_TEAM as I}from"../../../../constants/common.js";import{getLlmsTxtMdPathBySlug as K}from"../../../utils/llmstxt/get-llms-txt-md-path-by-slug.js";import{AiSearchIndexer as Q}from"../ai-search-indexer.js";import{getLocaleFromRelativePath as W}from"../../../fs/utils/get-locale-from-relative-path.js";import{extractDocumentSearchFacets as X}from"./search-facets.js";import{formatDocumentMetadata as Z}from"../../search/utils.js";import{llmsTxtLink as M}from"../../search/llmstxt/index.js";import{replaceFileExtension as ee}from"../store-definition-bundles.js";const j=new Map,Ee=({parser:s,options:c,info:n,tagOperations:r,relativePath:t,openapiContentItem:e,metadata:i,getSearchFacets:u,includeInLLMsTxt:a,excludeFromSearch:f})=>async(o,p,l,O)=>{if(f)return;const U=await o.getNavText?.()||C(o.fsPath),T=new Q(s,c,o.baseSlug||o.slug),m=T.addItem(e);if(!m)return;const w=await l.getConfig(),D=Array.isArray(m.title)?m.title.join(" "):m.title;let $,d,y=j.get(t);if((e.type==="tag"||e.type==="section"&&e.infoDefinition)&&!y){const{all:A,publiclyAccessible:g}=ue(r.tagged,T,w),{all:S,publiclyAccessible:b}=le(r.untagged,T,w);j.set(t,{taggedSearchDocuments:new Map(A),untaggedSearchDocuments:S,publiclyAccessibleTaggedSearchDocuments:new Map(g),publiclyAccessibleUntaggedSearchDocuments:b})}y=j.get(t);const h="#";switch(e.type){case"operation":const A=T.getOperation(e);$=d=ce({title:D,security:s.definition.security,document:m,version:m.version||n.version,headingLevel:h,operation:A});break;case"section":if(e.infoDefinition){y=j.get(t),d=await N({parser:s,info:n,staticData:p,relativePath:t,headingLevel:h,pageName:U,config:w}),d+=`
2
+ `;for(const[S,b]of y?.publiclyAccessibleTaggedSearchDocuments?.entries()||[]){if(!b.length)continue;const k=s.definition.tags?.find(L=>L.name===S);d+=E({title:k?.["x-displayName"]||S,description:k?.description,operationSearchDocuments:b,headingLevel:`${h}#`})}const g=y?.publiclyAccessibleUntaggedSearchDocuments||[];g.length&&(d+=E({title:"Other",description:void 0,operationSearchDocuments:g,headingLevel:`${h}#`})),$=await N({parser:s,info:n,staticData:p,relativePath:t,headingLevel:h,pageName:U,config:w})}else if(e.ast){const g=new q.Ast.Node("document",{},e.ast),{locale:S,translate:b}=await v(o.slug,O.getGlobalData?.().l10n),k=Array.from(new B({ast:g,partials:{},renderTag:z(O.markdocOptions.tags,S,b),getInnerContent:J,skipConditionals:!0}).transform());d=$=G(k)}break;case"tag":d=E({title:D,description:e.description,operationSearchDocuments:y?.publiclyAccessibleTaggedSearchDocuments.get(e.name)||[],headingLevel:h}),$=E({title:D,description:e.description,operationSearchDocuments:[],headingLevel:h});break;case"rsrc":case"prompt":case"tool":d=re({title:D,description:e.description,name:e.name,xMcpConfig:s.definition["x-mcp"],headingLevel:h}),$=d;break}return{async getLLMsTxts(){return[{title:e.name,description:e.type==="tag"?e.description:void 0,content:d||"",slug:o.slug,fsPath:o.fsPath,includeInLLMsTxt:a}]},async getSearchDocuments(){if(e.type==="operation"||e.type==="section"&&(e.infoDefinition||e.ast)||e.type==="tag"){const A=W(o.fsPath),g=X({...m,...i},n,u);return[{title:D,description:Array.isArray(m.text)?m.text.join(" "):m.text,content:$||"",url:m.url??o.slug,fsPath:o.fsPath,locale:A,product:o.product?.name,rbacTeams:m.rbacTeams,facets:g}]}return[]}}};async function N({parser:s,info:c,staticData:n,relativePath:r,pageName:t,headingLevel:e,config:i}){const u=Z(c["x-metadata"]);let a=c.title?`${e} ${c.title}
3
3
 
4
4
  `:`${e} ${t}
5
5
 
@@ -12,14 +12,14 @@ import{REDOCLY_TEAMS_RBAC as w}from"@redocly/config";import{basename as _,join a
12
12
  `:"",e=`${e}#`,a+=u.length?`Metadata:
13
13
  ${u}
14
14
  `:"",a+=`
15
- `,a+=ee({parser:s,headingLevel:e}),a+=te({parser:s,headingLevel:e}),a+=await ne({info:c,staticData:n,relativePath:r,pageName:t,headingLevel:e,config:i}),a}function x({title:s="",description:c,operationSearchDocuments:n,headingLevel:r}){let t=`${r} ${s}
15
+ `,a+=ne({parser:s,headingLevel:e}),a+=se({parser:s,headingLevel:e}),a+=await te({info:c,staticData:n,relativePath:r,pageName:t,headingLevel:e,config:i}),a}function E({title:s="",description:c,operationSearchDocuments:n,headingLevel:r}){let t=`${r} ${s}
16
16
 
17
17
  `;return c&&(t+=`${c}
18
18
 
19
19
  `),n.length&&n.forEach(e=>{const i=Array.isArray(e.title)?e.title.join(" "):e.title;t+=`${r}# ${i}${e.deprecated?" (deprecated)":""}
20
20
 
21
- `,t+=` - ${M({title:`${e.httpMethod?.toUpperCase()} ${e.httpPath}`,description:Array.isArray(e.text)?e.text.join(" "):e.text,slug:I(e.url)})}`,t+=`
22
- `}),t}function ee({parser:s,headingLevel:c}){const{servers:n}=s.definition;if(n&&n.length){let r=`${c} Servers
21
+ `,t+=` - ${M({title:`${e.httpMethod?.toUpperCase()} ${e.httpPath}`,description:Array.isArray(e.text)?e.text.join(" "):e.text,slug:K(e.url)})}`,t+=`
22
+ `}),t}function ne({parser:s,headingLevel:c}){const{servers:n}=s.definition;if(n&&n.length){let r=`${c} Servers
23
23
 
24
24
  `;return n.forEach(t=>{r+=t.description?`${t.description}
25
25
  `:"",r+=`\`\`\`
@@ -31,9 +31,9 @@ ${t.url}
31
31
  `,r+=i.default?`Default: ${JSON.stringify(i.default)}
32
32
  `:"",r+=i.enum?`Enum: ${i.enum.map(u=>JSON.stringify(u)).join(", ")}
33
33
  `:""}),r+=`
34
- `)}),r}return""}async function ne({info:s,staticData:c,relativePath:n,pageName:r,headingLevel:t,config:e}){const i=q(c.props?.outdir||"",Y,Z(n,".yaml")),u=e.access?.rbac,a=e.access?.requiresLogin;if(v(i,u??{},a??!1,{isAuthenticated:!1,teams:[H]})){let f=`${t} Download OpenAPI description
34
+ `)}),r}return""}async function te({info:s,staticData:c,relativePath:n,pageName:r,headingLevel:t,config:e}){const i=_(c.props?.outdir||"",H,ee(n,".yaml")),u=e.access?.rbac,a=e.access?.requiresLogin;if(V(i,u??{},a??!1,{isAuthenticated:!1,teams:[I]})){let f=`${t} Download OpenAPI description
35
35
 
36
- `;return f+=M({title:s.title||r||"OpenAPI definition",description:void 0,slug:i}),f}return""}function te({parser:s,headingLevel:c}){if(!s.definition.components?.securitySchemes)return"";let n=`${c} Security
36
+ `;return f+=M({title:s.title||r||"OpenAPI definition",description:void 0,slug:i}),f}return""}function se({parser:s,headingLevel:c}){if(!s.definition.components?.securitySchemes)return"";let n=`${c} Security
37
37
 
38
38
  `;const{securitySchemes:r}=s.definition.components;return Object.keys(r).forEach(t=>{const e=r[t];e&&(n+=`${c}# ${t}
39
39
 
@@ -52,19 +52,19 @@ ${t.url}
52
52
  `),e.flows?.password?.scopes&&(n+=`Scopes:
53
53
  `,Object.entries(e.flows?.password?.scopes||{}).forEach(([i,u])=>{n+=`- \`${i}\`: ${u}
54
54
  `})),n+=`
55
- `)}),n}function se({title:s,security:c,document:n,version:r,headingLevel:t,operation:e}){const{text:i,httpMethod:u,httpPath:a,deprecated:f}=n,o=oe(n.parameters||[],`${t}#`),p=re(`${t}#`,n.parameters,e);let l=s?`${t} ${s}${f?" (deprecated)":""}
55
+ `)}),n}function ce({title:s,security:c,document:n,version:r,headingLevel:t,operation:e}){const{text:i,httpMethod:u,httpPath:a,deprecated:f}=n,o=ae(n.parameters||[],`${t}#`),p=ie(`${t}#`,n.parameters,e);let l=s?`${t} ${s}${f?" (deprecated)":""}
56
56
 
57
57
  `:"";return l+=i?`${i}
58
58
 
59
59
  `:"",l+=`Endpoint: ${u?.toUpperCase()} ${a}
60
60
  `,l+=r?`Version: ${r}
61
61
  `:"",l+=n.security?.length?`Security: ${n.security.join(", ")}
62
- `:c?.length?`Security: ${c.map(j=>j.id).join(", ")}
62
+ `:c?.length?`Security: ${c.map(O=>O.id).join(", ")}
63
63
  `:"",l+=`
64
64
  `,l+=o?`${o}
65
65
  `:"",l+=`
66
66
  `,l+=`${p.join(`
67
- `)}`,l}function ce({title:s,name:c,xMcpConfig:n,headingLevel:r}){const t=n?.tools.find(i=>i.name===c);if(!t)return"";let e=`${r} ${s}
67
+ `)}`,l}function re({title:s,name:c,xMcpConfig:n,headingLevel:r}){const t=n?.tools.find(i=>i.name===c);if(!t)return"";let e=`${r} ${s}
68
68
 
69
69
  `;return e+=t.description?`${t.description}
70
70
 
@@ -80,15 +80,15 @@ ${JSON.stringify(t.inputSchema,null,2)}
80
80
  ${JSON.stringify(t.outputSchema,null,2)}
81
81
  \`\`\`
82
82
 
83
- `),e}function re(s,c,n){return!c&&!n||!n?.responses?[]:n?.responses.filter(t=>!t.content?.mediaTypes[0]?.schema).map(t=>`${s} ${R(`response ${t.code} fields`)}
84
- `)}function ie(s,c,n,r){const t=JSON.stringify(s),e=r.get(t);return e?`${n}Enum: same as ${e} (${s.length} values)
83
+ `),e}function ie(s,c,n){return!c&&!n||!n?.responses?[]:n?.responses.filter(t=>!t.content?.mediaTypes[0]?.schema).map(t=>`${s} ${R(`response ${t.code} fields`)}
84
+ `)}function oe(s,c,n,r){const t=JSON.stringify(s),e=r.get(t);return e?`${n}Enum: same as ${e} (${s.length} values)
85
85
  `:(r.set(t,c),`${n}Enum: ${s.map(i=>JSON.stringify(i)).join(", ")}
86
- `)}function E(s,c,n,r){const t=`${c} `,e=s.oneOf,u=[...s.path||[],s.name].join("."),a=Array.isArray(s.description)?s.description.join(" "):s.description,f=!!e&&e.variants.length>1;let o=`${c}- \`${u}\` (${s.type}${s.required?", required":""})`;if(f&&(o+=e.discriminator?` \u2014 one of (discriminator: ${e.discriminator}):`:" \u2014 one of:"),o+=`
86
+ `)}function P(s,c,n,r){const t=`${c} `,e=s.oneOf,u=[...s.path||[],s.name].join("."),a=Array.isArray(s.description)?s.description.join(" "):s.description,f=!!e&&e.variants.length>1;let o=`${c}- \`${u}\` (${s.type}${s.required?", required":""})`;if(f&&(o+=e.discriminator?` \u2014 one of (discriminator: ${e.discriminator}):`:" \u2014 one of:"),o+=`
87
87
  `,o+=a?`${t}${a.trim()}
88
- `:"",s.enum){const p=r?`\`${u}\` in "${r}"`:`\`${u}\``;o+=ie(s.enum,p,t,n)}else s.example&&(o+=`${t}Example: ${s.example}
88
+ `:"",s.enum){const p=r?`\`${u}\` in "${r}"`:`\`${u}\``;o+=oe(s.enum,p,t,n)}else s.example&&(o+=`${t}Example: ${s.example}
89
89
  `);if(f)for(const p of e.variants){o+=`${c} - ${p.title}:
90
- `;for(const l of p.parameters)o+=E(l,`${c} `,n,p.title)}else if(e)for(const p of e.variants[0].parameters)o+=E(p,`${c} `,n);return o}function oe(s,c){const n={};for(const e of s){const i=`${e.place}${e.mediaType?` (${e.mediaType})`:""}`;n[i]=[...n[i]||[],e]}const r=new Map;return Object.entries(n).map(([e,i])=>{const u=i.map(a=>E(a," ",r));return`${c} ${R(e)}:
90
+ `;for(const l of p.parameters)o+=P(l,`${c} `,n,p.title)}else if(e)for(const p of e.variants[0].parameters)o+=P(p,`${c} `,n);return o}function ae(s,c){const n={};for(const e of s){const i=`${e.place}${e.mediaType?` (${e.mediaType})`:""}`;n[i]=[...n[i]||[],e]}const r=new Map;return Object.entries(n).map(([e,i])=>{const u=i.map(a=>P(a," ",r));return`${c} ${R(e)}:
91
91
 
92
92
  ${u.join(`
93
93
  `)}`}).join(`
94
- `)}function ae(s,c,n){const r=[],t=[];return s.forEach((e,i)=>{const u=[],a=[];e.forEach(f=>{const o=c.addItem(f);o&&(u.push(o),F({[w]:f[w],slug:o.url},n)&&a.push(o))}),r.push([i,u]),t.push([i,a])}),{all:r,publiclyAccessible:t}}function ue(s,c,n){const r=[],t=[];return s.forEach(e=>{const i=c.addItem(e);i&&(r.push(i),F({[w]:e[w],slug:i.url},n)&&t.push(i))}),{all:r,publiclyAccessible:t}}function R(s){return s.charAt(0).toUpperCase()+s.slice(1)}function F(s,c){return c.access?.requiresLogin?!0:V(s,c)}export{xe as getAiDocumentsStore};
94
+ `)}function ue(s,c,n){const r=[],t=[];return s.forEach((e,i)=>{const u=[],a=[];e.forEach(f=>{const o=c.addItem(f);o&&(u.push(o),F({[x]:f[x],slug:o.url},n)&&a.push(o))}),r.push([i,u]),t.push([i,a])}),{all:r,publiclyAccessible:t}}function le(s,c,n){const r=[],t=[];return s.forEach(e=>{const i=c.addItem(e);i&&(r.push(i),F({[x]:e[x],slug:i.url},n)&&t.push(i))}),{all:r,publiclyAccessible:t}}function R(s){return s.charAt(0).toUpperCase()+s.slice(1)}function F(s,c){return c.access?.requiresLogin?!0:Y(s,c)}export{Ee as getAiDocumentsStore};
@@ -1 +1 @@
1
- import{DEFAULT_SSO_IDP_TITLE as A}from"../../../constants/common.js";import{envConfig as d}from"../../config/env-config.js";import{telemetryTraceStep as I}from"../../../cli/telemetry/helpers/trace-step.js";import{logger as C}from"../../tools/notifiers/logger.js";const O="https://auth.cloud.redocly.com/oidc/.well-known/openid-configuration",_="https://auth.cloud.redocly.com/api/sso/oidc/introspect";async function S(T){return{id:"sso",async processContent(i){await I("build.plugin.sso",async f=>{const o=i.getConfig(),s=o.access;if(f?.setAttribute("config",`{"ssoDirect": ${JSON.stringify(o.ssoDirect||{})}}, {"sso": ${JSON.stringify(s?.sso||{})}}, {"idps": ${JSON.stringify(s?.idps||{})}}`),o.ssoDirect&&typeof o.ssoDirect=="object"&&Object.keys(o.ssoDirect).length!==0)return;const y=!!s?.sso&&(Array.isArray(s.sso)?s.sso.length>0:!0),r=!!s?.idps&&(Array.isArray(s.idps)?s.idps.length>0:!0);if(s?.sso&&Array.isArray(s.sso)&&!s.sso.length&&!r)return;const g=!!(s?.rbac&&typeof s.rbac=="object"&&Object.keys(s.rbac).length!==0),u=s?.requiresLogin;if(!g&&!u)return;y&&r&&C.error("access.sso and access.idps both set \u2014 should have been rejected by config validation",{sso:s.sso,idps:s.idps});let c=O,a=d.REDOCLY_OAUTH_USE_INTROSPECT?_:"";const e=s?.residency;if(e){const l=e.endsWith("/")?e.slice(0,-1):e;c=`${l.replace("app.","auth.")}/oidc/.well-known/openid-configuration`,a=d.REDOCLY_OAUTH_USE_INTROSPECT?`${l}/api/sso/oidc/introspect`:""}let n="AUTO";s?.sso&&(Array.isArray(s.sso)?n=s.sso.join(","):n=s.sso);let t="";s?.idps&&(Array.isArray(s.idps)?t=s.idps.join(","):t=s.idps);const p={login_hint:"{{ process.env.ORGANIZATION_ID }}",login_type:n};t&&(p.login_idps=t);const m={oidc:{title:A,type:"OIDC",configurationUrl:c,clientId:"{{ process.env.OAUTH_CLIENT_ID }}",clientSecret:"{{ process.env.OAUTH_CLIENT_SECRET }}",teamsClaimName:"https://redocly.com/sso/teams",scopes:["openid"],authorizationRequestCustomParams:p,audience:"{{ process.env.ORGANIZATION_ID }}",introspectEndpoint:a}};i.setGlobalConfig({ssoDirect:m})})},async afterRoutesCreated(i){}}}export{S as ssoPlugin};
1
+ import{DEFAULT_SSO_IDP_TITLE as A}from"../../../constants/common.js";import{envConfig as d}from"../../config/env-config.js";import{telemetryTraceStep as I}from"../../../cli/telemetry/helpers/trace-step.js";import{logger as C}from"../../tools/notifiers/logger.js";const O="https://auth.cloud.redocly.com/oidc/.well-known/openid-configuration",_="https://auth.cloud.redocly.com/api/sso/oidc/introspect";async function S(T){return{id:"sso",async processContent(i){await I("build.plugin.sso",async f=>{const o=i.getConfig(),s=o.access;if(f?.setAttribute("config",`{"ssoDirect": ${JSON.stringify(o.ssoDirect||{})}}, {"sso": ${JSON.stringify(s?.sso||{})}}, {"idps": ${JSON.stringify(s?.idps||{})}}`),o.ssoDirect&&typeof o.ssoDirect=="object"&&Object.keys(o.ssoDirect).length!==0)return;const y=!!s?.sso&&(Array.isArray(s.sso)?s.sso.length>0:!0),r=!!s?.idps&&(Array.isArray(s.idps)?s.idps.length>0:!0);if(s?.sso&&Array.isArray(s.sso)&&!s.sso.length&&!r)return;const g=!!(s?.rbac&&typeof s.rbac=="object"&&Object.keys(s.rbac).length!==0),u=s?.requiresLogin;if(!g&&!u)return;y&&r&&C.error("access.sso and access.idps both set \u2014 should have been rejected by config validation",{sso:s.sso,idps:s.idps});let c=O,a=d.REDOCLY_OAUTH_USE_INTROSPECT?_:"";const e=s?.residency;if(e){const l=e.endsWith("/")?e.slice(0,-1):e;c=`${l.replace("app.","auth.")}/oidc/.well-known/openid-configuration`,a=d.REDOCLY_OAUTH_USE_INTROSPECT?`${l}/api/sso/oidc/introspect`:""}let n="AUTO";s?.sso&&(Array.isArray(s.sso)?n=s.sso.join(","):n=s.sso);let t="";s?.idps&&(Array.isArray(s.idps)?t=s.idps.join(","):t=s.idps);const p={login_hint:"{{ process.env.ORGANIZATION_ID }}",login_type:n};t&&(p.login_idps=t);const m={oidc:{title:A,type:"OIDC",configurationUrl:c,clientId:"{{ process.env.OAUTH_CLIENT_ID }}",clientSecret:"{{ process.env.OAUTH_CLIENT_SECRET }}",teamsClaimName:"https://redocly.com/sso/teams",scopes:["openid","offline"],authorizationRequestCustomParams:p,audience:"{{ process.env.ORGANIZATION_ID }}",introspectEndpoint:a}};i.setGlobalConfig({ssoDirect:m})})},async afterRoutesCreated(i){}}}export{S as ssoPlugin};
@@ -6,8 +6,9 @@ export type SandboxResult = {
6
6
  export type ExecutionBudget = {
7
7
  /**
8
8
  * Run `work()` as a host call: its latency is exempt from the compute budget (`timeoutMs`).
9
- * While the call is in flight the idle timer is paused, and the guest gets a fresh CPU
10
- * deadline when it settles — so time spent off in the host isn't charged as guest compute.
9
+ * While the call is in flight the idle timer is paused and the remaining compute budget is
10
+ * frozen, resuming where it stopped when the call settles — so time spent off in the host
11
+ * isn't charged as guest compute and the budget is never refreshed per call.
11
12
  */
12
13
  hostCall<T>(work: () => Promise<T>): Promise<T>;
13
14
  /** Rejects when a wall-clock deadline fires */
@@ -1,9 +1,10 @@
1
1
  import type { ExecutionBudget } from '../types.js';
2
2
  import type { QuickJSContext } from 'quickjs-emscripten-core';
3
3
  /**
4
- * Time-bounds a single sandbox run. Two deadlines — a refreshable per-stretch compute budget
5
- * (`timeoutMs`) and a fixed whole-run ceiling (`maxLifetimeMs`) are each enforced two ways,
6
- * because the guest is only ever in one of two states and each enforcer reaches only one:
4
+ * Time-bounds a single sandbox run. Two deadlines — a drawn-down compute budget (`timeoutMs`,
5
+ * spent only while the guest runs bytecode and frozen across host-call latency) and a fixed
6
+ * whole-run ceiling (`maxLifetimeMs`) are each enforced two ways, because the guest is only
7
+ * ever in one of two states and each enforcer reaches only one:
7
8
  * - while the guest RUNS bytecode → the interrupt handler
8
9
  * - while the guest is PARKED on an `await` → a wall-clock `setTimeout`
9
10
  */
@@ -1 +1 @@
1
- function f(a,t,i){const s=Date.now()+i;let c=Date.now()+t,l=()=>{};const d=new Promise((e,o)=>{l=r=>o(new Error(r))});let n;const u=()=>{clearTimeout(n),n=setTimeout(()=>l(`Execution timed out after ${t}ms`),t)};a.runtime.setInterruptHandler(()=>{const e=Date.now();return e>c||e>s}),u();const T=setTimeout(()=>l(`Exceeded the maximum lifetime of ${i}ms`),i);let m=0;return{hostCall:e=>{m++,clearTimeout(n);const o=()=>{a.alive&&(c=Date.now()+t,--m===0&&u())},r=e();return r.then(o,o),r},aborted:d,dispose(){clearTimeout(n),clearTimeout(T)}}}export{f as createExecutionBudget};
1
+ function f(c,t,i){const d=Date.now()+i;let l=Date.now()+t,u=t,a=()=>{};const T=new Promise((e,o)=>{a=r=>o(new Error(r))});let n;const m=()=>{clearTimeout(n),n=setTimeout(()=>a(`Execution timed out after ${t}ms`),t)};c.runtime.setInterruptHandler(()=>{const e=Date.now();return e>l||e>d}),m();const w=setTimeout(()=>a(`Exceeded the maximum lifetime of ${i}ms`),i);let s=0;return{hostCall:e=>{u=l-Date.now(),s++,clearTimeout(n);const o=()=>{c.alive&&(l=Date.now()+u,--s===0&&m())},r=e();return r.then(o,o),r},aborted:T,dispose(){clearTimeout(n),clearTimeout(w)}}}export{f as createExecutionBudget};
@@ -1 +1 @@
1
- import{pathToFileURL as I}from"url";import{HelmetProvider as z}from"@dr.pogodin/react-helmet";import{renderToString as m}from"react-dom/server";import{StaticRouterProvider as G,createStaticHandler as J,createStaticRouter as K}from"react-router-dom/server.js";import r from"react";import{readFile as Q}from"fs/promises";import{join as V}from"path";import{withPathPrefix as l,getLocaleFromPathname as W,withoutPathPrefix as X,removeTrailingSlash as Y}from"@redocly/theme/core/utils";import{RUNTIME_RESOURCES_DIR as T}from"../constants/common.js";import{slash as Z}from"../../utils/path/slash.js";import{reporter as tt}from"../tools/notifiers/reporter.js";import{envConfig as p}from"../config/env-config.js";import{slug as et}from"../../utils/slugger.js";import{shouldForwardProp as rt}from"../../utils/should-forward-prop.js";import{htmlTemplate as ot}from"./template.js";import{detectColorSchemaScript as st,generatePreloadPageData as nt}from"./utils.js";import"./hijack-console.js";import{getSitemapLinkTag as at}from"./get-sitemap-link-tag.js";let g="";async function it(t){return p.isRuntimeMode?await import("../../client/server-entry.js"):await import(I(`${Z(t)}/server-entry.js`)+"?"+new Date)}async function Mt(t){if(!p.isRuntimeMode){const e=tt.getCompilationProblems();if(e.length>0){const{renderCompilationError:n}=await import("./render-compilation-error.js");return n(e)}}const{Loader:u,App:R,routes:w,ServerStyleSheet:E,StyleSheetManager:C,ErrorDetails:P,initL10n:y}=await it(t.serverOutDir),{page:h,store:{globalData:S,hasSitemap:D},sharedData:v,ssrHref:b}=t,f=S?.l10n,i=W(X(h.slug),f?.defaultLocale,f?.locales),d=t.page.request?.url||"http://localhost/";await u.prepare({...h,slug:Y(new URL(d).pathname)},v,S,i),await y(i);const c=new E,{query:M,dataRoutes:x}=J([{Component:R,path:l("*"),children:w}]),s=await M(new Request(d));if(s instanceof Response)throw s;const B=K(x,s);try{globalThis.SSR_HOSTNAME=b,globalThis.SSR_USER_AGENT=t.userAgent,globalThis.SSR_OMIT_SUSPENSE=t.omitSuspense;const e={},n=m(r.createElement(z,{context:e},r.createElement(C,{sheet:c.instance,shouldForwardProp:rt},r.createElement(G,{router:B,context:s})))),L=D?at():"",a=e.helmet,k=a?.title.toString()||"",_=t.store.globalData?.logo?.favicon,o=t.store.config,j=`<link rel="preload" as="fetch" crossorigin="anonymous" href="${l("/app-data.json")}" />`,F=nt(t.page.slug),H=st(o),U=t.page.product?.name?`product-${et(t.page.product.name)}`:"",A=t.store.ssr.headTags.join(""),$=t.store.ssr.postBodyTags.join(""),N=t.store.ssr.preBodyTags.join(""),O=`<link rel="stylesheet" href="${l(T)}/browser-entry.css" />`;!p.isDevelopMode&&!g&&(g=`<style>${await Q(V(t.outdir,T,"browser-entry.css"),"utf-8")}</style>`);const q={bodyHtml:n,linkTags:o.linkTags+c.getStyleTags()+(a?.link.toString()||""),title:k,favicon:_,headScriptTags:L+H+o.headScriptTags+A+(a?.script.toString()||"")+(a?.meta.toString()||""),preload:[j,F],postBodyScriptTags:o.postBodyScriptTags+$,preBodyScriptTags:o.preBodyScriptTags||""+N,lang:i,productClass:U,runtimeCss:g||O};return{html:ot(q),statusCode:200}}catch(e){return t.telemetry.sendSsrErrorCaughtMessage({message:e.message}),{html:m(r.createElement(P,{error:e})),statusCode:500,error:e}}finally{c.seal(),u.clear()}}function xt(t){return m(r.createElement(r.Fragment,null,...t))}export{Mt as render,xt as renderComponents};
1
+ import{pathToFileURL as I}from"url";import{HelmetProvider as z}from"@dr.pogodin/react-helmet";import{renderToString as m}from"react-dom/server";import{StaticRouterProvider as G,createStaticHandler as J,createStaticRouter as K}from"react-router-dom";import r from"react";import{readFile as Q}from"fs/promises";import{join as V}from"path";import{withPathPrefix as l,getLocaleFromPathname as W,withoutPathPrefix as X,removeTrailingSlash as Y}from"@redocly/theme/core/utils";import{RUNTIME_RESOURCES_DIR as T}from"../constants/common.js";import{slash as Z}from"../../utils/path/slash.js";import{reporter as tt}from"../tools/notifiers/reporter.js";import{envConfig as p}from"../config/env-config.js";import{slug as et}from"../../utils/slugger.js";import{shouldForwardProp as rt}from"../../utils/should-forward-prop.js";import{htmlTemplate as ot}from"./template.js";import{detectColorSchemaScript as st,generatePreloadPageData as nt}from"./utils.js";import"./hijack-console.js";import{getSitemapLinkTag as at}from"./get-sitemap-link-tag.js";let g="";async function it(t){return p.isRuntimeMode?await import("../../client/server-entry.js"):await import(I(`${Z(t)}/server-entry.js`)+"?"+new Date)}async function Mt(t){if(!p.isRuntimeMode){const e=tt.getCompilationProblems();if(e.length>0){const{renderCompilationError:n}=await import("./render-compilation-error.js");return n(e)}}const{Loader:u,App:R,routes:w,ServerStyleSheet:E,StyleSheetManager:C,ErrorDetails:P,initL10n:y}=await it(t.serverOutDir),{page:h,store:{globalData:S,hasSitemap:D},sharedData:v,ssrHref:b}=t,f=S?.l10n,i=W(X(h.slug),f?.defaultLocale,f?.locales),d=t.page.request?.url||"http://localhost/";await u.prepare({...h,slug:Y(new URL(d).pathname)},v,S,i),await y(i);const c=new E,{query:M,dataRoutes:x}=J([{Component:R,path:l("*"),children:w}]),s=await M(new Request(d));if(s instanceof Response)throw s;const B=K(x,s);try{globalThis.SSR_HOSTNAME=b,globalThis.SSR_USER_AGENT=t.userAgent,globalThis.SSR_OMIT_SUSPENSE=t.omitSuspense;const e={},n=m(r.createElement(z,{context:e},r.createElement(C,{sheet:c.instance,shouldForwardProp:rt},r.createElement(G,{router:B,context:s})))),L=D?at():"",a=e.helmet,k=a?.title.toString()||"",_=t.store.globalData?.logo?.favicon,o=t.store.config,j=`<link rel="preload" as="fetch" crossorigin="anonymous" href="${l("/app-data.json")}" />`,F=nt(t.page.slug),H=st(o),U=t.page.product?.name?`product-${et(t.page.product.name)}`:"",A=t.store.ssr.headTags.join(""),$=t.store.ssr.postBodyTags.join(""),N=t.store.ssr.preBodyTags.join(""),O=`<link rel="stylesheet" href="${l(T)}/browser-entry.css" />`;!p.isDevelopMode&&!g&&(g=`<style>${await Q(V(t.outdir,T,"browser-entry.css"),"utf-8")}</style>`);const q={bodyHtml:n,linkTags:o.linkTags+c.getStyleTags()+(a?.link.toString()||""),title:k,favicon:_,headScriptTags:L+H+o.headScriptTags+A+(a?.script.toString()||"")+(a?.meta.toString()||""),preload:[j,F],postBodyScriptTags:o.postBodyScriptTags+$,preBodyScriptTags:o.preBodyScriptTags||""+N,lang:i,productClass:U,runtimeCss:g||O};return{html:ot(q),statusCode:200}}catch(e){return t.telemetry.sendSsrErrorCaughtMessage({message:e.message}),{html:m(r.createElement(P,{error:e})),statusCode:500,error:e}}finally{c.seal(),u.clear()}}function xt(t){return m(r.createElement(r.Fragment,null,...t))}export{Mt as render,xt as renderComponents};
@@ -2,7 +2,7 @@ import type { Node } from '@markdoc/markdoc';
2
2
  import type { PageStaticData, REDOCLY_ROUTE_RBAC, REDOCLY_TEAMS_RBAC, RbacScopeItems } from '@redocly/config';
3
3
  import type { PluginDefaultOptions, PageRouteDetails, LifecycleContext, AfterRoutesCreatedActions, MarkdownParseInput } from '../../types';
4
4
  import type { LINK_ORIGINAL_ATTR_NAME } from '../../constants/common';
5
- import type { RenderForLlmsContext } from '@redocly/theme/markdoc/tags/types';
5
+ import type { RenderForLlmsRenderContext } from '@redocly/theme/markdoc/tags/types';
6
6
  export type RoutesInfoActions = {
7
7
  outdir: string;
8
8
  getRouteByFsPath: (relativePath: string) => PageRouteDetails | undefined;
@@ -42,5 +42,5 @@ export type ParseMarkdocOpts = {
42
42
  deps?: MarkdocDeps;
43
43
  resource?: string;
44
44
  };
45
- export type RenderTagFn = (node: Node, context: RenderForLlmsContext) => string | undefined;
45
+ export type RenderTagFn = (node: Node, context: RenderForLlmsRenderContext) => string | undefined;
46
46
  //# sourceMappingURL=markdown.d.ts.map
@@ -0,0 +1,5 @@
1
+ export declare const IV_LENGTH_BYTES = 12;
2
+ export declare const AUTH_TAG_LENGTH_BYTES = 16;
3
+ /** Marks a JWT claim value as encrypted; unprefixed values are legacy plaintext. */
4
+ export declare const ENCRYPTED_CLAIM_PREFIX = "enc.v1.";
5
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ const E=12,T=16,_="enc.v1.";export{T as AUTH_TAG_LENGTH_BYTES,_ as ENCRYPTED_CLAIM_PREFIX,E as IV_LENGTH_BYTES};
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Decrypts a payload produced by `encryptAesGcm`.
3
+ * Throws when the payload is tampered with or the secret is wrong.
4
+ */
5
+ export declare function decryptAesGcm(payload: string, secret: string): string;
6
+ //# sourceMappingURL=decrypt-aes-gcm.d.ts.map
@@ -0,0 +1 @@
1
+ import{createDecipheriv as u}from"node:crypto";import{AUTH_TAG_LENGTH_BYTES as e,IV_LENGTH_BYTES as a}from"./constants.js";import{deriveKey as f}from"./derive-key.js";function h(o,c){const r=Buffer.from(o,"base64url"),n=r.subarray(0,a),i=r.subarray(r.length-e),s=r.subarray(a,r.length-e),t=u("aes-256-gcm",f(c),n);return t.setAuthTag(i),Buffer.concat([t.update(s),t.final()]).toString("utf8")}export{h as decryptAesGcm};
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Returns the decrypted claim value, the value itself when it is legacy
3
+ * plaintext, or undefined when it is missing or fails to decrypt.
4
+ */
5
+ export declare function decryptClaimValue(value: unknown, secret: string): string | undefined;
6
+ //# sourceMappingURL=decrypt-claim-value.d.ts.map
@@ -0,0 +1 @@
1
+ import{ENCRYPTED_CLAIM_PREFIX as t}from"./constants.js";import{decryptAesGcm as n}from"./decrypt-aes-gcm.js";function c(r,e){if(!(typeof r!="string"||!r)){if(!r.startsWith(t))return r;try{return n(r.slice(t.length),e)}catch{return}}}export{c as decryptClaimValue};
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Derives the AES-256-GCM key for a secret via HKDF-SHA256, cached per secret.
3
+ */
4
+ export declare function deriveKey(secret: string): Buffer;
5
+ //# sourceMappingURL=derive-key.d.ts.map
@@ -0,0 +1 @@
1
+ import{hkdfSync as t}from"node:crypto";const r=32,c="redocly-portal",f="claim-encryption",n=new Map;function y(o){let e=n.get(o);return e||(e=Buffer.from(t("sha256",o,c,f,r)),n.set(o,e)),e}export{y as deriveKey};
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Encrypts with AES-256-GCM using a key derived from the secret.
3
+ * Output layout: base64url(iv | ciphertext | authTag).
4
+ */
5
+ export declare function encryptAesGcm(plaintext: string, secret: string): string;
6
+ //# sourceMappingURL=encrypt-aes-gcm.d.ts.map
@@ -0,0 +1 @@
1
+ import{createCipheriv as i,randomBytes as n}from"node:crypto";import{IV_LENGTH_BYTES as f}from"./constants.js";import{deriveKey as a}from"./derive-key.js";function s(r,o){const e=n(f),t=i("aes-256-gcm",a(o),e),c=Buffer.concat([t.update(r,"utf8"),t.final()]);return Buffer.concat([e,c,t.getAuthTag()]).toString("base64url")}export{s as encryptAesGcm};
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Encrypts a JWT claim value and prefixes it so `decryptClaimValue` can tell
3
+ * encrypted values apart from legacy plaintext ones.
4
+ */
5
+ export declare function encryptClaimValue(value: string, secret: string): string;
6
+ //# sourceMappingURL=encrypt-claim-value.d.ts.map
@@ -0,0 +1 @@
1
+ import{ENCRYPTED_CLAIM_PREFIX as e}from"./constants.js";import{encryptAesGcm as m}from"./encrypt-aes-gcm.js";function p(r,t){return`${e}${m(r,t)}`}export{p as encryptClaimValue};
@@ -0,0 +1,7 @@
1
+ import type { TFunction } from '@redocly/theme/core/types';
2
+ import type { GlobalData } from '../../../types/index.js';
3
+ export declare function getBuildTranslateContext(slug: string, l10n: GlobalData['l10n']): Promise<{
4
+ locale: string;
5
+ translate: TFunction;
6
+ }>;
7
+ //# sourceMappingURL=get-build-translate-context.d.ts.map
@@ -0,0 +1 @@
1
+ import i from"i18next";import{getLocaleFromPathname as s}from"@redocly/theme/core/utils";import{DEFAULT_LOCALE_PLACEHOLDER as c}from"../../../constants/common.js";import{buildI18nConfig as l}from"../../../utils/l10n/build-i18n-config.js";import{createTranslate as f}from"../../../utils/l10n/create-translate.js";let o;function m(t){if(!o||o.l10n!==t){const e=(async()=>{const a=i.createInstance(),n=t?.defaultLocale||c;return await a.init(await l(t,n)),a})();o={l10n:t,instance:e}}return o.instance}async function x(t,e){const a=e?.defaultLocale||c,n=s(t,a,e?.locales??[]),r=await m(e);return{locale:n,translate:f(r.getFixedT(n))}}export{x as getBuildTranslateContext};
@@ -1 +1 @@
1
- import y from"path";import T from"picomatch";import"../node-crypto-polyfill.js";import{REDOCLY_TEAMS_RBAC as L,REDOCLY_ROUTE_RBAC as R}from"@redocly/config";import{ServerRoutes as w}from"../../constants/api.js";import{DEFAULT_ANONYMOUS_VISITOR_TEAM as x,PUBLIC_RBAC_SCOPE_ITEM as A,RBAC_ALL_OTHER_TEAMS as u,DEFAULT_RBAC_SCOPE as _}from"../../constants/common.js";import{DEPRECATED_PUBLIC_API_DEFINITIONS_FOLDER as I,PUBLIC_API_DEFINITIONS_FOLDER as j,PUBLIC_ASSETS_FOLDER as N}from"../constants/common.js";import{removeTrailingSlash as k}from"../../utils/url/remove-trailing-slash.js";import{removeLeadingSlash as B}from"../../utils/url/remove-leading-slash.js";import{parsePathVersions as b}from"../../utils/path/parse-path-versions.js";import{reporter as M}from"../tools/notifiers/reporter.js";import{bold as W}from"../tools/notifiers/helpers/colors.js";import{shaDirPathShort as U}from"../utils/crypto/sha-dir-path-short.js";import{isTruthy as $}from"../../utils/guards/is-truthy.js";import{canExpandConfig as v,expandRbacConfig as Y,getTeamFolderDefaults as z,parseTeamFoldersTemplate as K,parseTeamNameTemplate as H}from"./rbac-expand.js";import{getUserParamsFromCookies as G}from"../web-server/auth.js";import{getDeeperGlobPattern as V}from"./globs.js";import{EntitlementsProvider as J}from"../entitlements/entitlements-provider.js";const C=["NONE","READ","TRIAGE","WRITE","MAINTAIN","ADMIN"],Q=new Set(["x-parsed-md-description","x-parsed-md-summary"]);function xt(t,e){const r=C.indexOf(t.toUpperCase()),n=C.indexOf(e.toUpperCase());return r>n?t:e}const E={};function O(t,e){if(!t?.content)return A;const r=t.content,{slug:n,fsPath:o}=e;if(!n&&!o)return A;const s=f=>{const d=`slug:${f}`,p=E[d]??T(f);E[d]=p;const D=`fsPath:${f}`,S=E[D]??T(B(f));return E[D]=S,!!(n&&p(n))||!!(o&&S(o))};if(et(n||o||"")&&Object.keys(r).filter(p=>s(p)).length===0)return r[_]||A;const a=Object.keys(r).filter(f=>s(f));if(a.length==0)return A;const l=a.map(f=>T.scan(f,{tokens:!0,parts:!0}));let h=l[0];for(let f=1;f<l.length;f++)h=V(h,l[f]);return r[h.input]}function gt(t,e,r={},n=!1){if(n&&Object.keys(r).length===0)return e.isAuthenticated;const o=r.features?.[t];return o?e.teams.some(s=>o[s]&&o[s].toLowerCase()!=="none"):!0}function Dt(t,e){return P(t,{isAuthenticated:!1,teams:[x]},e.access?.rbac||{},e.access?.requiresLogin||!1)}function P(t,e={},r={},n=!1){if(t.slug&&typeof t.slug=="string"&&Object.values(w).some(a=>{const l=a.split(":")[0].replace(/\/$/,"");return t.slug===l||t.slug?.startsWith(a)})||typeof t.slug=="string"&&t.slug?.endsWith("/mcp")&&J.instance().canAccessFeature("mcp"))return!0;if(n&&Object.keys(r).length===0)return!!e.isAuthenticated;const o=Y(r,e.teams||[]),s=t[L]||O(o,t[R]||{});if(Object.keys(s||{}).length===0)return!1;if(Object.keys(s).length===1&&s[u]&&s[u].toLowerCase()!=="none")return!0;const i=(e?.email?[...e?.teams||[],e?.email]:e?.teams)||[],c=[];for(const a of i??[])s[a]?c.push(s[a]):s[u]&&a!==e?.email&&c.push(s[u]);return c.length?c.some(a=>a.toLowerCase()!=="none"):!1}function St(t,e,r,n){if(!t.startsWith(j)&&!t.startsWith(I))return!0;const o=t.replace(new RegExp(`^${j}/`),"").replace(new RegExp(`^${I}/`),""),i=o==="."?"":o,c={[R]:{slug:t,fsPath:i},slug:t};return P(c,n,e,r)}function Lt(t,e,r,n,o){if(!t.startsWith(N))return!0;const s=t.match(/.*\..{64}\.([A-Fa-f0-9]{8})\.[^\.]+$/)?.[1];if(!s)return!0;const i=n[s];if(!i)return!0;const{base:c,ext:a}=y.parse(t),l=c.split(".")[0],h=a.split(".").join(""),d=i==="."?"":i,p={[R]:{slug:t,fsPath:y.posix.join(d,`${l}.${h}`)},slug:t};return P(p,o,e,r)}async function _t(t,e){const{isAuthenticated:r=!1,idpAccessToken:n,federatedAccessToken:o,federatedIdToken:s,...i}=await G(t,e),{teams:c=[]}=i;let a;return r?a=c.filter(l=>l!==x):a=[x],{isAuthenticated:r,idpAccessToken:n,teams:a,claims:i}}function F(t,e,r={},n=!1){if(!t)return t;if(Array.isArray(t)){const o=[];for(const s of t){const i=F(s,e,r,n);i!==void 0&&o.push(i)}return tt(o)}if(typeof t=="object"){if(!P(t,e,r,n))return;let o=!1;const s={};for(const i in t){if(i===L||i===R)continue;if(Q.has(i)){s[i]=t[i];continue}const c=F(t[i],e,r,n);if(i==="items"&&Array.isArray(c)&&c.length===0&&t[i].length!==0){o=!0;continue}c!==void 0&&(s[i]=c),i==="paths"&&X(c)&&Z(c)}return o?void 0:s}return t}function It(t){return typeof t=="string"?t.split(" ").filter(Boolean):Array.isArray(t)?t.map(e=>e.toString()):[]}function jt(t,e){if(!e)return;const r=e.content;if(!r)return e;const n=Object.entries(r).flatMap(([s,i])=>s===_?[[s,i]]:[[s,i],...t.localeFolders.map(c=>[s.startsWith("/")?`/${c.toLocaleLowerCase()}${s}`:y.posix.join(t.localizationFolder,c,s),i])]),o=Object.fromEntries(n);return{...e,content:o}}async function Ct(t,e){if(!e)return{};const r={},n=new Set((await t.scan()).flatMap(({relativePath:o})=>{const{versionFolderPath:s}=b(o)||{},i=y.dirname(o);return s?[s,i]:i}));for(const o of n)r[U(o)]=o;return r}const m=t=>typeof t=="object"&&t!==null&&!Array.isArray(t);function X(t){return m(t)&&Object.keys(t).length>0}function Z(t){for(const e of Object.keys(t)){const r=t[e];m(r)&&Object.keys(r).length===0&&delete t[e]}}function q(t){return m(t)&&t.type==="separator"}function tt(t){const e=[];let r;for(const n of t){if(q(n)){r=n;continue}r&&(e.push(r),r=void 0),e.push(n)}return e}function et(t){return t?t.split("/").filter(Boolean).some(r=>r.startsWith(".")):!1}const rt=t=>{if(t&&m(t)&&("content"in t&&m(t.content)||"reunite"in t&&m(t.reunite)||"features"in t&&m(t.features)||t.teamFolders&&t.teamNamePatterns)){const e=Object.values(t.content||{});if(e.length===0)return!0;if(e.every(m))return e.every(r=>Object.values(r).every(n=>typeof n=="string"))}return!1},Ft=async t=>{if(t){if(Object.keys(t).length===0)return{};if(rt(t))return nt(t);await M.panicOnContentError(`You are using an incorrect format of ${W("rbac:")} configuration. See: https://redocly.com/docs/realm/access`)}},nt=t=>{const e={...t};if(e.content){const r={};for(const n in e.content)if(e.content[n]!==void 0){const o=k(n);r[o]=e.content[n]}e.content=r}return e};function wt(t,e){const r=t.fsPath,n=t.slug,o=[];if(v(e)&&(r||n)){const s=[r,n].filter($),i=K(e,s);if(i){const c=e?.teamNamePatterns?.map(l=>l.replace("{teamPathSegment}",i.teamPathSegment).replace("{projectRole}","read"))??[];o.push(...c);const a=O({content:{...z(e),...e.content}},t);o.push(...g(a))}else{const c=O(e,t);o.push(...g(c))}}else{const s=O(e,t);o.push(...g(s))}return ot(e,o)}function g(t){if(!t)return[];const e=[],r=u in t?{authenticated:t[u],anonymous:t[u]}:{};for(const[n,o]of Object.entries({...r,...t}))o.toLowerCase()!=="none"&&n!==u&&e.push(n);return e}function ot(t,e){return e.map(n=>H(t,n)??{teamName:n}).map(n=>n.projectRole&&n.projectRole!=="READ"?n.teamName?.toLowerCase().replace(n.projectRole?.toLowerCase?.()??"","read")??"":n.teamName?.toLowerCase()??"")}export{C as PROJECT_ROLES_ORDERED_BY_ACCESS_LEVEL,jt as applyL10nToRbacConfig,Lt as canAccessAsset,gt as canAccessFeature,P as canAccessResource,St as canDownloadApiDefinition,ot as expandTeamsForRead,g as extractTeamsFromScopeItems,F as filterDataByAccessDeep,_t as getAuthDetailsFromCookies,xt as getHigherRole,wt as getRbacTeamsListForResource,O as getScopeItemsForResource,rt as isRbacConfigValid,Dt as isResourcePubliclyAccessible,nt as normalizeRbacConfig,Ft as parseRbacConfig,It as parseTeamClaimToArray,Ct as resolveDirectoryHashes};
1
+ import y from"path";import T from"picomatch";import"../node-crypto-polyfill.js";import{REDOCLY_TEAMS_RBAC as L,REDOCLY_ROUTE_RBAC as R}from"@redocly/config";import{ServerRoutes as w}from"../../constants/api.js";import{DEFAULT_ANONYMOUS_VISITOR_TEAM as x,PUBLIC_RBAC_SCOPE_ITEM as A,RBAC_ALL_OTHER_TEAMS as u,DEFAULT_RBAC_SCOPE as _}from"../../constants/common.js";import{DEPRECATED_PUBLIC_API_DEFINITIONS_FOLDER as I,PUBLIC_API_DEFINITIONS_FOLDER as j,PUBLIC_ASSETS_FOLDER as N}from"../constants/common.js";import{removeTrailingSlash as k}from"../../utils/url/remove-trailing-slash.js";import{removeLeadingSlash as B}from"../../utils/url/remove-leading-slash.js";import{parsePathVersions as b}from"../../utils/path/parse-path-versions.js";import{reporter as M}from"../tools/notifiers/reporter.js";import{bold as U}from"../tools/notifiers/helpers/colors.js";import{shaDirPathShort as W}from"../utils/crypto/sha-dir-path-short.js";import{isTruthy as $}from"../../utils/guards/is-truthy.js";import{canExpandConfig as v,expandRbacConfig as Y,getTeamFolderDefaults as z,parseTeamFoldersTemplate as K,parseTeamNameTemplate as H}from"./rbac-expand.js";import{getUserParamsFromCookies as G}from"../web-server/auth.js";import{getDeeperGlobPattern as V}from"./globs.js";import{EntitlementsProvider as J}from"../entitlements/entitlements-provider.js";const C=["NONE","READ","TRIAGE","WRITE","MAINTAIN","ADMIN"],Q=new Set(["x-parsed-md-description","x-parsed-md-summary"]);function xt(t,e){const r=C.indexOf(t.toUpperCase()),n=C.indexOf(e.toUpperCase());return r>n?t:e}const E={};function O(t,e){if(!t?.content)return A;const r=t.content,{slug:n,fsPath:o}=e;if(!n&&!o)return A;const s=f=>{const d=`slug:${f}`,p=E[d]??T(f);E[d]=p;const g=`fsPath:${f}`,S=E[g]??T(B(f));return E[g]=S,!!(n&&p(n))||!!(o&&S(o))};if(et(n||o||"")&&Object.keys(r).filter(p=>s(p)).length===0)return r[_]||A;const i=Object.keys(r).filter(f=>s(f));if(i.length==0)return A;const l=i.map(f=>T.scan(f,{tokens:!0,parts:!0}));let h=l[0];for(let f=1;f<l.length;f++)h=V(h,l[f]);return r[h.input]}function Dt(t,e,r={},n=!1){if(n&&Object.keys(r).length===0)return e.isAuthenticated;const o=r.features?.[t];return o?e.teams.some(s=>o[s]&&o[s].toLowerCase()!=="none"):!0}function gt(t,e){return P(t,{isAuthenticated:!1,teams:[x]},e.access?.rbac||{},e.access?.requiresLogin||!1)}function P(t,e={},r={},n=!1){if(t.slug&&typeof t.slug=="string"&&Object.values(w).some(i=>{const l=i.split(":")[0].replace(/\/$/,"");return t.slug===l||t.slug?.startsWith(i)})||t.slug==="/mcp"&&J.instance().canAccessFeature("mcp"))return!0;if(n&&Object.keys(r).length===0)return!!e.isAuthenticated;const o=Y(r,e.teams||[]),s=t[L]||O(o,t[R]||{});if(Object.keys(s||{}).length===0)return!1;if(Object.keys(s).length===1&&s[u]&&s[u].toLowerCase()!=="none")return!0;const c=(e?.email?[...e?.teams||[],e?.email]:e?.teams)||[],a=[];for(const i of c??[])s[i]?a.push(s[i]):s[u]&&i!==e?.email&&a.push(s[u]);return a.length?a.some(i=>i.toLowerCase()!=="none"):!1}function St(t,e,r,n){if(!t.startsWith(j)&&!t.startsWith(I))return!0;const o=t.replace(new RegExp(`^${j}/`),"").replace(new RegExp(`^${I}/`),""),c=o==="."?"":o,a={[R]:{slug:t,fsPath:c},slug:t};return P(a,n,e,r)}function Lt(t,e,r,n,o){if(!t.startsWith(N))return!0;const s=t.match(/.*\..{64}\.([A-Fa-f0-9]{8})\.[^\.]+$/)?.[1];if(!s)return!0;const c=n[s];if(!c)return!0;const{base:a,ext:i}=y.parse(t),l=a.split(".")[0],h=i.split(".").join(""),d=c==="."?"":c,p={[R]:{slug:t,fsPath:y.posix.join(d,`${l}.${h}`)},slug:t};return P(p,o,e,r)}async function _t(t,e){const{isAuthenticated:r=!1,idpAccessToken:n,federatedAccessToken:o,federatedIdToken:s,...c}=await G(t,e),{teams:a=[]}=c;let i;return r?i=a.filter(l=>l!==x):i=[x],{isAuthenticated:r,idpAccessToken:n,teams:i,claims:c}}function F(t,e,r={},n=!1){if(!t)return t;if(Array.isArray(t)){const o=[];for(const s of t){const c=F(s,e,r,n);c!==void 0&&o.push(c)}return tt(o)}if(typeof t=="object"){if(!P(t,e,r,n))return;let o=!1;const s={};for(const c in t){if(c===L||c===R)continue;if(Q.has(c)){s[c]=t[c];continue}const a=F(t[c],e,r,n);if(c==="items"&&Array.isArray(a)&&a.length===0&&t[c].length!==0){o=!0;continue}a!==void 0&&(s[c]=a),c==="paths"&&X(a)&&Z(a)}return o?void 0:s}return t}function It(t){return typeof t=="string"?t.split(" ").filter(Boolean):Array.isArray(t)?t.map(e=>e.toString()):[]}function jt(t,e){if(!e)return;const r=e.content;if(!r)return e;const n=Object.entries(r).flatMap(([s,c])=>s===_?[[s,c]]:[[s,c],...t.localeFolders.map(a=>[s.startsWith("/")?`/${a.toLocaleLowerCase()}${s}`:y.posix.join(t.localizationFolder,a,s),c])]),o=Object.fromEntries(n);return{...e,content:o}}async function Ct(t,e){if(!e)return{};const r={},n=new Set((await t.scan()).flatMap(({relativePath:o})=>{const{versionFolderPath:s}=b(o)||{},c=y.dirname(o);return s?[s,c]:c}));for(const o of n)r[W(o)]=o;return r}const m=t=>typeof t=="object"&&t!==null&&!Array.isArray(t);function X(t){return m(t)&&Object.keys(t).length>0}function Z(t){for(const e of Object.keys(t)){const r=t[e];m(r)&&Object.keys(r).length===0&&delete t[e]}}function q(t){return m(t)&&t.type==="separator"}function tt(t){const e=[];let r;for(const n of t){if(q(n)){r=n;continue}r&&(e.push(r),r=void 0),e.push(n)}return e}function et(t){return t?t.split("/").filter(Boolean).some(r=>r.startsWith(".")):!1}const rt=t=>{if(t&&m(t)&&("content"in t&&m(t.content)||"reunite"in t&&m(t.reunite)||"features"in t&&m(t.features)||t.teamFolders&&t.teamNamePatterns)){const e=Object.values(t.content||{});if(e.length===0)return!0;if(e.every(m))return e.every(r=>Object.values(r).every(n=>typeof n=="string"))}return!1},Ft=async t=>{if(t){if(Object.keys(t).length===0)return{};if(rt(t))return nt(t);await M.panicOnContentError(`You are using an incorrect format of ${U("rbac:")} configuration. See: https://redocly.com/docs/realm/access`)}},nt=t=>{const e={...t};if(e.content){const r={};for(const n in e.content)if(e.content[n]!==void 0){const o=k(n);r[o]=e.content[n]}e.content=r}return e};function wt(t,e){const r=t.fsPath,n=t.slug,o=[];if(v(e)&&(r||n)){const s=[r,n].filter($),c=K(e,s);if(c){const a=e?.teamNamePatterns?.map(l=>l.replace("{teamPathSegment}",c.teamPathSegment).replace("{projectRole}","read"))??[];o.push(...a);const i=O({content:{...z(e),...e.content}},t);o.push(...D(i))}else{const a=O(e,t);o.push(...D(a))}}else{const s=O(e,t);o.push(...D(s))}return ot(e,o)}function D(t){if(!t)return[];const e=[],r=u in t?{authenticated:t[u],anonymous:t[u]}:{};for(const[n,o]of Object.entries({...r,...t}))o.toLowerCase()!=="none"&&n!==u&&e.push(n);return e}function ot(t,e){return e.map(n=>H(t,n)??{teamName:n}).map(n=>n.projectRole&&n.projectRole!=="READ"?n.teamName?.toLowerCase().replace(n.projectRole?.toLowerCase?.()??"","read")??"":n.teamName?.toLowerCase()??"")}export{C as PROJECT_ROLES_ORDERED_BY_ACCESS_LEVEL,jt as applyL10nToRbacConfig,Lt as canAccessAsset,Dt as canAccessFeature,P as canAccessResource,St as canDownloadApiDefinition,ot as expandTeamsForRead,D as extractTeamsFromScopeItems,F as filterDataByAccessDeep,_t as getAuthDetailsFromCookies,xt as getHigherRole,wt as getRbacTeamsListForResource,O as getScopeItemsForResource,rt as isRbacConfigValid,gt as isResourcePubliclyAccessible,nt as normalizeRbacConfig,Ft as parseRbacConfig,It as parseTeamClaimToArray,Ct as resolveDirectoryHashes};
@@ -35,12 +35,16 @@ export declare function isSaml2ProviderConfig(providerConfig: AuthProviderConfig
35
35
  export declare function getAuthProviderLoginParams(idpId: string, providerConfig: AuthProviderConfig): Promise<AuthProviderLoginParams | undefined>;
36
36
  export declare function getOidcLoginParams(idpId: string, providerConfig: OidcProviderConfig): Promise<OidcLoginParams>;
37
37
  export declare function getSaml2LoginParams(idpId: string, providerConfig: Saml2ProviderConfig): Saml2LoginParams;
38
- export declare function oidcExchangeCodeForToken(tokenUrl: string, code: string, redirectUri: string, idpConfig: OidcProviderConfig, extraParams?: Record<string, string>): Promise<{
38
+ export type OidcTokenResponse = {
39
39
  access_token?: string;
40
40
  id_token?: string;
41
+ refresh_token?: string;
42
+ expires_in?: number;
41
43
  error?: string;
42
44
  error_description?: string;
43
- }>;
45
+ };
46
+ export declare function oidcExchangeCodeForToken(tokenUrl: string, code: string, redirectUri: string, idpConfig: OidcProviderConfig, extraParams?: Record<string, string>): Promise<OidcTokenResponse>;
47
+ export declare function oidcRefreshTokenGrant(tokenUrl: string, refreshToken: string, idpConfig: OidcProviderConfig): Promise<OidcTokenResponse>;
44
48
  export declare function buildOidcLoginUrl(origin: string, { authorizationEndpoint, clientId, responseType, scope, extraParams, idpId, pkce, }: Partial<OidcLoginParams>, redirectTo: string | null, inviteCode?: string, options?: {
45
49
  redirectUriOverride?: string;
46
50
  sourceOverride?: 'portal' | 'mcp';
@@ -58,7 +62,10 @@ type McpAuthorizationCodePayload = {
58
62
  client_id: string;
59
63
  redirect_uri: string;
60
64
  id_token: string;
65
+ idp_id?: string;
61
66
  idp_access_token?: string;
67
+ idp_access_token_enc?: string;
68
+ idp_refresh_token_enc?: string;
62
69
  code_challenge?: string;
63
70
  code_challenge_method?: string;
64
71
  iat: number;
@@ -66,7 +73,9 @@ type McpAuthorizationCodePayload = {
66
73
  };
67
74
  export declare function createMcpAuthorizationCode(params: {
68
75
  idToken: string;
69
- idpAccessToken?: string;
76
+ idpId?: string;
77
+ idpAccessTokenEnc?: string;
78
+ idpRefreshTokenEnc?: string;
70
79
  clientId: string;
71
80
  redirectUri: string;
72
81
  codeChallenge?: string;
@@ -74,6 +83,26 @@ export declare function createMcpAuthorizationCode(params: {
74
83
  ttlSec?: number;
75
84
  }): Promise<string>;
76
85
  export declare function verifyMcpAuthorizationCode(code: string): Promise<McpAuthorizationCodePayload>;
86
+ export type McpRefreshTokenPayload = {
87
+ type: 'mcp_refresh_token';
88
+ client_id: string;
89
+ idp_id?: string;
90
+ claims: Record<string, unknown>;
91
+ idp_access_token_enc?: string;
92
+ idp_refresh_token_enc?: string;
93
+ session_exp: number;
94
+ iat: number;
95
+ exp: number;
96
+ };
97
+ export declare function createMcpRefreshToken(params: {
98
+ clientId: string;
99
+ idpId?: string;
100
+ claims: Record<string, unknown>;
101
+ idpAccessTokenEnc?: string;
102
+ idpRefreshTokenEnc?: string;
103
+ sessionExp: number;
104
+ }): Promise<string>;
105
+ export declare function verifyMcpRefreshToken(token: string): Promise<McpRefreshTokenPayload>;
77
106
  export declare function createMcpSessionResource(sessionId: string | null | undefined): {
78
107
  id: string;
79
108
  object: 'mcpSession';
@@ -114,6 +143,7 @@ export declare const oidcJwksCache: {
114
143
  }) | null>;
115
144
  };
116
145
  export declare function getOidcMetadata(idpId: string, providerConfig: OidcProviderConfig): Promise<OidcIssuerMetadata>;
146
+ export declare function discoverJwks(ssoConfig: SsoConfig): Promise<void>;
117
147
  export declare function getRedoclyTokenPayload(token: string): Promise<Record<string, unknown>>;
118
148
  export declare function isRedoclySso(config: OidcProviderConfig): boolean;
119
149
  export declare function verifySAMLResponse(responseXml: string, cert: string): Promise<boolean>;
@@ -1,12 +1,12 @@
1
- import"../node-crypto-polyfill.js";import{DOMParser as P}from"@xmldom/xmldom";import{SignedXml as q}from"xml-crypto";import K from"xpath";import{deflateSync as Y,inflateSync as Q}from"fflate";import{createHash as X}from"crypto";import{ulid as Z}from"ulid";import{AuthProviderType as u,DEFAULT_TEAM_CLAIM_NAME as N}from"@redocly/config";import{AUTH_URL as G,JWT_SECRET_KEY as C}from"../constants/common.js";import{envConfig as ee}from"../config/env-config.js";import{getPathPrefix as te,withPathPrefix as ne}from"@redocly/theme/core/utils";import{ServerRoutes as R}from"../../constants/api.js";import{AuthCookieNames as A,DEFAULT_AUTHENTICATED_TEAM as re,REQUIRED_OIDC_SCOPES as b}from"../../constants/common.js";import{appendQueryParams as oe}from"../../utils/url/append-query-params.js";import{parseHttpsUrl as v}from"../../utils/url/parse-https-url.js";import{logger as ae}from"../tools/notifiers/logger.js";import{randomString as se}from"../utils/crypto/random-string.js";import{randomUUID as U}from"../utils/crypto/random-uuid.js";import{AlgorithmTypes as w,JwtTokenExpired as ie}from"./jwt/types.js";import*as f from"./jwt/jwt.js";import{parseTeamClaimToArray as ce}from"../utils/index.js";import{arrayBufferToBase64 as ue,decodeBase64 as j,encodeBase64URL as le,urlSafeBase64 as V}from"./jwt/encode.js";import{formatSamlCertificate as de}from"./utils/format-saml-certificate.js";function $(e){return e?.type===u.OIDC}function me(e){return e?.type===u.SAML2}async function Ze(e,t){if($(t))return pe(e,t);if(me(t))return fe(e,t)}async function pe(e,t){const n=await z(e,t),r=new Set((t.scopes||[]).concat(b)),o=t.authorizationRequestCustomParams||{};return{type:u.OIDC,idpId:e,name:"OAuth provider",authorizationEndpoint:n.authorization_endpoint,clientId:t.clientId,responseType:"code",scope:Array.from(r).join(" "),extraParams:o,pkce:t.pkce}}function fe(e,t){return{type:u.SAML2,idpId:e,name:"SAML2 provider",ssoUrl:t.ssoUrl,issuerId:t.issuerId,entityId:t.entityId||t.issuerId}}async function Ge(e,t,n,r,o={}){const a=new Set((r.scopes||[]).concat(b));return await fetch(e,{method:"POST",body:new URLSearchParams({client_id:r.clientId,scope:Array.from(a).join(" "),code:t,redirect_uri:H(n),grant_type:"authorization_code",...r.clientSecret?{client_secret:r.clientSecret}:{},...o}).toString(),headers:{"Content-Type":"application/x-www-form-urlencoded",Accept:"application/json"}}).then(s=>s.json())}function he(e,{authorizationEndpoint:t,clientId:n,responseType:r,scope:o,extraParams:a,idpId:s,pkce:l},m,g,p){if(!t||!n||!r||!o)return{loginUrl:void 0};const i=new URL(t),h=p?.redirectUriOverride??`${e}${ne(R.OIDC_CALLBACK)}`,_={state:U(),idpId:s,redirectUri:h,redirectTo:m,branch:p?.branchOverride??ye(e),inviteCode:g,source:p?.sourceOverride??"portal",uiLocales:p?.uiLocales},y={};if(l){const d=V(se(50)),x=V(X("sha256").update(d).digest("base64")),I="S256";i.searchParams.append("code_challenge",x),i.searchParams.append("code_challenge_method",I),y.code_verifier={value:d,options:{secure:!0,httpOnly:!0,expires:new Date(Date.now()+1e3*60*10),path:te()||"/"}}}i.searchParams.append("client_id",n),i.searchParams.append("scope",o),i.searchParams.append("response_type",r),i.searchParams.append("redirect_uri",H(h)),i.searchParams.append("state",le(JSON.stringify(_))),p?.uiLocales&&i.searchParams.append("ui_locales",p.uiLocales);for(const d in a)a[d]!==void 0&&i.searchParams.append(d,a[d]);return{loginUrl:i.toString(),cookies:y}}function et(e,t,n,r){const o=new URL(e);return o.searchParams.append("post_logout_redirect_uri",t),r&&o.searchParams.append("state",r),o.searchParams.append("id_token_hint",n),o.toString()}async function tt(e){const t=Math.floor(Date.now()/1e3),n=t+(e.ttlSec??600);return f.sign({type:"mcp_auth_code",client_id:e.clientId,redirect_uri:e.redirectUri,id_token:e.idToken,...e.idpAccessToken?{idp_access_token:e.idpAccessToken}:{},...e.codeChallenge?{code_challenge:e.codeChallenge}:{},...e.codeChallengeMethod?{code_challenge_method:e.codeChallengeMethod}:{},iat:t,exp:n},C,w.HS256)}async function nt(e){await f.verify(e,C,w.HS256);const{payload:t}=f.decode(e);if(t.type!=="mcp_auth_code")throw new Error("Invalid authorization code type");if(!t.client_id||!t.redirect_uri)throw new Error("Authorization code missing required claims");if(typeof t.exp=="number"&&Date.now()>=t.exp*1e3)throw new Error("Authorization code expired");return t}function rt(e){const t=e||Z(),n=t.startsWith("mcp_")?t:`mcp_${t}`;return{id:n,object:"mcpSession",uri:`urn:redocly:realm:mcp:session:${n}`}}function H(e){const t=v(e);if(!t)return e;const n=we(t.hostname);if(n)return t.hostname=`previewauth--${n.previewBranch}${n.after}`,B(e,t);const r=F(t.hostname);return r?(t.hostname=`${r.projectSlug}.previewauth.${r.after}`,B(e,t)):e}function ye(e){const t=v(e);if(t)return F(t.hostname)?.previewBranch}function B(e,t){return e.replace(/^https:\/\/[^/?#]+/i,`https://${t.host}`)}function F(e){const t=e.split(".preview.",2);if(t.length<2)return null;const[n,r]=t,o=n.indexOf("--");if(o===-1)return null;const a=n.slice(0,o),s=n.slice(o+2);return!a||!s||s.includes(".")?null:{projectSlug:a,previewBranch:s,after:r}}function we(e){const t=e.indexOf("."),n=t===-1?e:e.slice(0,t);if(!n.startsWith("preview-"))return null;const r=n.indexOf("--");if(r===-1)return null;const o=n.slice(r+2);if(!o)return null;const a=t===-1?"":e.slice(t);return{previewBranch:o,after:a}}function Se(e){return e.type===u.OIDC}function Ae(e){return e.type===u.SAML2}function ot(e,t,n,r,o){return Se(e)?he(t,e,n,r,{uiLocales:o}):Ae(e)?ge(t,e,n,r,o):{}}function ge(e,t,n,r,o){const s=`<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
1
+ import"../node-crypto-polyfill.js";import{DOMParser as D}from"@xmldom/xmldom";import{SignedXml as Y}from"xml-crypto";import G from"xpath";import{deflateSync as Q,inflateSync as X}from"fflate";import{createHash as Z}from"crypto";import{ulid as ee}from"ulid";import{AuthProviderType as u,DEFAULT_TEAM_CLAIM_NAME as b}from"@redocly/config";import{AUTH_URL as te,JWT_SECRET_KEY as y}from"../constants/common.js";import{envConfig as ne}from"../config/env-config.js";import{decryptClaimValue as re}from"../utils/crypto/decrypt-claim-value.js";import{getPathPrefix as oe,withPathPrefix as se}from"@redocly/theme/core/utils";import{ServerRoutes as P}from"../../constants/api.js";import{AuthCookieNames as _,DEFAULT_AUTHENTICATED_TEAM as ae,REQUIRED_OIDC_SCOPES as v}from"../../constants/common.js";import{appendQueryParams as ie}from"../../utils/url/append-query-params.js";import{parseHttpsUrl as N}from"../../utils/url/parse-https-url.js";import{logger as ce}from"../tools/notifiers/logger.js";import{randomString as ue}from"../utils/crypto/random-string.js";import{randomUUID as U}from"../utils/crypto/random-uuid.js";import{AlgorithmTypes as h,JwtTokenExpired as le}from"./jwt/types.js";import*as l from"./jwt/jwt.js";import{parseTeamClaimToArray as de}from"../utils/index.js";import{arrayBufferToBase64 as me,decodeBase64 as j,encodeBase64URL as pe,urlSafeBase64 as V}from"./jwt/encode.js";import{formatSamlCertificate as fe}from"./utils/format-saml-certificate.js";function $(e){return e?.type===u.OIDC}function he(e){return e?.type===u.SAML2}async function nt(e,t){if($(t))return ye(e,t);if(he(t))return we(e,t)}async function ye(e,t){const n=await q(e,t),r=new Set((t.scopes||[]).concat(v)),o=t.authorizationRequestCustomParams||{};return{type:u.OIDC,idpId:e,name:"OAuth provider",authorizationEndpoint:n.authorization_endpoint,clientId:t.clientId,responseType:"code",scope:Array.from(r).join(" "),extraParams:o,pkce:t.pkce}}function we(e,t){return{type:u.SAML2,idpId:e,name:"SAML2 provider",ssoUrl:t.ssoUrl,issuerId:t.issuerId,entityId:t.entityId||t.issuerId}}function H(e){return Array.from(new Set((e.scopes||[]).concat(v))).join(" ")}async function B(e,t,n){return await fetch(e,{method:"POST",body:new URLSearchParams({client_id:t.clientId,...t.clientSecret?{client_secret:t.clientSecret}:{},...n}).toString(),headers:{"Content-Type":"application/x-www-form-urlencoded",Accept:"application/json"}}).then(r=>r.json())}async function rt(e,t,n,r,o={}){return await B(e,r,{scope:H(r),code:t,redirect_uri:F(n),grant_type:"authorization_code",...o})}async function ot(e,t,n){return await B(e,n,{scope:H(n),grant_type:"refresh_token",refresh_token:t})}function Se(e,{authorizationEndpoint:t,clientId:n,responseType:r,scope:o,extraParams:s,idpId:a,pkce:d},p,x,f){if(!t||!n||!r||!o)return{loginUrl:void 0};const i=new URL(t),w=f?.redirectUriOverride??`${e}${se(P.OIDC_CALLBACK)}`,g={state:U(),idpId:a,redirectUri:w,redirectTo:p,branch:f?.branchOverride??Ae(e),inviteCode:x,source:f?.sourceOverride??"portal",uiLocales:f?.uiLocales},S={};if(d){const m=V(ue(50)),k=V(Z("sha256").update(m).digest("base64")),I="S256";i.searchParams.append("code_challenge",k),i.searchParams.append("code_challenge_method",I),S.code_verifier={value:m,options:{secure:!0,httpOnly:!0,expires:new Date(Date.now()+1e3*60*10),path:oe()||"/"}}}i.searchParams.append("client_id",n),i.searchParams.append("scope",o),i.searchParams.append("response_type",r),i.searchParams.append("redirect_uri",F(w)),i.searchParams.append("state",pe(JSON.stringify(g))),f?.uiLocales&&i.searchParams.append("ui_locales",f.uiLocales);for(const m in s)s[m]!==void 0&&i.searchParams.append(m,s[m]);return{loginUrl:i.toString(),cookies:S}}function st(e,t,n,r){const o=new URL(e);return o.searchParams.append("post_logout_redirect_uri",t),r&&o.searchParams.append("state",r),o.searchParams.append("id_token_hint",n),o.toString()}async function at(e){const t=Math.floor(Date.now()/1e3),n=t+(e.ttlSec??600);return l.sign({type:"mcp_auth_code",client_id:e.clientId,redirect_uri:e.redirectUri,id_token:e.idToken,...e.idpId?{idp_id:e.idpId}:{},...e.idpAccessTokenEnc?{idp_access_token_enc:e.idpAccessTokenEnc}:{},...e.idpRefreshTokenEnc?{idp_refresh_token_enc:e.idpRefreshTokenEnc}:{},...e.codeChallenge?{code_challenge:e.codeChallenge}:{},...e.codeChallengeMethod?{code_challenge_method:e.codeChallengeMethod}:{},iat:t,exp:n},y,h.HS256)}async function it(e){await l.verify(e,y,h.HS256);const{payload:t}=l.decode(e);if(t.type!=="mcp_auth_code")throw new Error("Invalid authorization code type");if(!t.client_id||!t.redirect_uri)throw new Error("Authorization code missing required claims");if(typeof t.exp=="number"&&Date.now()>=t.exp*1e3)throw new Error("Authorization code expired");return t}async function ct(e){const t=Math.floor(Date.now()/1e3);return l.sign({type:"mcp_refresh_token",client_id:e.clientId,...e.idpId?{idp_id:e.idpId}:{},claims:e.claims,...e.idpAccessTokenEnc?{idp_access_token_enc:e.idpAccessTokenEnc}:{},...e.idpRefreshTokenEnc?{idp_refresh_token_enc:e.idpRefreshTokenEnc}:{},session_exp:e.sessionExp,iat:t,exp:e.sessionExp},y,h.HS256)}async function ut(e){await l.verify(e,y,h.HS256);const{payload:t}=l.decode(e);if(t.type!=="mcp_refresh_token")throw new Error("Invalid refresh token type");if(!t.client_id||typeof t.claims!="object"||t.claims===null)throw new Error("Refresh token missing required claims");if(typeof t.session_exp!="number")throw new Error("Refresh token missing session expiry");return t}function lt(e){const t=e||ee(),n=t.startsWith("mcp_")?t:`mcp_${t}`;return{id:n,object:"mcpSession",uri:`urn:redocly:realm:mcp:session:${n}`}}function F(e){const t=N(e);if(!t)return e;const n=_e(t.hostname);if(n)return t.hostname=`previewauth--${n.previewBranch}${n.after}`,z(e,t);const r=W(t.hostname);return r?(t.hostname=`${r.projectSlug}.previewauth.${r.after}`,z(e,t)):e}function Ae(e){const t=N(e);if(t)return W(t.hostname)?.previewBranch}function z(e,t){return e.replace(/^https:\/\/[^/?#]+/i,`https://${t.host}`)}function W(e){const t=e.split(".preview.",2);if(t.length<2)return null;const[n,r]=t,o=n.indexOf("--");if(o===-1)return null;const s=n.slice(0,o),a=n.slice(o+2);return!s||!a||a.includes(".")?null:{projectSlug:s,previewBranch:a,after:r}}function _e(e){const t=e.indexOf("."),n=t===-1?e:e.slice(0,t);if(!n.startsWith("preview-"))return null;const r=n.indexOf("--");if(r===-1)return null;const o=n.slice(r+2);if(!o)return null;const s=t===-1?"":e.slice(t);return{previewBranch:o,after:s}}function xe(e){return e.type===u.OIDC}function ge(e){return e.type===u.SAML2}function dt(e,t,n,r,o){return xe(e)?Se(t,e,n,r,{uiLocales:o}):ge(e)?ke(t,e,n,r,o):{}}function ke(e,t,n,r,o){const a=`<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
2
2
  xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
3
3
  Version="2.0"
4
4
  ID="_${U()}"
5
5
  IssueInstant="${new Date().toISOString()}"
6
- AssertionConsumerServiceURL="${e}${R.SAML_CALLBACK}"
6
+ AssertionConsumerServiceURL="${e}${P.SAML_CALLBACK}"
7
7
  AttributeConsumingServiceIndex="0">
8
8
  <saml:Issuer>${t.entityId}</saml:Issuer>
9
9
  <samlp:NameIDPolicy
10
10
  AllowCreate="true"
11
11
  Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"/>
12
- </samlp:AuthnRequest>`,l=_e(s);return{loginUrl:oe(t.ssoUrl,{SAMLRequest:l,RelayState:JSON.stringify({idpId:t.idpId,redirectTo:n,inviteCode:r,source:"portal",uiLocales:o})})}}function _e(e){return ue(Y(new TextEncoder().encode(e)).buffer)}function at(e){const t=j(e);if(t.startsWith("<samlp:Response")||t.indexOf("<saml2p:Response")>-1)return t;const n=Q(new Uint8Array(atob(e).split("").map(r=>r.charCodeAt(0))));return new TextDecoder().decode(n)}function st(e){try{return JSON.parse(j(e||""))}catch{throw new Error("Invalid OAuth2 state")}}function it(e){const t=new P().parseFromString(e,"application/xml"),r=c(t,"//*[local-name(.)='StatusCode']/@Value")[0]?.nodeValue?.endsWith("Success")||!1,a=c(t,"//*[local-name(.)='Response']/@Destination")[0]?.nodeValue||"",s=c(t,"//*[local-name(.)='Assertion']//*[local-name(.)='Issuer']/text()")[0],l=s&&s.nodeValue||void 0,m=c(t,"//*[local-name(.)='Audience']/text()")[0],g=m&&m.nodeValue||void 0,i=c(t,"//*[local-name(.)='Assertion']//*[local-name(.)='X509Certificate']/text()")[0]?.nodeValue||"",h=c(t,"//*[local-name(.)='Subject']//*[local-name(.)='NameID']/text()")[0],_=h&&h.nodeValue||"",y=c(t,"//*[local-name(.)='Subject']//*[local-name(.)='NameID']/@Format")[0],d=y&&y.nodeValue||"",x=c(t,"//*[local-name(.)='Conditions']/@NotOnOrAfter")[0],I=xe(x),O={},D=c(t,"//*[local-name(.)='AttributeStatement']//*[local-name(.)='Attribute']");if(D.length)for(const M of D){const k=c(M,"./@Name")[0];if(k.nodeValue){const E=c(M,"./*[local-name(.)='AttributeValue']/text()")[0];E?.nodeValue&&(O[k.nodeValue]=E.nodeValue)}}return{uid:_,success:r,expiresAt:I,issuerId:l,entityId:g,attrs:O,cert:i,nameFormat:d,destination:a}}function xe(e){const t=typeof e?.nodeValue=="string"&&L(Date.parse(e.nodeValue)),n=L(Date.now()),r=L(Date.now()+720*60*1e3);return t?t>n&&t<r?r:t:n}function L(e){return Math.floor(e/1e3)}const T={},S={jwks:{}};async function z(e,t){if(!T[e]){const n=t.configurationUrl?await W(t.configurationUrl):t.configuration;T[e]=Ie()?Ce(n):n}return T[e]}function Ie(){const e=ee.REDOCLY_ENFORCE_RESIDENCY;return!!e&&e.includes("host.docker.internal")}function Ce(e){if(typeof e!="object"||e===null)return e;const t={...e};for(const n of Object.keys(t)){const r=t[n];typeof r=="string"&&r.includes("://localhost")&&(t[n]=r.replace("://localhost","://host.docker.internal"))}return t}async function Le(e){for(const t of Object.keys(e)){const n=e[t];if(!$(n))continue;const r=await z(t,n);if(r.jwks_uri){const o=await W(r.jwks_uri);for(const a of o.keys)S.jwks[a.kid]={...a,idpId:t}}}}async function W(e){return fetch(e,{headers:{Accept:"application/json"}}).then(t=>t.json())}async function ct(e){return fetch(`${G}/oidc/userinfo`,{headers:{Accept:"application/json",Authorization:`Bearer ${e}`}}).then(t=>t.status===200?t.json():void 0).catch(()=>{})}function ut(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(r=>Te(t.hostname,r))}function Te(e,t){return e===t||e.endsWith(`.${t}`)}async function lt(e,t){const n=new P().parseFromString(e,"application/xml"),r=c(n,"//*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']")[0];if(!r)throw new Error("Cannot find Signature in the SAML response");const o=de(t),a=new q({publicCert:o});a.loadSignature(r);try{return a.checkSignature(e)}catch{return!1}}function dt(e,t,n,r){t==="urn:oasis:names:tc:SAML:2.0:nameid-format:transient"&&(e=n["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=n["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"],s=a?.match(/.+@.+/);return o=o||n["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"]||(s?a:void 0),o=o?.toLowerCase(),{sub:e,given_name:n["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname"],family_name:n["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname"],name:n["http://schemas.microsoft.com/identity/claims/displayname"]||a,email:o,email_verified:!0,teams:r?ce(n[r]):[]}}function J(e,t={}){return e.map(n=>t[n]||n)}async function mt(e,t){if(!t)return{};const n=t[A.AUTHORIZATION];if(!n)return{};try{const r=f.decode(n);if(r.header.alg===w.RS256){S.jwks[r.header.kid]===void 0&&await Le(e);const m=S.jwks[r.header.kid];if(!m)return S.jwks[r.header.kid]=null,{};await f.verify(n,m,w.RS256)}else await f.verify(n,C,w.HS256);const o=r.payload.idpId||S.jwks[r.header.kid]?.idpId,a=e[o]||{},s=Me(a),l=De(a);return{...r.payload,email:r.payload.email?.toLowerCase(),idpId:o,teams:Array.from(new Set([...J(r.payload.teams||[],l),..."defaultTeams"in a&&a.defaultTeams||[],...J("teamsClaimName"in a&&r.payload[s||""]||[],l),re])),name:Oe(r.payload),isAuthenticated:!0,idpAccessToken:r.payload.idp_access_token||t[A.IDP_ACCESS_TOKEN],federatedAccessToken:t[A.FEDERATED_ACCESS_TOKEN],federatedIdToken:t[A.FEDERATED_ID_TOKEN],authCookie:n}}catch(r){r instanceof ie||ae.error("Malformed JWT token: %s",r.message)}return{}}function Oe(e){return(e.firstName&&e.lastName?`${e.firstName} ${e.lastName}`:e.name||e.given_name||e.firstName||e.lastName)||e.email}function De(e){switch(e.type){case u.SAML2:return e.teamsAttributeMap;case u.OIDC:return e.teamsClaimMap;default:return}}function Me(e){switch(e.type){case u.SAML2:return e.teamsAttributeName??N;case u.OIDC:return e.teamsClaimName;default:return N}}function c(e,t){return K.select(t,e)||[]}export{ot as buildLoginUrl,he as buildOidcLoginUrl,et as buildOidcLogoutUrl,ge as buildSAML2LoginUrl,tt as createMcpAuthorizationCode,rt as createMcpSessionResource,at as decodeSamlResponse,_e as encodeSAML2,dt as extractUserClaims,Ze as getAuthProviderLoginParams,pe as getOidcLoginParams,z as getOidcMetadata,ct as getRedoclyTokenPayload,fe as getSaml2LoginParams,mt as getUserParamsFromCookies,Oe as getUsernameFromPayload,$ as isOidcProviderConfig,ut as isRedoclySso,me as isSaml2ProviderConfig,Ge as oidcExchangeCodeForToken,S as oidcJwksCache,T as oidcMetadataCache,st as parseOidcState,ye as parsePreviewBranch,it as parseSamlResponse,H as rewritePreviewAuthRedirectUri,nt as verifyMcpAuthorizationCode,lt as verifySAMLResponse};
12
+ </samlp:AuthnRequest>`,d=Ie(a);return{loginUrl:ie(t.ssoUrl,{SAMLRequest:d,RelayState:JSON.stringify({idpId:t.idpId,redirectTo:n,inviteCode:r,source:"portal",uiLocales:o})})}}function Ie(e){return me(Q(new TextEncoder().encode(e)).buffer)}function mt(e){const t=j(e);if(t.startsWith("<samlp:Response")||t.indexOf("<saml2p:Response")>-1)return t;const n=X(new Uint8Array(atob(e).split("").map(r=>r.charCodeAt(0))));return new TextDecoder().decode(n)}function pt(e){try{return JSON.parse(j(e||""))}catch{throw new Error("Invalid OAuth2 state")}}function ft(e){const t=new D().parseFromString(e,"application/xml"),r=c(t,"//*[local-name(.)='StatusCode']/@Value")[0]?.nodeValue?.endsWith("Success")||!1,s=c(t,"//*[local-name(.)='Response']/@Destination")[0]?.nodeValue||"",a=c(t,"//*[local-name(.)='Assertion']//*[local-name(.)='Issuer']/text()")[0],d=a&&a.nodeValue||void 0,p=c(t,"//*[local-name(.)='Audience']/text()")[0],x=p&&p.nodeValue||void 0,i=c(t,"//*[local-name(.)='Assertion']//*[local-name(.)='X509Certificate']/text()")[0]?.nodeValue||"",w=c(t,"//*[local-name(.)='Subject']//*[local-name(.)='NameID']/text()")[0],g=w&&w.nodeValue||"",S=c(t,"//*[local-name(.)='Subject']//*[local-name(.)='NameID']/@Format")[0],m=S&&S.nodeValue||"",k=c(t,"//*[local-name(.)='Conditions']/@NotOnOrAfter")[0],I=Te(k),C={},L=c(t,"//*[local-name(.)='AttributeStatement']//*[local-name(.)='Attribute']");if(L.length)for(const R of L){const M=c(R,"./@Name")[0];if(M.nodeValue){const O=c(R,"./*[local-name(.)='AttributeValue']/text()")[0];O?.nodeValue&&(C[M.nodeValue]=O.nodeValue)}}return{uid:g,success:r,expiresAt:I,issuerId:d,entityId:x,attrs:C,cert:i,nameFormat:m,destination:s}}function Te(e){const t=typeof e?.nodeValue=="string"&&T(Date.parse(e.nodeValue)),n=T(Date.now()),r=T(Date.now()+720*60*1e3);return t?t>n&&t<r?r:t:n}function T(e){return Math.floor(e/1e3)}const E={},A={jwks:{}};async function q(e,t){if(!E[e]){const n=t.configurationUrl?await J(t.configurationUrl):t.configuration;E[e]=Ee()?Ce(n):n}return E[e]}function Ee(){const e=ne.REDOCLY_ENFORCE_RESIDENCY;return!!e&&e.includes("host.docker.internal")}function Ce(e){if(typeof e!="object"||e===null)return e;const t={...e};for(const n of Object.keys(t)){const r=t[n];typeof r=="string"&&r.includes("://localhost")&&(t[n]=r.replace("://localhost","://host.docker.internal"))}return t}async function Le(e){for(const t of Object.keys(e)){const n=e[t];if(!$(n))continue;const r=await q(t,n);if(r.jwks_uri){const o=await J(r.jwks_uri);for(const s of o.keys)A.jwks[s.kid]={...s,idpId:t}}}}async function J(e){return fetch(e,{headers:{Accept:"application/json"}}).then(t=>t.json())}async function ht(e){return fetch(`${te}/oidc/userinfo`,{headers:{Accept:"application/json",Authorization:`Bearer ${e}`}}).then(t=>t.status===200?t.json():void 0).catch(()=>{})}function yt(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(r=>Re(t.hostname,r))}function Re(e,t){return e===t||e.endsWith(`.${t}`)}async function wt(e,t){const n=new D().parseFromString(e,"application/xml"),r=c(n,"//*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']")[0];if(!r)throw new Error("Cannot find Signature in the SAML response");const o=fe(t),s=new Y({publicCert:o});s.loadSignature(r);try{return s.checkSignature(e)}catch{return!1}}function St(e,t,n,r){t==="urn:oasis:names:tc:SAML:2.0:nameid-format:transient"&&(e=n["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 s=n["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"],a=s?.match(/.+@.+/);return o=o||n["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"]||(a?s:void 0),o=o?.toLowerCase(),{sub:e,given_name:n["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname"],family_name:n["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname"],name:n["http://schemas.microsoft.com/identity/claims/displayname"]||s,email:o,email_verified:!0,teams:r?de(n[r]):[]}}function K(e,t={}){return e.map(n=>t[n]||n)}async function At(e,t){if(!t)return{};const n=t[_.AUTHORIZATION];if(!n)return{};try{const r=l.decode(n);if(r.header.alg===h.RS256){A.jwks[r.header.kid]===void 0&&await Le(e);const p=A.jwks[r.header.kid];if(!p)return A.jwks[r.header.kid]=null,{};await l.verify(n,p,h.RS256)}else await l.verify(n,y,h.HS256);const o=r.payload.idpId||A.jwks[r.header.kid]?.idpId,s=e[o]||{},a=De(s),d=Oe(s);return{...r.payload,email:r.payload.email?.toLowerCase(),idpId:o,teams:Array.from(new Set([...K(r.payload.teams||[],d),..."defaultTeams"in s&&s.defaultTeams||[],...K("teamsClaimName"in s&&r.payload[a||""]||[],d),ae])),name:Me(r.payload),isAuthenticated:!0,idpAccessToken:re(r.payload.idp_access_token,y)||t[_.IDP_ACCESS_TOKEN],federatedAccessToken:t[_.FEDERATED_ACCESS_TOKEN],federatedIdToken:t[_.FEDERATED_ID_TOKEN],authCookie:n}}catch(r){r instanceof le||ce.error("Malformed JWT token: %s",r.message)}return{}}function Me(e){return(e.firstName&&e.lastName?`${e.firstName} ${e.lastName}`:e.name||e.given_name||e.firstName||e.lastName)||e.email}function Oe(e){switch(e.type){case u.SAML2:return e.teamsAttributeMap;case u.OIDC:return e.teamsClaimMap;default:return}}function De(e){switch(e.type){case u.SAML2:return e.teamsAttributeName??b;case u.OIDC:return e.teamsClaimName;default:return b}}function c(e,t){return G.select(t,e)||[]}export{dt as buildLoginUrl,Se as buildOidcLoginUrl,st as buildOidcLogoutUrl,ke as buildSAML2LoginUrl,at as createMcpAuthorizationCode,ct as createMcpRefreshToken,lt as createMcpSessionResource,mt as decodeSamlResponse,Le as discoverJwks,Ie as encodeSAML2,St as extractUserClaims,nt as getAuthProviderLoginParams,ye as getOidcLoginParams,q as getOidcMetadata,ht as getRedoclyTokenPayload,we as getSaml2LoginParams,At as getUserParamsFromCookies,Me as getUsernameFromPayload,$ as isOidcProviderConfig,yt as isRedoclySso,he as isSaml2ProviderConfig,rt as oidcExchangeCodeForToken,A as oidcJwksCache,E as oidcMetadataCache,ot as oidcRefreshTokenGrant,pt as parseOidcState,Ae as parsePreviewBranch,ft as parseSamlResponse,F as rewritePreviewAuthRedirectUri,it as verifyMcpAuthorizationCode,ut as verifyMcpRefreshToken,wt as verifySAMLResponse};
@@ -1 +1 @@
1
- import{logger as n}from"../tools/notifiers/logger.js";import{envConfig as o}from"../config/env-config.js";import{runApiRoutesWorker as m}from"../api-routes/run-api-routes-worker.js";import{MCP_DOCS_SERVER_HANDLER_ID as i}from"../plugins/mcp/index.js";import{handleMcpRequest as u}from"../plugins/mcp/handlers/handle-mcp-request.js";async function l(r,s,a){try{const e=n.startTiming(),t=r.requestHandlerId===i?await u(r,s,a):await m(r,s,a);return n.infoTime(e,`API request handled "${new URL(s.req.url).pathname}" with status "${t.status}" and content type "${t.headers?.get("content-type")}"`),t.headers.set("X-Source","REALM_API_FUNCTION"),t}catch(e){return n.error(`[${r.requestHandlerId}] ${e.stack}`),e.name==="RequestBodySizeLimitError"?s.json({message:e.message},{status:413}):e.name==="ResponseSizeLimitError"?s.json({message:e.message},{status:500}):e.name==="MemoryUsageLimitError"?s.json({message:e.message},{status:502}):e.name==="TimeoutExceededError"?s.json({message:e.message},{status:504}):o.isDevelopMode?s.json({message:e.message},{status:500}):s.json({message:"Internal server error"},{status:500})}}export{l as handleApiRouteRequest};
1
+ import{logger as n}from"../tools/notifiers/logger.js";import{envConfig as o}from"../config/env-config.js";import{runApiRoutesWorker as m}from"../api-routes/run-api-routes-worker.js";import{MCP_CREDENTIALS_HANDLER_ID as i,MCP_DOCS_SERVER_HANDLER_ID as u}from"../plugins/mcp/index.js";import{handleMcpRequest as d}from"../plugins/mcp/handlers/handle-mcp-request.js";async function l(r,s,a){try{const e=n.startTiming(),t=r.requestHandlerId===u||r.requestHandlerId===i?await d(r,s,a):await m(r,s,a);return n.infoTime(e,`API request handled "${new URL(s.req.url).pathname}" with status "${t.status}" and content type "${t.headers?.get("content-type")}"`),t.headers.set("X-Source","REALM_API_FUNCTION"),t}catch(e){return n.error(`[${r.requestHandlerId}] ${e.stack}`),e.name==="RequestBodySizeLimitError"?s.json({message:e.message},{status:413}):e.name==="ResponseSizeLimitError"?s.json({message:e.message},{status:500}):e.name==="MemoryUsageLimitError"?s.json({message:e.message},{status:502}):e.name==="TimeoutExceededError"?s.json({message:e.message},{status:504}):o.isDevelopMode?s.json({message:e.message},{status:500}):s.json({message:"Internal server error"},{status:500})}}export{l as handleApiRouteRequest};
@@ -1 +1 @@
1
- import{TrieRouter as E}from"hono/router/trie-router";import{REDOCLY_ROUTE_RBAC as a}from"@redocly/config";import{withPathPrefix as _}from"@redocly/theme/core/utils";import{CACHE_CONTROL_NO_STORE_HEADER_VALUE as L}from"../../../constants/common.js";import{canAccessResource as O}from"../../../utils/rbac.js";import{handleUnauthorizedApiRequest as U}from"../../utils.js";import{handleApiRouteRequest as q}from"../../handle-api-route-request.js";import{sortApiFunctionRoutes as w}from"../../utils/sort-api-function-routes.js";function u(t){return t.headers.set("Cache-Control",L),t}function z(t,o){t.all("*",async(e,m)=>{const{method:h,path:r}=e.req,p=o.getAllApiRoutes(),R=w(p),i=new E;for(const c of R){const g=c.httpMethod?.toUpperCase()||"ALL",C=_(c.slug);i.add(g,C,c)}const s=i.match(h.toUpperCase(),r);if(!s||s[0].length===0)return m();const f=s[0],[n]=f[0],{isAuthenticated:l,claims:{email:A},teams:d}=e.get("auth");return O({...n,slug:r,[a]:{...n[a],slug:r}},{isAuthenticated:l,email:A,teams:d},o.config.access?.rbac,o.config.access?.requiresLogin)?u(await q(n,e,o)):u(U(e))})}export{z as installApiRoutes};
1
+ import{TrieRouter as _}from"hono/router/trie-router";import{REDOCLY_ROUTE_RBAC as u}from"@redocly/config";import{withPathPrefix as L,withoutPathPrefix as O}from"@redocly/theme/core/utils";import{CACHE_CONTROL_NO_STORE_HEADER_VALUE as w}from"../../../constants/common.js";import{canAccessResource as P}from"../../../utils/rbac.js";import{handleUnauthorizedApiRequest as U}from"../../utils.js";import{handleApiRouteRequest as q}from"../../handle-api-route-request.js";import{sortApiFunctionRoutes as T}from"../../utils/sort-api-function-routes.js";function h(t){return t.headers.set("Cache-Control",w),t}function F(t,o){t.all("*",async(e,m)=>{const{method:p,path:c}=e.req,R=o.getAllApiRoutes(),f=T(R),i=new _;for(const n of f){const C=n.httpMethod?.toUpperCase()||"ALL",E=L(n.slug);i.add(C,E,n)}const r=i.match(p.toUpperCase(),c);if(!r||r[0].length===0)return m();const l=r[0],[s]=l[0],{isAuthenticated:A,claims:{email:d},teams:g}=e.get("auth"),a=O(c);return P({...s,slug:a,[u]:{...s[u],slug:a}},{isAuthenticated:A,email:d,teams:g},o.config.access?.rbac,o.config.access?.requiresLogin)?h(await q(s,e,o)):h(U(e))})}export{F as installApiRoutes};