@redocly/reef 0.132.0-next.0 → 0.132.0-next.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (121) hide show
  1. package/CHANGELOG.md +62 -0
  2. package/dist/client/App.js +1 -1
  3. package/dist/client/TestProvider.js +1 -1
  4. package/dist/client/app/hooks/catalog/useCatalogSort.d.ts +3 -4
  5. package/dist/client/app/hooks/catalog/useFetchCatalogEntities.js +1 -1
  6. package/dist/client/app/hooks/catalog/useFetchCatalogEntitiesRelations.js +1 -1
  7. package/dist/client/app/hooks/index.d.ts +1 -0
  8. package/dist/client/app/hooks/index.js +1 -1
  9. package/dist/client/app/hooks/markdown/useMarkdocRenderer.d.ts +3 -0
  10. package/dist/client/app/hooks/markdown/useMarkdocRenderer.js +1 -0
  11. package/dist/client/app/hooks/useBanner.d.ts +3 -5
  12. package/dist/client/app/hooks/useBanner.js +1 -1
  13. package/dist/client/app/hooks/utils/match-banner-target.d.ts +2 -2
  14. package/dist/client/app/hooks/utils/match-banner-target.js +1 -1
  15. package/dist/client/app/l10n/hooks/useTranslate.js +1 -1
  16. package/dist/client/app/markdoc/custom-components/ExcalidrawRenderer.d.ts +8 -0
  17. package/dist/client/app/markdoc/custom-components/ExcalidrawRenderer.js +14 -0
  18. package/dist/client/app/markdoc/custom-components/index.d.ts +1 -0
  19. package/dist/client/app/markdoc/custom-components/index.js +1 -1
  20. package/dist/client/app/utils/loadAndNavigate.js +1 -1
  21. package/dist/client/app/utils/scroll-to-anchor.d.ts +3 -0
  22. package/dist/client/app/utils/scroll-to-anchor.js +1 -0
  23. package/dist/client/providers/theme/ThemeDataProvider.js +1 -1
  24. package/dist/constants/common.js +1 -1
  25. package/dist/markdoc/nodes/fence/index.js +1 -1
  26. package/dist/markdoc/tags/excalidraw.d.ts +3 -0
  27. package/dist/markdoc/tags/excalidraw.js +1 -0
  28. package/dist/markdoc/tags/index.d.ts +4 -0
  29. package/dist/markdoc/tags/index.js +1 -1
  30. package/dist/server/config/env-schema.d.ts +3 -0
  31. package/dist/server/config/env-schemas/auth.d.ts +3 -0
  32. package/dist/server/config/env-schemas/auth.js +1 -1
  33. package/dist/server/fs/fast-mtime.js +3 -3
  34. package/dist/server/plugins/api-functions/helpers/parse-route-fs-path-for-hono.js +1 -1
  35. package/dist/server/plugins/api-functions/index.js +1 -1
  36. package/dist/server/plugins/arazzo-docs/index.js +1 -1
  37. package/dist/server/plugins/asyncapi-docs/get-server-props.js +1 -1
  38. package/dist/server/plugins/asyncapi-docs/index.js +1 -1
  39. package/dist/server/plugins/asyncapi-docs/search/get-ai-search-documents.js +3 -3
  40. package/dist/server/plugins/catalog-entities/database/mappers/create-bff-related-entity.js +1 -1
  41. package/dist/server/plugins/catalog-entities/database/mappers/field-transformations.d.ts +2 -2
  42. package/dist/server/plugins/catalog-entities/database/mappers/field-transformations.js +1 -1
  43. package/dist/server/plugins/catalog-entities/database/repositories/utils/create-merged-entity-fields-for-select.d.ts +1 -0
  44. package/dist/server/plugins/catalog-entities/database/repositories/utils/create-merged-entity-fields-for-select.js +8 -8
  45. package/dist/server/plugins/catalog-entities/database/repositories/utils.d.ts +4 -0
  46. package/dist/server/plugins/catalog-entities/database/repositories/utils.js +1 -1
  47. package/dist/server/plugins/catalog-entities/extensions/extractors/api-description/arazzo-entities-extractor.js +1 -1
  48. package/dist/server/plugins/catalog-entities/extensions/extractors/api-description/asyncapi-entities-extractor.js +1 -1
  49. package/dist/server/plugins/catalog-entities/extensions/extractors/api-description/base.d.ts +13 -1
  50. package/dist/server/plugins/catalog-entities/extensions/extractors/api-description/base.js +1 -1
  51. package/dist/server/plugins/catalog-entities/extensions/extractors/api-description/graphql-entities-extractor.js +2 -2
  52. package/dist/server/plugins/catalog-entities/extensions/extractors/api-description/openapi-entities-extractor.js +1 -1
  53. package/dist/server/plugins/catalog-entities/get-server-props.js +1 -1
  54. package/dist/server/plugins/catalog-entities/plugin.js +1 -1
  55. package/dist/server/plugins/catalog-entities/schemas/database-schemas.d.ts +6 -6
  56. package/dist/server/plugins/catalog-entities/schemas/database-schemas.js +1 -1
  57. package/dist/server/plugins/config-parser/index.js +1 -1
  58. package/dist/server/plugins/config-parser/loaders/redocly-config-loader.js +1 -1
  59. package/dist/server/plugins/config-parser/loaders/utils/read-and-validate-config.d.ts +1 -0
  60. package/dist/server/plugins/config-parser/loaders/utils/read-and-validate-config.js +1 -1
  61. package/dist/server/plugins/default-theme/index.js +1 -1
  62. package/dist/server/plugins/dev-onboarding/index.js +1 -1
  63. package/dist/server/plugins/enforce-login/index.d.ts +3 -0
  64. package/dist/server/plugins/enforce-login/index.js +1 -0
  65. package/dist/server/plugins/graphql-docs/spec-download.api.js +1 -1
  66. package/dist/server/plugins/lifecycle.js +2 -2
  67. package/dist/server/plugins/markdown/compiler.d.ts +1 -1
  68. package/dist/server/plugins/markdown/compiler.js +1 -1
  69. package/dist/server/plugins/markdown/get-server-props.js +1 -1
  70. package/dist/server/plugins/markdown/index.js +1 -1
  71. package/dist/server/plugins/markdown/markdoc/partials.js +1 -1
  72. package/dist/server/plugins/markdown/markdown-static-data-loader.js +1 -1
  73. package/dist/server/plugins/markdown/search/get-ai-search-documents.js +10 -10
  74. package/dist/server/plugins/mcp/handlers/docs-mcp-handler.js +1 -1
  75. package/dist/server/plugins/openapi-docs/get-server-props.js +1 -1
  76. package/dist/server/plugins/openapi-docs/index.js +1 -1
  77. package/dist/server/plugins/openapi-docs/load-definition.js +3 -3
  78. package/dist/server/plugins/openapi-docs/search/get-ai-search-documents.js +32 -32
  79. package/dist/server/plugins/openapi-docs/spec-download.api.js +1 -1
  80. package/dist/server/plugins/scorecard-classic/compute-scorecard.js +4 -4
  81. package/dist/server/plugins/scorecard-classic/loaders/scorecard-config.js +1 -1
  82. package/dist/server/plugins/scorecard-classic/loaders/scorecard.js +1 -1
  83. package/dist/server/plugins/search/ai-indexer/prepare-semantic-documents.js +1 -1
  84. package/dist/server/plugins/search/documents/search-documents.js +1 -1
  85. package/dist/server/plugins/search/engines/flexsearch/search-index.js +1 -1
  86. package/dist/server/plugins/search/index.js +1 -1
  87. package/dist/server/plugins/search/llmstxt/index.d.ts +0 -1
  88. package/dist/server/plugins/search/llmstxt/index.js +4 -4
  89. package/dist/server/plugins/sso/index.js +1 -1
  90. package/dist/server/plugins/utils.d.ts +4 -0
  91. package/dist/server/plugins/utils.js +1 -1
  92. package/dist/server/ssr/index.js +1 -1
  93. package/dist/server/store.d.ts +2 -3
  94. package/dist/server/store.js +1 -1
  95. package/dist/server/tools/notifiers/terminal-manager.js +5 -5
  96. package/dist/server/types/plugins/common.d.ts +4 -4
  97. package/dist/server/types/plugins/markdown.d.ts +7 -1
  98. package/dist/server/utils/llmstxt/get-llms-txt-md-path-by-slug.d.ts +19 -0
  99. package/dist/server/utils/llmstxt/get-llms-txt-md-path-by-slug.js +1 -0
  100. package/dist/server/utils/rbac/is-rbac-scope-items.d.ts +3 -0
  101. package/dist/server/utils/rbac/is-rbac-scope-items.js +1 -0
  102. package/dist/server/utils/rbac.js +1 -1
  103. package/dist/server/utils/search/highlight-text-for-search.d.ts +2 -0
  104. package/dist/server/utils/search/highlight-text-for-search.js +1 -0
  105. package/dist/server/web-server/routes/api-routes/api-routes.js +1 -1
  106. package/dist/server/web-server/routes/app-data.js +1 -1
  107. package/dist/server/web-server/routes/ask-ai.js +1 -1
  108. package/dist/server/web-server/routes/auth.d.ts +2 -1
  109. package/dist/server/web-server/routes/auth.js +1 -1
  110. package/dist/server/web-server/routes/catalog/bff-catalog-related-entities.js +1 -1
  111. package/dist/server/web-server/routes/catalog/bff-catalog.js +1 -1
  112. package/dist/server/web-server/routes/catalog/helpers/has-access-to-entity.js +1 -1
  113. package/dist/server/web-server/routes/dynamic-route.js +1 -1
  114. package/dist/server/web-server/routes/feedback.js +1 -1
  115. package/dist/server/web-server/routes/helpers/get-rbac-restrictions-data-for-catalog.js +1 -1
  116. package/dist/server/web-server/routes/page-data.js +1 -1
  117. package/dist/server/web-server/routes/search.js +1 -1
  118. package/dist/server/web-server/routes/static-content.js +1 -1
  119. package/package.json +11 -10
  120. package/dist/server/web-server/routes/helpers/get-md-asset-pathname.d.ts +0 -2
  121. package/dist/server/web-server/routes/helpers/get-md-asset-pathname.js +0 -1
@@ -1 +1 @@
1
- import w from"node:path";import{reporter as x}from"../../../tools/notifiers/reporter.js";import{lintDefinition as h}from"../lint.js";import{ExternalResolver as b}from"../../../fs/utils/external-ref-resolver.js";const v="Non-conformant";async function O(o,e){const{data:{levelsConfig:s,configs:n,targets:t}}=await e.cache.load("","scorecard-config"),a={};let i=v,f=!1;const c=await e.fs.read(o),{data:l}=await e.cache.load(o,"yaml"),m=new b(e.fs);let g={};if(t.length){const r=await e.getConfig(w.posix.dirname(o)),d=l?.info?.["x-metadata"],p={title:l.info.title,version:l.info.version,...d,...r.metadata};g=(await k(t,p))?.configs||{}}for(const r of s){const d=await h({parsed:l,content:c,relativePath:o},g[r.name]||n[r.name],e,m);a[r.name]=d,d.errors===0&&!f?i=r.name:f=!0}let u=s.findIndex(r=>r.name===i);return{levels:a,scorecardLevel:i,scorecardLevelIdx:u+1}}async function k(o,e){if(o)for(const s of o){let n=!0;for(const[t,a]of Object.entries(s.where?.metadata||{}))if(String(a).match(/^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}:\d{2}Z)?\/(\d{4}-\d{2}-\d{2})?$/)){if(!e[t]){n=!1;break}const[i,f]=a.split("/"),c=new Date(e[t]);if(c<new Date(i)||f&&c>new Date(f)){n=!1;break}}else if(String(a).match(/^\/.*\//)){if(!e[t]){n=!1;break}try{if(!new RegExp(a.slice(1,-1)).test(e[t])){n=!1;break}}catch{await x.panicOnBuild(`Invalid regex in scorecard target "${t}": ${a}`),n=!1;break}}else if(e[t]!==a){n=!1;break}if(n)return s}}export{k as getTarget,O as scorecardLoader};
1
+ import w from"node:path";import{regexFromString as h}from"@redocly/openapi-core";import{reporter as x}from"../../../tools/notifiers/reporter.js";import{lintDefinition as C}from"../lint.js";import{ExternalResolver as N}from"../../../fs/utils/external-ref-resolver.js";const I="Non-conformant";async function F(t,e){const{data:{levelsConfig:n,configs:i,targets:r}}=await e.cache.load("","scorecard-config"),o={};let s=I,d=!1;const m=await e.fs.read(t),{data:f}=await e.cache.load(t,"yaml"),g=new N(e.fs);let l={};if(r.length){const a=await e.getConfig(w.posix.dirname(t)),c=f?.info?.["x-metadata"],p={title:f.info.title,version:f.info.version,...c,...a.metadata};l=(await M(r,p))?.configs||{}}for(const a of n){const c=await C({parsed:f,content:m,relativePath:t},l[a.name]||i[a.name],e,g);o[a.name]=c,c.errors===0&&!d?s=a.name:d=!0}let u=n.findIndex(a=>a.name===s);return{levels:o,scorecardLevel:s,scorecardLevelIdx:u+1}}async function M(t,e){if(t)for(const n of t){const i=Object.entries(n.where?.metadata||{});let r=!0;for(const[o,s]of i)if(!await O(o,s,e)){r=!1;break}if(r)return n}}async function O(t,e,n){if(e.match(/^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}:\d{2}Z)?\/(\d{4}-\d{2}-\d{2})?$/)){if(!n[t])return!1;const[i,r]=e.split("/"),o=new Date(n[t]);return isNaN(o.getTime())?!1:!(o<new Date(i)||r&&o>new Date(r))}else if(e.match(/^\/.*\//)){if(!n[t])return!1;try{return h(e).test(n[t])}catch{return await x.panicOnContentError(`Invalid regex in scorecard target "${t}": ${e}`),!1}}return n[t]===e}export{M as getTarget,F as scorecardLoader};
@@ -1 +1 @@
1
- import p from"node:path";import{existsSync as v}from"node:fs";import{writeFile as R,access as N,rm as X,constants as $}from"fs/promises";import{REDOCLY_ROUTE_RBAC as A,REDOCLY_TEAMS_RBAC as S}from"@redocly/config";import b from"picomatch";import{DEFAULT_LOCALE_PLACEHOLDER as _}from"../../../../constants/common.js";import{AI_INDEX_EXPORT_FOLDER as j}from"../../../constants/plugins/search.js";import{LLMS_TXT_FILE_NAME as k}from"../../../constants/common.js";import{envConfig as B}from"../../../config/env-config.js";import{logger as a}from"../../../tools/notifiers/logger.js";import{shaHexShort as G}from"../../../utils/crypto/sha-hex-short.js";import{promiseMapLimit as C}from"../../../utils/async/promise-map-limit.js";import{validateLLMsTxtConfig as H,generateLLMsTxt as U,getLLMsTxtMdSlug as Y}from"../llmstxt/index.js";import{ensureDir as h}from"../../../utils/fs.js";import{isResourcePubliclyAccessible as J,extractTeamsFromScopeItems as K,getRbacTeamsListForResource as V}from"../../../utils/rbac.js";const M=20,d="llms.txt:";async function pt(t,i,{embeddingsEnabled:e,llmstxtEnabled:r}){const n=p.join(t.outdir,k);if(!r){try{await N(n,$.W_OK),await X(n)}catch{}if(!e)return}e&&a.info("Preparing semantic documents..."),r&&a.info(`${d} Generating llms.txt files...`);const L=a.startTiming(),c=a.startTiming(),f=t.getGlobalConfig("seo"),m=f?.llmstxt,T=p.resolve(t.outdir,j),u=t.getConfig(),P=u.rbac??{},w=t.getAllRoutes(),F=u?.l10n?.defaultLocale||u?.i18n?.defaultLocale||_,O=(m?.excludeFiles||[]).map(o=>b(o)),x=[];if(await C(w,M,async o=>{if(o.excludeFromSearch)return;const y=await W(o,t),D=await q(o,y,i,t);if(D){if(r)for(const s of await D.getLLMsTxts()){if(O.some(l=>l(s.fsPath)))continue;const g=p.join(t.outdir,Y(s.slug));h(g),await R(g,s.content),s.includeInLLMsTxt&&J(o,u)&&x.push(s)}if(e&&B.isBuildMode){const s=await D.getSearchDocuments();if(!s.length)return;const g=z(o,P),l=o.versions?.find(({active:I})=>I),E=l&&{folder:l.folderId,label:l.label,default:l.default};await Q(s,o.fsPath,g,T,F,E)}}}),e&&a.infoTime(c,"Semantic search documents prepared"),x.length)try{H(m);const o=await U(x,m,{title:f?.title,description:f?.description},i);h(n),await R(n,o),a.infoTime(L,`${d} files generated`)}catch(o){a.error(`${d} Failed to generate llms.txt file. ${o.message}`)}}async function W(t,i){return t.getStaticData?t.getStaticData(t,{...i,contentDir:i.contentDir,parseMarkdoc:(e,r,n)=>i.parseMarkdoc(e,r,n)}):{}}async function q(t,i,e,r){if(t.getAiDocumentsStore)return t.getAiDocumentsStore(t,{...i,[S]:t[S],[A]:t[A]},e,r)}function z(t,i){const e=K(t?.[S]);return e?.length?e:V(t,i)}async function Q(t,i,e,r,n,L){await C(t,M,async c=>{const f=`${G(i+c.content)}.json`,m=h(p.join(r,f)),T=c.locale===_?n:c.locale;v(m)||await R(m,JSON.stringify({...c,rbacTeams:e||[],version:L,locale:T}),"utf-8")})}export{pt as prepareSemanticDocuments};
1
+ import p from"node:path";import{existsSync as v}from"node:fs";import{writeFile as h,access as N,rm as X,constants as $}from"fs/promises";import{REDOCLY_ROUTE_RBAC as A,REDOCLY_TEAMS_RBAC as S}from"@redocly/config";import b from"picomatch";import{DEFAULT_LOCALE_PLACEHOLDER as _}from"../../../../constants/common.js";import{AI_INDEX_EXPORT_FOLDER as j}from"../../../constants/plugins/search.js";import{LLMS_TXT_FILE_NAME as B}from"../../../constants/common.js";import{envConfig as G}from"../../../config/env-config.js";import{logger as n}from"../../../tools/notifiers/logger.js";import{shaHexShort as H}from"../../../utils/crypto/sha-hex-short.js";import{promiseMapLimit as P}from"../../../utils/async/promise-map-limit.js";import{getLlmsTxtMdPathBySlug as U}from"../../../utils/llmstxt/get-llms-txt-md-path-by-slug.js";import{validateLLMsTxtConfig as Y,generateLLMsTxt as k}from"../llmstxt/index.js";import{ensureDir as D}from"../../../utils/fs.js";import{isResourcePubliclyAccessible as J,extractTeamsFromScopeItems as K,getRbacTeamsListForResource as V}from"../../../utils/rbac.js";const C=20,d="llms.txt:";async function Lt(t,o,{embeddingsEnabled:i,llmstxtEnabled:s}){const a=p.join(t.outdir,B);if(!s){try{await N(a,$.W_OK),await X(a)}catch{}if(!i)return}i&&n.info("Preparing semantic documents..."),s&&n.info(`${d} Generating llms.txt files...`);const L=n.startTiming(),c=n.startTiming(),f=t.getGlobalConfig("seo"),m=f?.llmstxt,T=p.resolve(t.outdir,j),u=t.getConfig(),w=u.access?.rbac??{},F=t.getAllRoutes(),y=u?.l10n?.defaultLocale||u?.i18n?.defaultLocale||_,M=(m?.excludeFiles||[]).map(e=>b(e)),x=[];if(await P(F,C,async e=>{if(e.excludeFromSearch)return;const O=await W(e,t),R=await q(e,O,o,t);if(R){if(s)for(const r of await R.getLLMsTxts()){if(M.some(l=>l(r.fsPath)))continue;const g=p.join(t.outdir,U(r.slug));D(g),await h(g,r.content),r.includeInLLMsTxt&&J(e,u)&&x.push(r)}if(i&&G.isBuildMode){const r=await R.getSearchDocuments();if(!r.length)return;const g=z(e,w),l=e.versions?.find(({active:I})=>I),E=l&&{folder:l.folderId,label:l.label,default:l.default};await Q(r,e.fsPath,g,T,y,E)}}}),i&&n.infoTime(c,"Semantic search documents prepared"),x.length)try{Y(m);const e=await k(x,m,{title:f?.title,description:f?.description},o);D(a),await h(a,e),n.infoTime(L,`${d} files generated`)}catch(e){n.error(`${d} Failed to generate llms.txt file. ${e.message}`)}}async function W(t,o){return t.getStaticData?t.getStaticData(t,o):{}}async function q(t,o,i,s){if(t.getAiDocumentsStore)return t.getAiDocumentsStore(t,{...o,[S]:t[S],[A]:t[A]},i,s)}function z(t,o){const i=K(t?.[S]);return i?.length?i:V(t,o)}async function Q(t,o,i,s,a,L){await P(t,C,async c=>{const f=`${H(o+c.content)}.json`,m=D(p.join(s,f)),T=c.locale===_?a:c.locale;v(m)||await h(m,JSON.stringify({...c,rbacTeams:i||[],version:L,locale:T}),"utf-8")})}export{Lt as prepareSemanticDocuments};
@@ -1 +1 @@
1
- import{REDOCLY_ROUTE_RBAC as E,REDOCLY_TEAMS_RBAC as g}from"@redocly/config";import{existsSync as B}from"fs";import{rm as M}from"node:fs/promises";import $ from"node:path";import{DEFAULT_LOCALE_PLACEHOLDER as y}from"../../../../constants/common.js";import{SEARCH_DATA_EXPORT_FOLDER as S}from"../../../constants/plugins/search.js";import{envConfig as m}from"../../../config/env-config.js";import{logger as n}from"../../../tools/notifiers/logger.js";import{extractTeamsFromScopeItems as H,getRbacTeamsListForResource as P}from"../../../utils/index.js";import{getSearchDocumentGroup as U}from"../utils.js";import{telemetry as V}from"../../../../cli/telemetry/index.js";import{telemetryTraceStep as A}from"../../../../cli/telemetry/helpers/trace-step.js";async function Q(R,r,d){await A("build.plugin.search.prepare_search_documents",async()=>{n.info("Preparing search documents and create indexes...");const u=m.SEARCH_DEV_DEBUG?$.join(r.contentDir,"..","public","client"):r.outdir;(m.SEARCH_DEV_DEBUG||m.isBuildMode)&&B(`${u}/${S}`)&&await M(`${u}/${S}`,{recursive:!0});const C=n.startTiming(),b=r.getConfig().rbac,v=[y,...R.localeFolders.map(a=>a.toLowerCase())];for(const a of v)await A("build.plugin.search.prepare_search_documents.locale",async c=>{const F=r.getAllRoutesForLocale(a);let h=0,T=0;for(const t of F){if(h++,t.excludeFromSearch)continue;const p=new Map,{product:l}=t,L=await t.getStaticData?.(t,{...r,contentDir:r.contentDir,parseMarkdoc:(s,e,f)=>r.parseMarkdoc(s,e,f)})||{},i=await t.getSearchDocuments?.(t,{...L,[g]:t[g],[E]:t[E]},r),o=t.versions?.find(s=>s.active),w=P(t,b??{});if(i){if(i&&i.length){T+=i.length;for(const s in i){let e=i[s];const f=H(e?.[g]),_=f?.length?f:w,x=e.tags||[];e={...e,...o&&{version:o.version,isDefaultVersion:o.default,versionFolderId:o.folderId},...l&&{product:l},rbacTeams:_,tags:[...x,..._,...o?o.default?["v:default"]:[`v:${o.folderId}:${o.version}`]:["v:default"],...l?[`p:${l.name}`]:[]],url:e.url&&(e.path&&e.path.length>1?e.url:e.url.split("#")[0])};const D=U(e.facets);if(D){const O=p.get(D)??[];p.set(D,[...O,e])}}}for(const[s,e]of p)await d.addDocuments(e,{locale:a,group:s,outDir:u})}}c?.setAttribute("locale",a),c?.setAttribute("totalDocuments",h),c?.setAttribute("totalSearchDocuments",T)});if(d.cleanupFacetValues(r),n.infoTime(C,"Search indexes created"),m.SEARCH_DEV_DEBUG||m.isBuildMode){n.info("Writing out search data...");const a=n.startTiming();await d.export(u);const c=n.infoTime(a,"Search data written");c&&V.sendTimingPerformedMessage(c)}})}export{Q as prepareSearchDocuments};
1
+ import{REDOCLY_ROUTE_RBAC as E,REDOCLY_TEAMS_RBAC as D}from"@redocly/config";import{existsSync as B}from"fs";import{rm as $}from"node:fs/promises";import y from"node:path";import{DEFAULT_LOCALE_PLACEHOLDER as H}from"../../../../constants/common.js";import{SEARCH_DATA_EXPORT_FOLDER as S}from"../../../constants/plugins/search.js";import{envConfig as m}from"../../../config/env-config.js";import{logger as i}from"../../../tools/notifiers/logger.js";import{extractTeamsFromScopeItems as M,getRbacTeamsListForResource as P}from"../../../utils/index.js";import{getSearchDocumentGroup as U}from"../utils.js";import{telemetry as V}from"../../../../cli/telemetry/index.js";import{telemetryTraceStep as A}from"../../../../cli/telemetry/helpers/trace-step.js";async function Q(R,r,f){await A("build.plugin.search.prepare_search_documents",async()=>{i.info("Preparing search documents and create indexes...");const u=m.SEARCH_DEV_DEBUG?y.join(r.contentDir,"..","public","client"):r.outdir;(m.SEARCH_DEV_DEBUG||m.isBuildMode)&&B(`${u}/${S}`)&&await $(`${u}/${S}`,{recursive:!0});const C=i.startTiming(),b=r.getConfig().access?.rbac,v=[H,...R.localeFolders.map(a=>a.toLowerCase())];for(const a of v)await A("build.plugin.search.prepare_search_documents.locale",async s=>{const F=r.getAllRoutesForLocale(a);let g=0,h=0;for(const t of F){if(g++,t.excludeFromSearch)continue;const d=new Map,{product:l}=t,L=await t.getStaticData?.(t,r)||{},c=await t.getSearchDocuments?.(t,{...L,[D]:t[D],[E]:t[E]},r),o=t.versions?.find(n=>n.active),w=P(t,b??{});if(c){if(c&&c.length){h+=c.length;for(const n in c){let e=c[n];const T=M(e?.[D]),_=T?.length?T:w,x=e.tags||[];e={...e,...o&&{version:o.version,isDefaultVersion:o.default,versionFolderId:o.folderId},...l&&{product:l},rbacTeams:_,tags:[...x,..._,...o?o.default?["v:default"]:[`v:${o.folderId}:${o.version}`]:["v:default"],...l?[`p:${l.name}`]:[]],url:e.url&&(e.path&&e.path.length>1?e.url:e.url.split("#")[0])};const p=U(e.facets);if(p){const O=d.get(p)??[];d.set(p,[...O,e])}}}for(const[n,e]of d)await f.addDocuments(e,{locale:a,group:n,outDir:u})}}s?.setAttribute("locale",a),s?.setAttribute("totalDocuments",g),s?.setAttribute("totalSearchDocuments",h)});if(f.cleanupFacetValues(r),i.infoTime(C,"Search indexes created"),m.SEARCH_DEV_DEBUG||m.isBuildMode){i.info("Writing out search data...");const a=i.startTiming();await f.export(u);const s=i.infoTime(a,"Search data written");s&&V.sendTimingPerformedMessage(s)}})}export{Q as prepareSearchDocuments};
@@ -1 +1 @@
1
- import L from"flexsearch";import{REDOCLY_TEAMS_RBAC as g}from"@redocly/config";import{DISABLE_DEEP_LINK_IF_FIELDS_EXIST as w,HIGHLIGHTED_TEXT_MAX_LENGTH as S,SEARCH_LIMIT as I}from"../../../../constants/plugins/search.js";import{telemetryTraceStep as E}from"../../../../telemetry/helpers/trace-step.js";class T{#e;#t=new Map;#r=1;id;constructor(e,t){this.id=e,this.#e=new L.Document(t)}get documents(){return this.#t.entries()}get documentsCount(){return this.#r}clearDocuments(){this.#t.clear()}async export(e){await this.#e.export(e)}async import(e){const{documents:t,index:r}=e;this.#t.clear();for(const[i,s]of t)this.#t.set(i,s);for(const[i,s]of Object.entries(r))await this.#e.import(i,s)}add(e){e.tags||(e.tags=[]),this.#t.set(this.#r,e[g]?e:{...e,[g]:void 0}),this.#e.add(this.#r,e),this.#r++}async search(e){return await E("search",async t=>{const{query:r,offset:i,auth:s,product:n,versions:a}=e,o=[],c=s.teams,h={limit:I,offset:i};let d=new Map,p=await this.#e.searchAsync(r,{...h,tag:c});if(n){const l=await this.#e.searchAsync(r,{...h,tag:n});p=this.#n(p,l),t?.setAttribute("product",n)}if(a&&a.length){const l=await this.#e.searchAsync(r,{...h,tag:a});p=this.#n(p,l),t?.setAttribute("versions",a.join(","))}for(const l of p)for(const u of l.result){const f=d.get(u)?.fields||[];d.set(u,{fields:l.field?[...f,l.field]:[...f]})}let m=0;for(const[l,u]of d.entries()){if(m>=I)break;const f=this.#t.get(l);f&&!this.#c(f,a)&&(o.push({document:this.#o(f,r,u.fields),highlight:this.#a(f,r,u.fields)}),m++)}return{documents:{[this.id]:o},facets:{}}})}#o(e,t,r){return this.#h(e,t,r)}#a(e,t,r){const i={};let s=!1;for(const n of r)if(n==="path")i.path=e.path?e.path.map(a=>this.#s(t,a)):[];else if(n.includes("parameters")){if(!s){const a=n.split(":")[1],o=e.parameters?.find(c=>{const h=c[a];return this.#i(t,typeof h=="boolean"?h.toString():h)});o&&(i.parameters=[{name:this.#s(t,o.name),description:this.#s(t,o.description),place:this.#s(t,o.place),path:o.path?o.path.map(c=>this.#s(t,c)):[]}],s=!0)}}else i[n]=this.#s(t,e[n]);return i}#s(e,t){const r=e.split(/\s+/g),i=n=>n.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),s=r.reduce((n,a)=>a?n?.replace?.(new RegExp(`(^|\\s)${i(a)}`,"i"),o=>`<mark>${o}</mark>`):n,t);if(!s)return t||"";if(s.length<S)return s;{const n=s.indexOf("<mark>"),a=s.indexOf("</mark>")+7,o=S/2+e.length/2,c=n<o,h=a+o<s.length,d=s.substring(c?0:n-o,h?a+o:s.length);return`${c?"":"..."}${d}${h?"...":""}`}}#i=(e,t)=>{if(t){const r=e.split(/\s+/g);return Array.isArray(t)?t.some(i=>r.some(s=>i.toLowerCase().includes(s.toLowerCase()))):r.some(i=>t.toLowerCase().includes(i.toLowerCase()))}else return!1};#n(e,t){const r=[];for(const i of e){const s=[];for(const n of t)for(const a of i.result){const o=n.result.find(c=>c===a);o&&s.push(o)}s.length&&r.push({result:s,field:i.field})}return r}#c(e,t){return!!(t&&t.length&&e.isDefaultVersion&&e.versionFolderId&&e.version&&t.some(r=>r.includes(e.versionFolderId??""))&&!t.some(r=>r.includes(e.version??"")))}#h(e,t,r){for(const s of w)if(r.some(n=>n===s))return e;let i;for(const s of r)if(s.includes("parameters")){const n=s.split(":")[1],a=e.parameters?.find(o=>{const c=o[n];return this.#i(t,typeof c=="boolean"?c.toString():c)});if(a){i=a.deepLink;break}}if(i){const s=i.split("#")[1];return{...e,url:`${e.url}#${s}`}}return e}}export{T as FlexSearchIndex};
1
+ import I from"flexsearch";import{REDOCLY_TEAMS_RBAC as S}from"@redocly/config";import{DISABLE_DEEP_LINK_IF_FIELDS_EXIST as L,SEARCH_LIMIT as w}from"../../../../constants/plugins/search.js";import{telemetryTraceStep as D}from"../../../../telemetry/helpers/trace-step.js";import{highlightTextForSearch as p}from"../../../../utils/search/highlight-text-for-search.js";class y{#e;#t=new Map;#s=1;id;constructor(e,t){this.id=e,this.#e=new I.Document(t)}get documents(){return this.#t.entries()}get documentsCount(){return this.#s}clearDocuments(){this.#t.clear()}async export(e){await this.#e.export(e)}async import(e){const{documents:t,index:s}=e;this.#t.clear();for(const[r,i]of t)this.#t.set(r,i);for(const[r,i]of Object.entries(s))await this.#e.import(r,i)}add(e){e.tags||(e.tags=[]),this.#t.set(this.#s,e[S]?e:{...e,[S]:void 0}),this.#e.add(this.#s,e),this.#s++}async search(e){return await D("search",async t=>{const{query:s,offset:r,auth:i,product:o,versions:a}=e,n=[],c=i.teams,h={limit:w,offset:r};let m=new Map,u=await this.#e.searchAsync(s,{...h,tag:c});if(o){const l=await this.#e.searchAsync(s,{...h,tag:o});u=this.#i(u,l),t?.setAttribute("product",o)}if(a&&a.length){const l=await this.#e.searchAsync(s,{...h,tag:a});u=this.#i(u,l),t?.setAttribute("versions",a.join(","))}for(const l of u)for(const d of l.result){const f=m.get(d)?.fields||[];m.set(d,{fields:l.field?[...f,l.field]:[...f]})}let g=0;for(const[l,d]of m.entries()){if(g>=w)break;const f=this.#t.get(l);f&&!this.#n(f,a)&&(n.push({document:this.#o(f,s,d.fields),highlight:this.#a(f,s,d.fields)}),g++)}return{documents:{[this.id]:n},facets:{}}})}#o(e,t,s){return this.#c(e,t,s)}#a(e,t,s){const r={};let i=!1;for(const o of s)if(o==="path")r.path=e.path?e.path.map(a=>p(t,a)):[];else if(o.includes("parameters")){if(!i){const a=o.split(":")[1],n=e.parameters?.find(c=>{const h=c[a];return this.#r(t,typeof h=="boolean"?h.toString():h)});n&&(r.parameters=[{name:p(t,n.name),description:p(t,n.description),place:p(t,n.place),path:n.path?n.path.map(c=>p(t,c)):[]}],i=!0)}}else r[o]=p(t,e[o]);return r}#r=(e,t)=>{if(t){const s=e.split(/\s+/g);return Array.isArray(t)?t.some(r=>s.some(i=>r.toLowerCase().includes(i.toLowerCase()))):s.some(r=>t.toLowerCase().includes(r.toLowerCase()))}else return!1};#i(e,t){const s=[];for(const r of e){const i=[];for(const o of t)for(const a of r.result){const n=o.result.find(c=>c===a);n&&i.push(n)}i.length&&s.push({result:i,field:r.field})}return s}#n(e,t){return!!(t&&t.length&&e.isDefaultVersion&&e.versionFolderId&&e.version&&t.some(s=>s.includes(e.versionFolderId??""))&&!t.some(s=>s.includes(e.version??"")))}#c(e,t,s){for(const i of L)if(s.some(o=>o===i))return e;let r;for(const i of s)if(i.includes("parameters")){const o=i.split(":")[1],a=e.parameters?.find(n=>{const c=n[o];return this.#r(t,typeof c=="boolean"?c.toString():c)});if(a){r=a.deepLink;break}}if(r){const i=r.split("#")[1];return{...e,url:`${e.url}#${i}`}}return e}}export{y as FlexSearchIndex};
@@ -1 +1 @@
1
- import{REDOCLY_TEAMS_RBAC as g}from"@redocly/config";import{DEFAULT_SEARCH_ENGINE as c}from"../../constants/plugins/search.js";import{envConfig as o}from"../../config/env-config.js";import{logger as p}from"../../tools/notifiers/logger.js";import{reporter as E}from"../../tools/notifiers/reporter.js";import{prepareSearchDocuments as u}from"./documents/search-documents.js";import{SearchEngine as S}from"./engines/search-engine.js";import{prepareSemanticDocuments as b}from"./ai-indexer/prepare-semantic-documents.js";import{isAiSearchEnabled as D,shouldGenerateEmbeddings as y}from"./utils.js";import{telemetryTraceStep as C}from"../../../cli/telemetry/helpers/trace-step.js";async function H(){let e=!0;return{async afterRoutesCreated(a,i){(o.SEARCH_DEV_REINIT||e)&&await A(a,i),e=!1},id:"search"}}async function A(e,a){await C("build.plugin.search",async i=>{const r=e.getConfig();if(i?.setAttribute("config",JSON.stringify(r.search||{})),r.search?.hide){p.info("Search is disabled in the config, skipping");return}const s=r.search?.engine||c,m=o.isDevelopMode?o.SEARCH_DEV_DEBUG?s:c:s,{l10n:f}=e.getGlobalData(),h=D(r),n=r.rbac?.features?.aiSearch,l=y(r);let t;try{t=new S(m,f)}catch(d){await E.panic(d);return}await t.initIndexSchema(e.getSearchFacets()),e.setSearchEngine(t),e.setGlobalData({searchFeatures:{advanced:{enabled:m!==c&&!r.search?.filters?.hide},ai:{enabled:h,[g]:n&&Object.keys(n).length?n:void 0}}}),await u(a.fs,e,t),await b(e,a,{embeddingsEnabled:l,llmstxtEnabled:r.seo?.llmstxt?.hide!==!0})})}export{H as searchPlugin};
1
+ import{REDOCLY_TEAMS_RBAC as g}from"@redocly/config";import{DEFAULT_SEARCH_ENGINE as c}from"../../constants/plugins/search.js";import{envConfig as s}from"../../config/env-config.js";import{logger as p}from"../../tools/notifiers/logger.js";import{reporter as E}from"../../tools/notifiers/reporter.js";import{prepareSearchDocuments as u}from"./documents/search-documents.js";import{SearchEngine as S}from"./engines/search-engine.js";import{prepareSemanticDocuments as b}from"./ai-indexer/prepare-semantic-documents.js";import{isAiSearchEnabled as D,shouldGenerateEmbeddings as y}from"./utils.js";import{telemetryTraceStep as C}from"../../../cli/telemetry/helpers/trace-step.js";async function H(){let e=!0;return{async afterRoutesCreated(a,i){(s.SEARCH_DEV_REINIT||e)&&await A(a,i),e=!1},id:"search"}}async function A(e,a){await C("build.plugin.search",async i=>{const r=e.getConfig();if(i?.setAttribute("config",JSON.stringify(r.search||{})),r.search?.hide){p.info("Search is disabled in the config, skipping");return}const o=r.search?.engine||c,m=s.isDevelopMode?s.SEARCH_DEV_DEBUG?o:c:o,{l10n:f}=e.getGlobalData(),h=D(r),n=r.access?.rbac?.features?.aiSearch,l=y(r);let t;try{t=new S(m,f)}catch(d){await E.panic(d);return}await t.initIndexSchema(e.getSearchFacets()),e.setSearchEngine(t),e.setGlobalData({searchFeatures:{advanced:{enabled:m!==c&&!r.search?.filters?.hide},ai:{enabled:h,[g]:n&&Object.keys(n).length?n:void 0}}}),await u(a.fs,e,t),await b(e,a,{embeddingsEnabled:l,llmstxtEnabled:r.seo?.llmstxt?.hide!==!0})})}export{H as searchPlugin};
@@ -11,5 +11,4 @@ export declare function llmsTxtLink({ title, description, slug, }: {
11
11
  slug: LLMsTxt['slug'];
12
12
  }): string;
13
13
  export declare function validateLLMsTxtConfig(llmstxtConfig: SeoConfig['llmstxt']): void;
14
- export declare function getLLMsTxtMdSlug(llmstxtSlug: string): string;
15
14
  //# sourceMappingURL=index.d.ts.map
@@ -1,4 +1,4 @@
1
- import a from"picomatch";import{dirname as $,resolve as x}from"node:path";import{access as P,readFile as E,constants as F}from"fs/promises";import{removeTrailingSlash as w}from"../../../../utils/url/remove-trailing-slash.js";import{logger as g}from"../../../tools/notifiers/logger.js";import{withPathPrefix as I}from"@redocly/theme/core/utils";import{envConfig as y}from"../../../config/env-config.js";const l="llms.txt",u="Table of contents";async function M(t,e,n={title:l,description:void 0},o){if(!e)return{title:n.title||l,description:n.description,details:void 0,sections:[{title:u,description:void 0,llmstxts:t}]};const s=e.title||n.title||l,r=e.description||n.description,i=await v(e,o),c=e.sections?.map(d=>{const{title:f,description:h,excludeFiles:m,includeFiles:L}=d,T=p(t,{excludeFiles:m,includeFiles:L});return{title:f,description:h,llmstxts:T}});return{title:s,description:r,details:i,sections:c||[{title:u,description:void 0,llmstxts:p(t,{includeFiles:["**/*"],excludeFiles:[]})}]}}async function v(t,e){const n=await e.getConfig();if(t?.details?.path&&n.configPath)try{const o=e.fs.getFileInfo(n.configPath);if(!o)throw new Error(`Config file ${n.configPath} not found`);const s=x(e.fs.cwd,$(o.relativePath),t.details.path);return await P(s,F.R_OK),E(s,"utf-8")}catch{throw new Error(`${t.details.path} is not accessible`)}if(t?.details?.content)return t.details.content}function p(t,e){const{excludeFiles:n,includeFiles:o}=e,s=n?.map(i=>a(i)),r=o?.map(i=>a(i));return t.filter(i=>s?.some(d=>d(i.fsPath))?!1:r?.some(d=>d(i.fsPath)))}async function j(t,e,n={title:l,description:void 0},o){const s=await M(t,e,n,o),r=[`# ${s.title}
1
+ import d from"picomatch";import{dirname as T,resolve as x}from"node:path";import{access as $,readFile as E,constants as F}from"fs/promises";import{removeTrailingSlash as w}from"../../../../utils/url/remove-trailing-slash.js";import{logger as g}from"../../../tools/notifiers/logger.js";import{withPathPrefix as y}from"@redocly/theme/core/utils";import{envConfig as I}from"../../../config/env-config.js";import{getLlmsTxtMdPathBySlug as v}from"../../../utils/llmstxt/get-llms-txt-md-path-by-slug.js";const a="llms.txt",u="Table of contents";async function M(t,e,n={title:a,description:void 0},o){if(!e)return{title:n.title||a,description:n.description,details:void 0,sections:[{title:u,description:void 0,llmstxts:t}]};const s=e.title||n.title||a,r=e.description||n.description,i=await _(e,o),c=e.sections?.map(l=>{const{title:f,description:h,excludeFiles:m,includeFiles:L}=l,P=p(t,{excludeFiles:m,includeFiles:L});return{title:f,description:h,llmstxts:P}});return{title:s,description:r,details:i,sections:c||[{title:u,description:void 0,llmstxts:p(t,{includeFiles:["**/*"],excludeFiles:[]})}]}}async function _(t,e){const n=await e.getConfig();if(t?.details?.path&&n.configPath)try{const o=e.fs.getFileInfo(n.configPath);if(!o)throw new Error(`Config file ${n.configPath} not found`);const s=x(e.fs.cwd,T(o.relativePath),t.details.path);return await $(s,F.R_OK),E(s,"utf-8")}catch{throw new Error(`${t.details.path} is not accessible`)}if(t?.details?.content)return t.details.content}function p(t,e){const{excludeFiles:n,includeFiles:o}=e,s=n?.map(i=>d(i)),r=o?.map(i=>d(i));return t.filter(i=>s?.some(l=>l(i.fsPath))?!1:r?.some(l=>l(i.fsPath)))}async function j(t,e,n={title:a,description:void 0},o){const s=await M(t,e,n,o),r=[`# ${s.title}
2
2
 
3
3
  `];return s.description&&r.push(`> ${s.description}
4
4
 
@@ -8,6 +8,6 @@ import a from"picomatch";import{dirname as $,resolve as x}from"node:path";import
8
8
  `),i.description?r.push(`${i.description.replace(/\n+$/,"")}
9
9
 
10
10
  `):r.push(`
11
- `),i.llmstxts.forEach(c=>{r.push(` - ${_({title:c.title,description:c.description,slug:D(c.slug)})}`)}),r.push(`
12
- `)}),r.join("")}function _({title:t,description:e,slug:n}){return`[${t}](${w(y.REDOCLY_PUBLIC_URL||"")}${encodeURI(I(n))})${e?`: ${e}`:""}
13
- `}function B(t){if(t?.details?.path&&t?.details?.content)throw new Error('"details.path" and "details.content" are mutually exclusive. Please use only one of them.')}function D(t){return`${t}${t==="/"?"index.html.md":".md"}`}export{j as generateLLMsTxt,D as getLLMsTxtMdSlug,_ as llmsTxtLink,B as validateLLMsTxtConfig};
11
+ `),i.llmstxts.forEach(c=>{r.push(` - ${D({title:c.title,description:c.description,slug:v(c.slug)})}`)}),r.push(`
12
+ `)}),r.join("")}function D({title:t,description:e,slug:n}){return`[${t}](${w(I.REDOCLY_PUBLIC_URL||"")}${encodeURI(y(n))})${e?`: ${e}`:""}
13
+ `}function K(t){if(t?.details?.path&&t?.details?.content)throw new Error('"details.path" and "details.content" are mutually exclusive. Please use only one of them.')}export{j as generateLLMsTxt,D as llmsTxtLink,K as validateLLMsTxtConfig};
@@ -1 +1 @@
1
- import{DEFAULT_SSO_IDP_TITLE as f}from"../../../constants/common.js";import{envConfig as c}from"../../config/env-config.js";import{telemetryTraceStep as u}from"../../../cli/telemetry/helpers/trace-step.js";const g="https://auth.cloud.redocly.com/oidc/.well-known/openid-configuration",y="https://auth.cloud.redocly.com/api/sso/oidc/introspect";async function m(C){return{id:"sso",async processContent(e){await u("build.plugin.sso",async a=>{const o=e.getConfig();if(a?.setAttribute("config",`{"ssoDirect": ${JSON.stringify(o.ssoDirect||{})}}, {"sso": ${JSON.stringify(o.sso||{})}}`),o.ssoDirect&&typeof o.ssoDirect=="object"&&Object.keys(o.ssoDirect).length!==0||o.sso&&Array.isArray(o.sso)&&!o.sso.length)return;const l=!!(o.rbac&&typeof o.rbac=="object"&&Object.keys(o.rbac).length!==0),p=o.requiresLogin;if(!l&&!p)return;let i=g,n=c.REDOCLY_OAUTH_USE_INTROSPECT?y:"";const s=o.residency;if(s){const r=s.endsWith("/")?s.slice(0,-1):s;i=`${r.replace("app.","auth.")}/oidc/.well-known/openid-configuration`,n=c.REDOCLY_OAUTH_USE_INTROSPECT?`${r}/api/sso/oidc/introspect`:""}let t="AUTO";o.sso&&(Array.isArray(o.sso)?t=o.sso.join(","):t=o.sso);const d={oidc:{title:f,type:"OIDC",configurationUrl:i,clientId:"{{ process.env.OAUTH_CLIENT_ID }}",clientSecret:"{{ process.env.OAUTH_CLIENT_SECRET }}",teamsClaimName:"https://redocly.com/sso/teams",scopes:["openid"],authorizationRequestCustomParams:{login_hint:"{{ process.env.ORGANIZATION_ID }}",login_type:t,prompt:"login"},audience:"{{ process.env.ORGANIZATION_ID }}",introspectEndpoint:n}};e.setGlobalConfig({ssoDirect:d})})},async afterRoutesCreated(e){}}}export{m as ssoPlugin};
1
+ import{DEFAULT_SSO_IDP_TITLE as u}from"../../../constants/common.js";import{envConfig as a}from"../../config/env-config.js";import{telemetryTraceStep as g}from"../../../cli/telemetry/helpers/trace-step.js";const y="https://auth.cloud.redocly.com/oidc/.well-known/openid-configuration",C="https://auth.cloud.redocly.com/api/sso/oidc/introspect";async function I(O){return{id:"sso",async processContent(t){await g("build.plugin.sso",async l=>{const s=t.getConfig(),o=s.access;if(l?.setAttribute("config",`{"ssoDirect": ${JSON.stringify(s.ssoDirect||{})}}, {"sso": ${JSON.stringify(o?.sso||{})}}`),s.ssoDirect&&typeof s.ssoDirect=="object"&&Object.keys(s.ssoDirect).length!==0||o?.sso&&Array.isArray(o.sso)&&!o.sso.length)return;const p=!!(o?.rbac&&typeof o.rbac=="object"&&Object.keys(o.rbac).length!==0),d=o?.requiresLogin;if(!p&&!d)return;let n=y,c=a.REDOCLY_OAUTH_USE_INTROSPECT?C:"";const e=o?.residency;if(e){const r=e.endsWith("/")?e.slice(0,-1):e;n=`${r.replace("app.","auth.")}/oidc/.well-known/openid-configuration`,c=a.REDOCLY_OAUTH_USE_INTROSPECT?`${r}/api/sso/oidc/introspect`:""}let i="AUTO";o?.sso&&(Array.isArray(o.sso)?i=o.sso.join(","):i=o.sso);const f={oidc:{title:u,type:"OIDC",configurationUrl:n,clientId:"{{ process.env.OAUTH_CLIENT_ID }}",clientSecret:"{{ process.env.OAUTH_CLIENT_SECRET }}",teamsClaimName:"https://redocly.com/sso/teams",scopes:["openid"],authorizationRequestCustomParams:{login_hint:"{{ process.env.ORGANIZATION_ID }}",login_type:i,prompt:"login"},audience:"{{ process.env.ORGANIZATION_ID }}",introspectEndpoint:c}};t.setGlobalConfig({ssoDirect:f})})},async afterRoutesCreated(t){}}}export{I as ssoPlugin};
@@ -9,4 +9,8 @@ export declare function findFrontmatterSlugs(relativePath: string, loaderName: s
9
9
  export declare function getSidebarSharedDataId(sidebar: string | {
10
10
  path: string;
11
11
  }, relativePath: string, fs: ContentFs): Promise<string | null>;
12
+ export declare function getRouteSlugsForPath(routes: {
13
+ fsPath: string;
14
+ slug: string;
15
+ }[], relativePath: string): string[];
12
16
  //# sourceMappingURL=utils.d.ts.map
@@ -1 +1 @@
1
- import a from"path";import{DEFAULT_LOCALE_PLACEHOLDER as s}from"../../constants/common.js";import{normalizeRouteSlug as m}from"../../utils/path/normalize-route-slug.js";import{logger as l}from"../tools/notifiers/logger.js";import{getLocaleFromRelativePath as p}from"../fs/utils/get-locale-from-relative-path.js";import{isL10nPath as f}from"../fs/utils/is-l10n-path.js";import{removeL10nPrefix as u}from"../fs/utils/remove-l10n-prefix.js";import{resolveSidebarId as c}from"./sidebars/index.js";function E(e,o){return(Array.isArray(e)?e:e?[e]:[]).map(r=>d(r,o))}function d(e,o){const t=p(o).toLowerCase(),r=m(e);return t!==s?`/${t}${r}`:r}function b(e){const o=e.endsWith(".page.tsx")?".page.tsx":a.posix.extname(e),t=a.posix.basename(e,o);return{baseName:t,isIndexFile:t==="index"}}async function R(e,o,t,r){if(t?.slug||!f(e))return t?.slug;const n=u(e);if(!r.fs.exists(n))return;const{data:i}=await r.cache.load(n,o);return i?.frontmatter?.slug}async function I(e,o,t){const r=typeof e=="string",n=r?e:e.path;return r&&l.warnForRealFile("The 'sidebar' property in the front matter of %rp is deprecated. Use 'sidebar.path' instead.",o,t),n?c(o,n,t):null}export{R as findFrontmatterSlugs,I as getSidebarSharedDataId,b as parseBaseName,E as resolveFrontmatterSlugs};
1
+ import a from"path";import{DEFAULT_LOCALE_PLACEHOLDER as m}from"../../constants/common.js";import{normalizeRouteSlug as l}from"../../utils/path/normalize-route-slug.js";import{slash as i}from"../../utils/path/slash.js";import{logger as u}from"../tools/notifiers/logger.js";import{getLocaleFromRelativePath as f}from"../fs/utils/get-locale-from-relative-path.js";import{isL10nPath as p}from"../fs/utils/is-l10n-path.js";import{removeL10nPrefix as c}from"../fs/utils/remove-l10n-prefix.js";import{resolveSidebarId as d}from"./sidebars/index.js";function b(e,r){return(Array.isArray(e)?e:e?[e]:[]).map(o=>g(o,r))}function g(e,r){const t=f(r).toLowerCase(),o=l(e);return t!==m?`/${t}${o}`:o}function I(e){const r=e.endsWith(".page.tsx")?".page.tsx":a.posix.extname(e),t=a.posix.basename(e,r);return{baseName:t,isIndexFile:t==="index"}}async function P(e,r,t,o){if(t?.slug||!p(e))return t?.slug;const n=c(e);if(!o.fs.exists(n))return;const{data:s}=await o.cache.load(n,r);return s?.frontmatter?.slug}async function w(e,r,t){const o=typeof e=="string",n=o?e:e.path;return o&&u.warnForRealFile("The 'sidebar' property in the front matter of %rp is deprecated. Use 'sidebar.path' instead.",r,t),n?d(r,n,t):null}function C(e,r){return e.filter(t=>i(t.fsPath)===i(r)).map(t=>t.slug)}export{P as findFrontmatterSlugs,C as getRouteSlugsForPath,w as getSidebarSharedDataId,I as parseBaseName,b as resolveFrontmatterSlugs};
@@ -1 +1 @@
1
- import{withPathPrefix as O}from"@redocly/theme/core/utils";import{SSR_RENDER_MODE as y}from"../constants/common.js";import{logger as b}from"../tools/notifiers/logger.js";import{canAccessResource as L,filterDataByAccessDeep as d,isResourcePubliclyAccessible as _}from"../utils/rbac.js";import{readSharedData as x}from"../utils/index.js";import{render as C}from"./render.js";import{getServerProps as T}from"./server-side-props/get-server-props.js";import{ssrWorkers as $}from"../workers/ssr-worker-pool.js";import{SSR_WORKER_KEY as j}from"../workers/ssr-worker-pool.js";async function J(e,s,a,r,o,i=!1){const w=b.startTiming(),E=r.routesSharedData.get(e.slug)||{},S=s.sharedDataIds||{},m={...E,...S},{isAuthenticated:g,teams:u,claims:{name:q,picture:I,email:f}}=a?.get("auth")||{claims:{}},t={isAuthenticated:g,email:f,teams:u},R=Object.fromEntries(await Promise.all(Object.entries(m).map(async([H,D])=>[D,await x(D,r.outdir)]))),P=d(R,t,r.config.rbac,r.config.requiresLogin),v=d(r.globalData,t,r.config.rbac,r.config.requiresLogin),p=L(e,t,r.config.rbac,r.config.requiresLogin),A=!!r.compilationErrors?.length?{templateId:"compilation-error",props:{compilationErrors:r.compilationErrors},sharedDataIds:{}}:null,h={page:{templateId:e.templateId,isPublic:_(e,r.config),slug:O(e.slug),versions:d(e.versions,t,r.config.rbac,r.config.requiresLogin),props:s,sharedDataIds:p?m:{},product:e.product,request:{search:a?.req.raw.context.url?.search||"",url:a?.req.raw.context.url?.href||""},userInfo:{isAuthenticated:g,name:q,picture:I,email:f,teams:u},...A},store:{globalData:v,config:r.config,ssr:r.ssr,hasSitemap:r.hasSitemap},sharedData:p?P:{},serverOutDir:r.serverOutDir,outdir:r.outdir,ssrHref:k(a),userAgent:a?.req.raw.headers.get("user-agent")||"",telemetry:o,omitSuspense:i};let n,c,l;return y==="worker"?{html:n,statusCode:c,error:l}=await $.exec(j,[h]):{html:n,statusCode:c,error:l}=await C(h),b.verboseTime(w,`Page rendered ${e.slug}`),{html:n,props:s,statusCode:c,error:l}}function k(e){const s=e?.req.raw.url;if(!s)return"";const a=new URL(s),r=e?.req.raw.headers,o=r?.get("x-forwarded-proto")||a.protocol.replace(":",""),i=r?.get("x-forwarded-host")||a.host;return`${o}://${i}`}export{T as getServerProps,J as renderPage};
1
+ import{withPathPrefix as O}from"@redocly/theme/core/utils";import{SSR_RENDER_MODE as y}from"../constants/common.js";import{logger as b}from"../tools/notifiers/logger.js";import{canAccessResource as L,filterDataByAccessDeep as d,isResourcePubliclyAccessible as _}from"../utils/rbac.js";import{readSharedData as x}from"../utils/index.js";import{render as C}from"./render.js";import{getServerProps as T}from"./server-side-props/get-server-props.js";import{ssrWorkers as $}from"../workers/ssr-worker-pool.js";import{SSR_WORKER_KEY as j}from"../workers/ssr-worker-pool.js";async function J(e,s,a,r,o,c=!1){const w=b.startTiming(),E=r.routesSharedData.get(e.slug)||{},S=s.sharedDataIds||{},m={...E,...S},{isAuthenticated:g,teams:u,claims:{name:q,picture:I,email:f}}=a?.get("auth")||{claims:{}},t={isAuthenticated:g,email:f,teams:u},R=Object.fromEntries(await Promise.all(Object.entries(m).map(async([H,D])=>[D,await x(D,r.outdir)]))),P=d(R,t,r.config.access?.rbac,r.config.access?.requiresLogin),v=d(r.globalData,t,r.config.access?.rbac,r.config.access?.requiresLogin),p=L(e,t,r.config.access?.rbac,r.config.access?.requiresLogin),A=!!r.compilationErrors?.length?{templateId:"compilation-error",props:{compilationErrors:r.compilationErrors},sharedDataIds:{}}:null,h={page:{templateId:e.templateId,isPublic:_(e,r.config),slug:O(e.slug),versions:d(e.versions,t,r.config.access?.rbac,r.config.access?.requiresLogin),props:s,sharedDataIds:p?m:{},product:e.product,request:{search:a?.req.raw.context.url?.search||"",url:a?.req.raw.context.url?.href||""},userInfo:{isAuthenticated:g,name:q,picture:I,email:f,teams:u},...A},store:{globalData:v,config:r.config,ssr:r.ssr,hasSitemap:r.hasSitemap},sharedData:p?P:{},serverOutDir:r.serverOutDir,outdir:r.outdir,ssrHref:k(a),userAgent:a?.req.raw.headers.get("user-agent")||"",telemetry:o,omitSuspense:c};let i,n,l;return y==="worker"?{html:i,statusCode:n,error:l}=await $.exec(j,[h]):{html:i,statusCode:n,error:l}=await C(h),b.verboseTime(w,`Page rendered ${e.slug}`),{html:i,props:s,statusCode:n,error:l}}function k(e){const s=e?.req.raw.url;if(!s)return"";const a=new URL(s),r=e?.req.raw.headers,o=r?.get("x-forwarded-proto")||a.protocol.replace(":",""),c=r?.get("x-forwarded-host")||a.host;return`${o}://${c}`}export{T as getServerProps,J as renderPage};
@@ -1,8 +1,7 @@
1
1
  import type { Node } from '@markdoc/markdoc';
2
2
  import type { JSX } from 'react';
3
3
  import type { CommonError, GlobalData } from '../types/index.js';
4
- import type { WildcardRedirectsTree } from './types';
5
- import type { MiddlewareDetails, PageRouteInit, PageRouteDetails, RouteDetails, LifecycleContext, MarkdownParseInput, ApiRoute, MarkdocDeps } from './types';
4
+ import type { MiddlewareDetails, PageRouteInit, PageRouteDetails, RouteDetails, LifecycleContext, ApiRoute, ParseMarkdocOpts, WildcardRedirectsTree } from './types';
6
5
  import type { RedoclyConfig, RedirectConfig, CompilationError, PageStaticData } from '@redocly/config';
7
6
  import type { SearchFacet } from '@redocly/theme/core/types';
8
7
  import type { BundledDefinition as OpenApiBundledDefinition } from './plugins/openapi-docs/load-definition.js';
@@ -119,7 +118,7 @@ export declare class Store {
119
118
  setGlobalData: (data: GlobalData) => void;
120
119
  getGlobalData: () => GlobalData;
121
120
  getKv: () => Promise<KvService>;
122
- parseMarkdoc: (input: MarkdownParseInput, context: LifecycleContext, deps?: MarkdocDeps) => Promise<{
121
+ parseMarkdoc: ({ input, context, deps, resource }: ParseMarkdocOpts) => Promise<{
123
122
  info: {
124
123
  sharedDataDeps?: Set<string>;
125
124
  dynamicMarkdocComponents?: string[];
@@ -1 +1 @@
1
- import b from"@markdoc/markdoc";import{getPathnameForLocale as A}from"@redocly/theme/core/utils";import{DEFAULT_LOCALE_PLACEHOLDER as u}from"../constants/common.js";import{DEFAULT_TITLE as C}from"./constants/common.js";import{GATED_MARKDOC_TAGS as D}from"./constants/entitlements.js";import{isObject as O}from"../utils/guards/is-object.js";import{mapObject as T}from"../utils/object/map-object.js";import{getValueDeep as S}from"../utils/object/get-value-deep.js";import{removeTrailingSlash as M}from"../utils/url/remove-trailing-slash.js";import{normalizeRouteSlug as f}from"../utils/path/normalize-route-slug.js";import{isLocalLink as L}from"../utils/path/is-local-link.js";import{reporter as w}from"./tools/notifiers/reporter.js";import{logger as p}from"./tools/notifiers/logger.js";import{sha1 as k}from"./utils/crypto/sha1.js";import{writeEnvVariable as _}from"./utils/envs/write-env-variable.js";import{envConfig as F}from"./config/env-config.js";import{KvService as G}from"./persistence/kv/services/kv-service.js";import{writeSharedData as B}from"./utils/index.js";import{renderComponents as I}from"./ssr/render.js";import{readStaticData as N,writeStaticData as V}from"./utils/static-data.js";import{parseAndResolveMarkdoc as j}from"./plugins/markdown/compiler.js";import{getMarkdocOptions as H}from"./plugins/markdown/markdoc/markdoc-options.js";import{EntitlementsProvider as y}from"./entitlements/entitlements-provider.js";import{isL10nPath as K}from"./fs/utils/is-l10n-path.js";import{resolveMetadataGlobs as U}from"./utils/globs.js";import{replaceEnvVariablesDeep as J}from"./utils/envs/replace-env-variables-deep.js";import{findRedirect as x}from"./utils/redirects/find-redirect.js";import{addWildcardRedirectToTree as q}from"./utils/redirects/add-wildcard-redirect-to-tree.js";import{telemetryTraceStep as $}from"../cli/telemetry/helpers/trace-step.js";const R={routesBySlug:"map",apiRoutes:"object",middleware:"object",routesByFsPath:"map",routesSharedData:"map",globalData:"object",config:"object",ssr:"object",searchFacets:"map",routesPartials:"map"},g="markdown/partials",W="markdown/partials-deps",v="PLAN_GATES",z=["OAUTH_CLIENT_ID","OAUTH_CLIENT_SECRET","ORGANIZATION_SLUG","ORGANIZATION_ID","ORG_ID"],At="userDefinedApiFunctions";class E{routesBySlug=new Map;replacedEnvVars={};unsetEnvVars=new Set;lifecycleContext;newRoutes=[];#t={};routesByFsPath=new Map;apiRoutes=[];middleware=[];routesSharedData=new Map;sharedDataDeps=new Map;sharedDataMarkdocComponents=new Map;routesDynamicComponents=new Map;routesPartials=new Map;ssr={preBodyTags:[],postBodyTags:[],headTags:[]};searchFacets=new Map;searchEngine;templates=new Map;browserPlugins=new Set;apiRoutesRequestHandlers=new Map;serverPropsGetters=new Map;pagePropsGetters=new Map;listeners=new Map;globalData={};#s=void 0;config={configFilePath:"",redirects:{},wildcardRedirectsTree:{},rbac:{},directoryPermissions:{},devLogin:!1,ssoDirect:{}};#r;serverMode;serverOutDir;outdir;buildRevision=0;hasSitemap=!1;compilationErrors=[];#a;userCodeReady;#o=Promise.resolve();#i;#n=Promise.resolve();#c;#e=new Map;constructor({outdir:t,contentDir:e,serverMode:s=!1,serverOutDir:r}){this.#r=e,this.outdir=t,this.serverMode=s,this.serverOutDir=r,this.userCodeReady=new Promise(a=>{this.#a=a})}on(t,e){const s=this.listeners.get(t);s?s.add(e):this.listeners.set(t,new Set([e]))}queueEvent=(t,e,...s)=>{this.#e.set(t+String(e),[t,e,...s])};runListeners=(t,e,...s)=>{for(const r of this.listeners.get(t)||new Set)e?r(e,...s):r(...s)};startPluginsRun(){this.clear(),this.#o=new Promise(t=>{this.#i=t})}waitForPluginsLifecycle(){return Promise.all([this.#o,this.#n])}finishPluginsRun(){this.#i?.();for(const t of this.#e.values())this.runListeners(...t);this.#e.clear()}startEsbuildRun(){this.#n=new Promise(t=>{this.#c=t})}finishEsbuildRun(){this.#c?.()}get contentDir(){if(this.serverMode)throw new Error("contentDir should not be used in server mode");return this.#r}markUserCodeReady(){this.#a?.(!0)}async reloadMarkdocOptions(){await $("build.reload_markdoc_options",async()=>{const t=y.instance(),e=await H(this.serverOutDir),s=Object.fromEntries(Object.entries(e.tags).filter(([r])=>D[r]!=null?t.canAccessFeature(D[r]):!0));this.#s={...e,tags:s}})}get markdocOptions(){return{...this.#s,partials:this.getGlobalConfig(g),themeConfig:this.config.markdown}}setGlobalData=t=>{const e=this.globalData,s={...this.globalData,...t};this.globalData=s,JSON.stringify(s)!==JSON.stringify(e)&&this.queueEvent("global-data-updated",void 0,s)};getGlobalData=()=>this.globalData;getKv=async()=>G.getInstance({baseDbDir:this.serverOutDir});parseMarkdoc=async(t,e,s)=>{const{data:{info:r,ast:a},compoundHash:n}=await j(t,this.markdocOptions,{actions:this,context:e});for(const i of r.sharedDataDeps||[]){for(const o of s?.routeSlugs||[])this.addRouteSharedData(o,i,i);for(const o of s?.sharedDataIds||[]){const c=this.sharedDataDeps.get(o)||new Set;c.add(i),this.sharedDataDeps.set(o,c)}}for(const i of r.dynamicMarkdocComponents||[]){for(const o of s?.routeSlugs||[]){const c=this.routesDynamicComponents.get(o)||new Set;c.add(i),this.routesDynamicComponents.set(o,c)}for(const o of s?.sharedDataIds||[]){const c=this.sharedDataMarkdocComponents.get(o)||new Set;c.add(i),this.sharedDataMarkdocComponents.set(o,c)}}if(s?.routeSlugs&&r.partials?.length)for(const i of s.routeSlugs){const o=this.routesPartials.get(i)||[];for(const c of r.partials)o.includes(c)||o.push(c);this.routesPartials.set(i,o)}return{info:r,ast:a,compoundHash:n}};async loadOpenApiDefinitions(t){return(await t.cache.load(".","load-oas-docs")).data}async loadAsyncApiDefinitions(t){return(await t.cache.load(".","asyncapi-docs")).data}setSearchEngine(t){this.searchEngine=t}setSearchFacets=t=>{this.searchFacets=t};setGlobalConfig=t=>{const e=Object.keys(t);for(const n of e)for(const i in this.replacedEnvVars)if(i===n||i.startsWith(`${n}:`)){const o=i.split(":"),{error:c,value:l}=S(t,o);(c||l!==this.replacedEnvVars[i].replaced)&&delete this.replacedEnvVars[i]}const{resolvedObj:s,unsetEnvVars:r,replacedValues:a}=J(t);for(const n of r)this.unsetEnvVars.add(n);Object.assign(this.replacedEnvVars,a),Object.assign(this.config,s)};getConfig=()=>this.config;getGlobalConfig=t=>this.config[t];getSearchFacets=()=>this.searchFacets;addRedirect=(t,e)=>{if(!y.instance().canAccessFeature("redirects")&&t!=="/")return;this.config.redirects||(this.config.redirects={});const a=f(t).toLowerCase();this.config.redirects[a]=e,a.endsWith("*")&&q(this.config.wildcardRedirectsTree,a)};getRedirect=t=>{const e=f(t).toLowerCase();return x(e,this.config.redirects,this.config.wildcardRedirectsTree)};createSharedData=async(t,e,s)=>{if(s&&this.#t[t]===s)return t;const r=JSON.stringify(e),a=s??k(r);return this.#t[t]===a||(this.#t[t]=a,await B(t,r,this.outdir),this.queueEvent("shared-data-updated",t)),t};addRouteSharedData=(t,e,s)=>{const r=M(t),a=this.routesSharedData.get(r)||{};a[e]=s,this.routesSharedData.set(r,a),p.verbose(`Adding shared data to ${t}, ${e}, ${s}`)};getRouteSharedDataByFsPath=t=>{const e=this.routesByFsPath.get(t);return e?this.routesSharedData.get(e)||{}:{}};getPartialsForRoute=t=>{const e=this.getGlobalConfig(g)||{},s=this.routesPartials.get(t);if(!s||s.length===0)return{};const r=this.getGlobalConfig(W)||{},a=new Set(s),n=Array.from(s);for(let o=0;o<n.length;o++){const c=n[o],l=r[c]?.partials??[];for(const d of l)a.has(d)||(a.add(d),n.push(d))}const i={};for(const o of a)e[o]&&(i[o]=e[o]);return i};addRoute=t=>{const s={...U(t.fsPath,this.config.metadataGlobs),...t.metadata||{}};this.newRoutes.push({...t,metadata:s}),p.verbose("Created route %s",t.slug)};addRouteSharedDataToAllLocales=(t,e,s)=>{const r=[u,...this.lifecycleContext?.fs.localeFolders||[]].map(a=>({code:a,name:a}));for(const a of r){const n=A(t,u,a.code,r);this.addRouteSharedData(n,e,s)}};addApiRoute=t=>{this.apiRoutes.push(t),p.verbose("Created API route %s",t.slug)};addMiddleware=t=>{this.middleware.push(t),p.verbose("Created middleware %s",t.id)};getRouteByFsPath=t=>{const e=this.routesByFsPath.get(t);return e?this.getRouteBySlug(e):void 0};getRouteBySlug=(t,e={})=>{const{followRedirect:s=!0}=e,r=this.getRedirect(t);return s&&r?this.routesBySlug.get(f(r.to)):this.routesBySlug.get(t)};slugHasRouteOrRedirect=t=>{if(this.routesBySlug.has(t))return!0;const e=this.getRedirect(t);if(!e)return!1;if(!L(e.to))return!0;const s=f(e.to);return this.routesBySlug.has(s)};getRoutesByTemplateId=t=>this.newRoutes.filter(e=>e.templateId===t);getAllRoutesForLocale=(t=u)=>{const e=Array.from(this.routesBySlug.values()),s=t.toLowerCase();return e.filter(r=>t===u?!K(r.fsPath):r.slug.startsWith(`/${s}`))};getAllRoutes=()=>Array.from(this.routesBySlug.values());getAllApiRoutes=()=>this.apiRoutes;getAllMiddleware=()=>this.middleware;getTemplate=t=>this.templates.get(t);getRequestHandler=t=>this.apiRoutesRequestHandlers.get(t);createTemplate=(t,e)=>(this.templates.set(t,e),t);addBrowserPlugin=t=>{this.browserPlugins.add(t)};createRequestHandler=(t,e)=>(this.apiRoutesRequestHandlers.set(t,e),t);registerServerPropsGetter=(t,e)=>(this.serverPropsGetters.set(t,e),t);registerPagePropsGetter=(t,e)=>{this.pagePropsGetters.set(t,e)};async writeRouteStaticData(t,e){const s=await this.resolveRouteStaticData(t,e,!1);s&&V(t.slug,s,this.outdir)}async resolveRouteStaticData(t,e,s){if(this.serverMode)return N(t.slug,this.outdir);const r={...this,contentDir:this.contentDir,parseMarkdoc:(l,d)=>this.parseMarkdoc(l,d,{routeSlugs:[t.slug]})},a=await t.getStaticData?.(t,r)||{},n=new Set(this.routesDynamicComponents.get(t.slug)),i=this.routesSharedData.get(t.slug)||{};for(const l of Object.values(i)){const d=this.sharedDataMarkdocComponents.get(l);d&&d.forEach(h=>n.add(h));const m=this.sharedDataDeps.get(l);m&&m.forEach(h=>this.addRouteSharedData(t.slug,h,h))}const o=this.getGlobalConfig("seo"),c=a?.frontmatter||{};return{...a,frontmatter:{...c,seo:{...c?.seo,title:c?.seo?.title||await t.getNavText?.()}},props:{...a.props,dynamicMarkdocComponents:Array.from(n),metadata:{...a?.props?.metadata,...t.metadata},seo:{title:C,...o,...a.props?.seo},compilationErrors:this.compilationErrors},lastModified:s||!t.fsPath?null:await this.lifecycleContext?.fs.getLastModified(t.fsPath)}}addSsrComponents(t,e){if(!t?.length)return;const s=typeof t[0]=="string"?t.join(""):I(t);s&&(e==="head"?this.ssr.headTags.push(s):e==="preBody"?this.ssr.preBodyTags.push(s):this.ssr.postBodyTags.push(s))}clear=()=>{this.routesByFsPath.clear(),this.templates.clear(),this.newRoutes=[],this.routesBySlug.clear(),this.apiRoutes=[],this.middleware=[],this.routesSharedData.clear(),this.sharedDataDeps.clear(),this.sharedDataMarkdocComponents.clear(),this.routesDynamicComponents.clear(),this.routesPartials.clear(),this.config.redirects={},this.config.wildcardRedirectsTree={},this.config.directoryPermissions={},this.ssr={preBodyTags:[],postBodyTags:[],headTags:[]}};async toJson(){const t=[];for(const[s,r]of Object.entries(R))switch(r){case"map":const a=Array.from(this[s].entries());t.push([s,a]);break;case"object":s==="config"&&t.push([s,await this.getConfigWithEnvPlaceholders()]),t.push([s,this[s]]);break;default:throw new Error("Invalid format")}const e=Object.fromEntries(t);return e[v]=F.PLAN_GATES,e}static fromJson(t,e){const s=new E(e);for(const[a,n]of Object.entries(R))switch(n){case"map":s[a]=new Map(t[a]);break;case"object":if(a==="config"){s.setGlobalConfig(t[a]);break}s[a]=t[a];break;default:throw new Error("Invalid format")}s.config[g]=Y(s.config[g]||{});const r=t[v];return r&&_("PLAN_GATES",r),s}async getConfigWithEnvPlaceholders(){const t=JSON.parse(JSON.stringify(this.config));for(const e in this.replacedEnvVars){const{original:s}=this.replacedEnvVars[e],r=e.split(":"),a=r.pop(),{error:n,value:i}=S(t,r);if(n||!O(i)&&!Array.isArray(i)){await w.panicOnBuild(`Failed to replace env var with env name for ${e}`);continue}i[a]=s}return t}async reportUnsetEnvVars(){if(this.unsetEnvVars.size===0)return;const t=Array.from(this.unsetEnvVars).filter(s=>!z.includes(s));if(t.length===0)return;const e=`Failed to resolve config. The following environment variables are not set: ${t.join(", ")}`;await w.panicOnBuildContentError(e)}}function Y(P){return T(P,t=>b.Ast.fromJSON(JSON.stringify(t)))}export{g as MARKDOC_PARTIALS_DATA_KEY,W as MARKDOC_PARTIALS_DEPS_KEY,E as Store,At as USER_DEFINED_API_FUNCTIONS_COUNTER_KEY};
1
+ import b from"@markdoc/markdoc";import{getPathnameForLocale as A}from"@redocly/theme/core/utils";import{DEFAULT_LOCALE_PLACEHOLDER as f}from"../constants/common.js";import{DEFAULT_TITLE as C}from"./constants/common.js";import{GATED_MARKDOC_TAGS as D}from"./constants/entitlements.js";import{isObject as O}from"../utils/guards/is-object.js";import{mapObject as T}from"../utils/object/map-object.js";import{getValueDeep as S}from"../utils/object/get-value-deep.js";import{removeTrailingSlash as M}from"../utils/url/remove-trailing-slash.js";import{normalizeRouteSlug as p}from"../utils/path/normalize-route-slug.js";import{isLocalLink as L}from"../utils/path/is-local-link.js";import{reporter as w}from"./tools/notifiers/reporter.js";import{logger as g}from"./tools/notifiers/logger.js";import{sha1 as k}from"./utils/crypto/sha1.js";import{writeEnvVariable as _}from"./utils/envs/write-env-variable.js";import{envConfig as F}from"./config/env-config.js";import{KvService as G}from"./persistence/kv/services/kv-service.js";import{writeSharedData as B}from"./utils/index.js";import{renderComponents as I}from"./ssr/render.js";import{readStaticData as N,writeStaticData as V}from"./utils/static-data.js";import{parseAndResolveMarkdoc as j}from"./plugins/markdown/compiler.js";import{getMarkdocOptions as H}from"./plugins/markdown/markdoc/markdoc-options.js";import{EntitlementsProvider as y}from"./entitlements/entitlements-provider.js";import{isL10nPath as K}from"./fs/utils/is-l10n-path.js";import{resolveMetadataGlobs as U}from"./utils/globs.js";import{replaceEnvVariablesDeep as J}from"./utils/envs/replace-env-variables-deep.js";import{findRedirect as q}from"./utils/redirects/find-redirect.js";import{addWildcardRedirectToTree as x}from"./utils/redirects/add-wildcard-redirect-to-tree.js";import{telemetryTraceStep as $}from"../cli/telemetry/helpers/trace-step.js";const R={routesBySlug:"map",apiRoutes:"object",middleware:"object",routesByFsPath:"map",routesSharedData:"map",globalData:"object",config:"object",ssr:"object",searchFacets:"map",routesPartials:"map"},m="markdown/partials",W="markdown/partials-deps",v="PLAN_GATES",z=["OAUTH_CLIENT_ID","OAUTH_CLIENT_SECRET","ORGANIZATION_SLUG","ORGANIZATION_ID","ORG_ID"],At="userDefinedApiFunctions";class E{routesBySlug=new Map;replacedEnvVars={};unsetEnvVars=new Set;lifecycleContext;newRoutes=[];#t={};routesByFsPath=new Map;apiRoutes=[];middleware=[];routesSharedData=new Map;sharedDataDeps=new Map;sharedDataMarkdocComponents=new Map;routesDynamicComponents=new Map;routesPartials=new Map;ssr={preBodyTags:[],postBodyTags:[],headTags:[]};searchFacets=new Map;searchEngine;templates=new Map;browserPlugins=new Set;apiRoutesRequestHandlers=new Map;serverPropsGetters=new Map;pagePropsGetters=new Map;listeners=new Map;globalData={};#s=void 0;config={configFilePath:"",redirects:{},wildcardRedirectsTree:{},access:{rbac:{},requiresLogin:!1},directoryPermissions:{},devLogin:!1,ssoDirect:{}};#r;serverMode;serverOutDir;outdir;buildRevision=0;hasSitemap=!1;compilationErrors=[];#a;userCodeReady;#o=Promise.resolve();#i;#n=Promise.resolve();#c;#e=new Map;constructor({outdir:t,contentDir:e,serverMode:s=!1,serverOutDir:a}){this.#r=e,this.outdir=t,this.serverMode=s,this.serverOutDir=a,this.userCodeReady=new Promise(r=>{this.#a=r})}on(t,e){const s=this.listeners.get(t);s?s.add(e):this.listeners.set(t,new Set([e]))}queueEvent=(t,e,...s)=>{this.#e.set(t+String(e),[t,e,...s])};runListeners=(t,e,...s)=>{for(const a of this.listeners.get(t)||new Set)e?a(e,...s):a(...s)};startPluginsRun(){this.clear(),this.#o=new Promise(t=>{this.#i=t})}waitForPluginsLifecycle(){return Promise.all([this.#o,this.#n])}finishPluginsRun(){this.#i?.();for(const t of this.#e.values())this.runListeners(...t);this.#e.clear()}startEsbuildRun(){this.#n=new Promise(t=>{this.#c=t})}finishEsbuildRun(){this.#c?.()}get contentDir(){if(this.serverMode)throw new Error("contentDir should not be used in server mode");return this.#r}markUserCodeReady(){this.#a?.(!0)}async reloadMarkdocOptions(){await $("build.reload_markdoc_options",async()=>{const t=y.instance(),e=await H(this.serverOutDir),s=Object.fromEntries(Object.entries(e.tags).filter(([a])=>D[a]!=null?t.canAccessFeature(D[a]):!0));this.#s={...e,tags:s}})}get markdocOptions(){return{...this.#s,partials:this.getGlobalConfig(m),themeConfig:this.config.markdown}}setGlobalData=t=>{const e=this.globalData,s={...this.globalData,...t};this.globalData=s,JSON.stringify(s)!==JSON.stringify(e)&&this.queueEvent("global-data-updated",void 0,s)};getGlobalData=()=>this.globalData;getKv=async()=>G.getInstance({baseDbDir:this.serverOutDir});parseMarkdoc=async({input:t,context:e,deps:s,resource:a})=>{const{data:{info:r,ast:c},compoundHash:l}=await j(t,this.markdocOptions,{actions:this,context:e},a);for(const i of r.sharedDataDeps||[]){for(const o of s?.routeSlugs||[])this.addRouteSharedData(o,i,i);for(const o of s?.sharedDataIds||[]){const n=this.sharedDataDeps.get(o)||new Set;n.add(i),this.sharedDataDeps.set(o,n)}}for(const i of r.dynamicMarkdocComponents||[]){for(const o of s?.routeSlugs||[]){const n=this.routesDynamicComponents.get(o)||new Set;n.add(i),this.routesDynamicComponents.set(o,n)}for(const o of s?.sharedDataIds||[]){const n=this.sharedDataMarkdocComponents.get(o)||new Set;n.add(i),this.sharedDataMarkdocComponents.set(o,n)}}if(s?.routeSlugs&&r.partials?.length)for(const i of s.routeSlugs){const o=this.routesPartials.get(i)||[];for(const n of r.partials)o.includes(n)||o.push(n);this.routesPartials.set(i,o)}return{info:r,ast:c,compoundHash:l}};async loadOpenApiDefinitions(t){return(await t.cache.load(".","load-oas-docs")).data}async loadAsyncApiDefinitions(t){return(await t.cache.load(".","asyncapi-docs")).data}setSearchEngine(t){this.searchEngine=t}setSearchFacets=t=>{this.searchFacets=t};setGlobalConfig=t=>{const e=Object.keys(t);for(const c of e)for(const l in this.replacedEnvVars)if(l===c||l.startsWith(`${c}:`)){const i=l.split(":"),{error:o,value:n}=S(t,i);(o||n!==this.replacedEnvVars[l].replaced)&&delete this.replacedEnvVars[l]}const{resolvedObj:s,unsetEnvVars:a,replacedValues:r}=J(t);for(const c of a)this.unsetEnvVars.add(c);Object.assign(this.replacedEnvVars,r),Object.assign(this.config,s)};getConfig=()=>this.config;getGlobalConfig=t=>this.config[t];getSearchFacets=()=>this.searchFacets;addRedirect=(t,e)=>{if(!y.instance().canAccessFeature("redirects")&&t!=="/")return;this.config.redirects||(this.config.redirects={});const r=p(t).toLowerCase();this.config.redirects[r]=e,r.endsWith("*")&&x(this.config.wildcardRedirectsTree,r)};getRedirect=t=>{const e=p(t).toLowerCase();return q(e,this.config.redirects,this.config.wildcardRedirectsTree)};createSharedData=async(t,e,s)=>{if(s&&this.#t[t]===s)return t;const a=JSON.stringify(e),r=s??k(a);return this.#t[t]===r||(this.#t[t]=r,await B(t,a,this.outdir),this.queueEvent("shared-data-updated",t)),t};addRouteSharedData=(t,e,s)=>{const a=M(t),r=this.routesSharedData.get(a)||{};r[e]=s,this.routesSharedData.set(a,r),g.verbose(`Adding shared data to ${t}, ${e}, ${s}`)};getRouteSharedDataByFsPath=t=>{const e=this.routesByFsPath.get(t);return e?this.routesSharedData.get(e)||{}:{}};getPartialsForRoute=t=>{const e=this.getGlobalConfig(m)||{},s=this.routesPartials.get(t);if(!s||s.length===0)return{};const a=this.getGlobalConfig(W)||{},r=new Set(s),c=Array.from(s);for(let i=0;i<c.length;i++){const o=c[i],n=a[o]?.partials??[];for(const d of n)r.has(d)||(r.add(d),c.push(d))}const l={};for(const i of r)e[i]&&(l[i]=e[i]);return l};addRoute=t=>{const s={...U(t.fsPath,this.config.metadataGlobs),...t.metadata||{}};this.newRoutes.push({...t,metadata:s}),g.verbose("Created route %s",t.slug)};addRouteSharedDataToAllLocales=(t,e,s)=>{const a=[f,...this.lifecycleContext?.fs.localeFolders||[]].map(r=>({code:r,name:r}));for(const r of a){const c=A(t,f,r.code,a);this.addRouteSharedData(c,e,s)}};addApiRoute=t=>{this.apiRoutes.push(t),g.verbose("Created API route %s",t.slug)};addMiddleware=t=>{this.middleware.push(t),g.verbose("Created middleware %s",t.id)};getRouteByFsPath=t=>{const e=this.routesByFsPath.get(t);return e?this.getRouteBySlug(e):void 0};getRouteBySlug=(t,e={})=>{const{followRedirect:s=!0}=e,a=this.getRedirect(t);return s&&a?this.routesBySlug.get(p(a.to)):this.routesBySlug.get(t)};slugHasRouteOrRedirect=t=>{if(this.routesBySlug.has(t))return!0;const e=this.getRedirect(t);if(!e)return!1;if(!L(e.to))return!0;const s=p(e.to);return this.routesBySlug.has(s)};getRoutesByTemplateId=t=>this.newRoutes.filter(e=>e.templateId===t);getAllRoutesForLocale=(t=f)=>{const e=Array.from(this.routesBySlug.values()),s=t.toLowerCase();return e.filter(a=>t===f?!K(a.fsPath):a.slug.startsWith(`/${s}`))};getAllRoutes=()=>Array.from(this.routesBySlug.values());getAllApiRoutes=()=>this.apiRoutes;getAllMiddleware=()=>this.middleware;getTemplate=t=>this.templates.get(t);getRequestHandler=t=>this.apiRoutesRequestHandlers.get(t);createTemplate=(t,e)=>(this.templates.set(t,e),t);addBrowserPlugin=t=>{this.browserPlugins.add(t)};createRequestHandler=(t,e)=>(this.apiRoutesRequestHandlers.set(t,e),t);registerServerPropsGetter=(t,e)=>(this.serverPropsGetters.set(t,e),t);registerPagePropsGetter=(t,e)=>{this.pagePropsGetters.set(t,e)};async writeRouteStaticData(t,e){const s=await this.resolveRouteStaticData(t,e,!1);s&&V(t.slug,s,this.outdir)}async resolveRouteStaticData(t,e,s){if(this.serverMode)return N(t.slug,this.outdir);const a={...this,contentDir:this.contentDir,parseMarkdoc:({input:n,context:d,resource:h})=>this.parseMarkdoc({input:n,context:d,deps:{routeSlugs:[t.slug]},resource:h})},r=await t.getStaticData?.(t,a)||{},c=new Set(this.routesDynamicComponents.get(t.slug)),l=this.routesSharedData.get(t.slug)||{};for(const n of Object.values(l)){const d=this.sharedDataMarkdocComponents.get(n);d&&d.forEach(u=>c.add(u));const h=this.sharedDataDeps.get(n);h&&h.forEach(u=>this.addRouteSharedData(t.slug,u,u))}const i=this.getGlobalConfig("seo"),o=r?.frontmatter||{};return{...r,frontmatter:{...o,seo:{...o?.seo,title:o?.seo?.title||await t.getNavText?.()}},props:{...r.props,dynamicMarkdocComponents:Array.from(c),metadata:{...r?.props?.metadata,...t.metadata},seo:{title:C,...i,...r.props?.seo},compilationErrors:this.compilationErrors},lastModified:s||!t.fsPath?null:await this.lifecycleContext?.fs.getLastModified(t.fsPath)}}addSsrComponents(t,e){if(!t?.length)return;const s=typeof t[0]=="string"?t.join(""):I(t);s&&(e==="head"?this.ssr.headTags.push(s):e==="preBody"?this.ssr.preBodyTags.push(s):this.ssr.postBodyTags.push(s))}clear=()=>{this.routesByFsPath.clear(),this.templates.clear(),this.newRoutes=[],this.routesBySlug.clear(),this.apiRoutes=[],this.middleware=[],this.routesSharedData.clear(),this.sharedDataDeps.clear(),this.sharedDataMarkdocComponents.clear(),this.routesDynamicComponents.clear(),this.routesPartials.clear(),this.config.redirects={},this.config.wildcardRedirectsTree={},this.config.directoryPermissions={},this.ssr={preBodyTags:[],postBodyTags:[],headTags:[]}};async toJson(){const t=[];for(const[s,a]of Object.entries(R))switch(a){case"map":const r=Array.from(this[s].entries());t.push([s,r]);break;case"object":s==="config"&&t.push([s,await this.getConfigWithEnvPlaceholders()]),t.push([s,this[s]]);break;default:throw new Error("Invalid format")}const e=Object.fromEntries(t);return e[v]=F.PLAN_GATES,e}static fromJson(t,e){const s=new E(e);for(const[r,c]of Object.entries(R))switch(c){case"map":s[r]=new Map(t[r]);break;case"object":if(r==="config"){s.setGlobalConfig(t[r]);break}s[r]=t[r];break;default:throw new Error("Invalid format")}s.config[m]=Y(s.config[m]||{});const a=t[v];return a&&_("PLAN_GATES",a),s}async getConfigWithEnvPlaceholders(){const t=JSON.parse(JSON.stringify(this.config));for(const e in this.replacedEnvVars){const{original:s}=this.replacedEnvVars[e],a=e.split(":"),r=a.pop(),{error:c,value:l}=S(t,a);if(c||!O(l)&&!Array.isArray(l)){await w.panicOnBuild(`Failed to replace env var with env name for ${e}`);continue}l[r]=s}return t}async reportUnsetEnvVars(){if(this.unsetEnvVars.size===0)return;const t=Array.from(this.unsetEnvVars).filter(s=>!z.includes(s));if(t.length===0)return;const e=`Failed to resolve config. The following environment variables are not set: ${t.join(", ")}`;await w.panicOnBuildContentError(e)}}function Y(P){return T(P,t=>b.Ast.fromJSON(JSON.stringify(t)))}export{m as MARKDOC_PARTIALS_DATA_KEY,W as MARKDOC_PARTIALS_DEPS_KEY,E as Store,At as USER_DEFINED_API_FUNCTIONS_COUNTER_KEY};
@@ -1,6 +1,6 @@
1
- import{envConfig as p}from"../../config/env-config.js";import{gray as w}from"./helpers/colors.js";const t="\x1B[",l=`${t}6n`,i=`${t}s`,c=`${t}u`,f=`${t}J`,h=n=>`${t}1;${n}r`,d=`${t}r`,u=`${t}?25h`,R=`${t}?25l`,I=()=>`${w("\u2500".repeat(process.stderr.columns||80))}
1
+ import{envConfig as p}from"../../config/env-config.js";import{gray as w}from"./helpers/colors.js";const t="\x1B[",u=`${t}6n`,o=`${t}s`,c=`${t}u`,f=`${t}J`,h=n=>`${t}1;${n}r`,a=`${t}r`,l=`${t}?25h`,R=`${t}?25l`,I=()=>`${w("\u2500".repeat(process.stderr.columns||80))}
2
2
 
3
- `,g=3;class T{#s=new Map;#t=process.stderr.rows;#o=0;#i=!1;#c=!1;#r;constructor(s=!1){this.#c=s,this.isInteractive()&&(this.#a(),process.stderr.write(l))}isInteractive(){return!!(this.#c&&process.stderr&&process.stderr.isTTY&&p.TERM!=="dumb"&&!("CI"in process.env)&&p.isDevelopMode)}isFooterChanged(s,r){return this.#s.get(s)!==r}updateFooter(s,r){const e=!this.#s.has(s);this.#s.set(s,r),this.isInteractive()&&(e?this.#p():this.#n())}get#e(){if(this.#s.size===0)return 0;let s=g;for(const r of this.#s.values())s+=(r.match(/\n/g)||[]).length;return s}#n(){if(!this.isInteractive()||this.#s.size===0||!this.#r)return;this.#h();const s=this.#e,r=process.stderr.rows;if(!(s>r)){process.stderr.write(i),process.stderr.cursorTo(0,r-s-1),process.stderr.write(f),process.stderr.cursorTo(0,r-s+1),process.stderr.write(I());for(const e of this.#s.values())process.stderr.write(e);process.stderr.write(c)}}#p(s=0){if(!this.isInteractive())return;const r=process.stderr.rows;let e=this.#e;e>r&&(e=0);const o=e-this.#o;this.#o=e,o>0&&(process.stderr.write(i),process.stderr.write(`
4
- `.repeat(o)),process.stderr.write(c)),process.stderr.write(i),s<0&&process.stderr.write(`
5
- `.repeat(e)),process.stderr.write(h(r-e)),process.stderr.write(c),this.#n()}#h(){this.#i||!this.#r||(this.#i=!0,this.#d(),process.stderr.write(R),process.on("exit",this.#w),process.stderr.on("resize",this.#l))}#d(){if(!this.#r)return;const s=process.stderr.rows,{row:r}=this.#r,e=this.#e,o=s-e;r<o||(process.stderr.write(i),process.stderr.write(d),process.stderr.cursorTo(0,s-1),process.stderr.write(`
6
- `.repeat(Math.max(0,r-e))),process.stderr.write(h(o)),process.stderr.write(c),process.stderr.cursorTo(0,0))}#a(){if(!this.isInteractive())return;process.stdin.setRawMode(!0),process.stdin.resume(),process.stdin.setEncoding("utf8");const s=/\[(\d+);(\d+)R/;process.stdin.once("data",r=>{if(s.test(r)){const e=s.exec(r);if(e){const o=parseInt(e[1],10),a=parseInt(e[2],10);this.#r={row:o,col:a}}}process.stdin.setRawMode(!1)})}#w=()=>{this.isInteractive()&&(process.stderr.write(d),process.stderr.write(`${t}${process.stderr.rows};1H`),process.stderr.write(u))};#l=()=>{const s=process.stderr.rows-this.#t;this.#t=process.stderr.rows,this.#p(s)}}export{T as TerminalManager};
3
+ `,g=3;class E{#s=new Map;#i=process.stderr.rows;#o=0;#c=!1;#n=!1;#r;#p=!1;constructor(s=!1){this.#n=s}isInteractive(){return!!(this.#n&&process.stderr&&process.stderr.isTTY&&process.stdin.isTTY&&p.TERM!=="dumb"&&!("CI"in process.env)&&p.isDevelopMode)}isFooterChanged(s,r){return this.#s.get(s)!==r}updateFooter(s,r){const e=!this.#s.has(s);this.#s.set(s,r),this.isInteractive()&&(this.#a(),e?this.#h():this.#t())}get#e(){if(this.#s.size===0)return 0;let s=g;for(const r of this.#s.values())s+=(r.match(/\n/g)||[]).length;return s}#a(){!this.isInteractive()||this.#p||(this.#p=!0,this.#u(),process.stderr.write(u))}#t(){if(!this.isInteractive()||this.#s.size===0||!this.#r)return;this.#d();const s=this.#e,r=process.stderr.rows;if(!(s>r)){process.stderr.write(o),process.stderr.cursorTo(0,r-s-1),process.stderr.write(f),process.stderr.cursorTo(0,r-s+1),process.stderr.write(I());for(const e of this.#s.values())process.stderr.write(e);process.stderr.write(c)}}#h(s=0){if(!this.isInteractive())return;const r=process.stderr.rows;let e=this.#e;e>r&&(e=0);const i=e-this.#o;this.#o=e,i>0&&(process.stderr.write(o),process.stderr.write(`
4
+ `.repeat(i)),process.stderr.write(c)),process.stderr.write(o),s<0&&process.stderr.write(`
5
+ `.repeat(e)),process.stderr.write(h(r-e)),process.stderr.write(c),this.#t()}#d(){this.#c||!this.#r||(this.#c=!0,this.#w(),process.stderr.write(R),process.on("exit",this.#f),process.stderr.on("resize",this.#l))}#w(){if(!this.#r)return;const s=process.stderr.rows,{row:r}=this.#r,e=this.#e,i=s-e;r<i||(process.stderr.write(o),process.stderr.write(a),process.stderr.cursorTo(0,s-1),process.stderr.write(`
6
+ `.repeat(Math.max(0,r-e))),process.stderr.write(h(i)),process.stderr.write(c),process.stderr.cursorTo(0,0))}#u(){if(!this.isInteractive())return;process.stdin.setRawMode(!0),process.stdin.resume(),process.stdin.setEncoding("utf8");const s=/\[(\d+);(\d+)R/;process.stdin.once("data",r=>{if(s.test(r)){const e=s.exec(r);if(e){const i=parseInt(e[1],10),d=parseInt(e[2],10);this.#r={row:i,col:d}}}process.stdin.setRawMode(!1),process.stdin.pause(),this.#s.size>0&&this.#t()})}#f=()=>{this.isInteractive()&&(process.stderr.write(a),process.stderr.write(`${t}${process.stderr.rows};1H`),process.stderr.write(l))};#l=()=>{const s=process.stderr.rows-this.#i;this.#i=process.stderr.rows,this.#h(s)}}export{E as TerminalManager};
@@ -8,13 +8,13 @@ import type { GlobalData, Feature } from '../../../types/index.js';
8
8
  import type { SearchDocument } from '../../types';
9
9
  import type { RbacScopeItems, RedirectConfig, RedoclyConfig, ServerPropsContext, ServerPropsRequest, PageProps, PageStaticData, NavItem, ResolvedNavItem, Version, MdOptions, KvService } from '@redocly/config';
10
10
  import type { LoaderFn } from '../fs';
11
- import type { MarkdocDeps } from './markdown';
12
11
  import type { BundledDefinition } from '../../plugins/openapi-docs/load-definition';
13
12
  import type { Cache } from '../../fs/cache';
14
13
  import type { ContentFs } from '../../fs/content-fs';
15
14
  import type { SearchEngine } from '../../plugins/search/engines/search-engine';
16
15
  import type { Logger } from '../../tools/notifiers/logger.js';
17
16
  import type { AiDocumentsStore } from '../../plugins/search/types';
17
+ import type { ParseMarkdocOpts } from '../../types/plugins/markdown';
18
18
  export type ResolveItemsOptions = {
19
19
  groupCustomSidebars?: boolean;
20
20
  locale?: string;
@@ -37,7 +37,7 @@ export type GetStaticDataContext = {
37
37
  getConfig: () => RedoclyConfig;
38
38
  getAllRoutes: () => PageRouteDetails<PageStaticData, PageProps>[];
39
39
  getAllApiRoutes: () => ApiRoute[];
40
- parseMarkdoc: (input: MarkdownParseInput, context: LifecycleContext, deps?: MarkdocDeps) => Promise<{
40
+ parseMarkdoc: (opts: Omit<ParseMarkdocOpts, 'deps'>) => Promise<{
41
41
  ast: Node;
42
42
  info: Record<string, unknown>;
43
43
  compoundHash: string;
@@ -132,7 +132,7 @@ export type ProcessContentActions = {
132
132
  setGlobalConfig: (data: Record<string, unknown>) => void;
133
133
  setGlobalData: (data: GlobalData) => void;
134
134
  getConfig: () => RedoclyConfig;
135
- parseMarkdoc: (input: MarkdownParseInput, context: LifecycleContext, deps?: MarkdocDeps) => Promise<{
135
+ parseMarkdoc: (opt: ParseMarkdocOpts) => Promise<{
136
136
  ast: Node;
137
137
  info: Record<string, unknown>;
138
138
  compoundHash: string;
@@ -168,7 +168,7 @@ export type AfterRoutesCreatedActions = {
168
168
  setGlobalData: (data: GlobalData) => void;
169
169
  getGlobalData: () => GlobalData;
170
170
  setGlobalConfig: (data: Record<string, unknown>) => void;
171
- parseMarkdoc: (input: MarkdownParseInput, context: LifecycleContext, deps?: MarkdocDeps) => Promise<{
171
+ parseMarkdoc: (opts: ParseMarkdocOpts) => Promise<{
172
172
  ast: Node;
173
173
  info: Record<string, unknown>;
174
174
  compoundHash: string;
@@ -1,5 +1,5 @@
1
1
  import type { PageStaticData, REDOCLY_ROUTE_RBAC, REDOCLY_TEAMS_RBAC, RbacScopeItems } from '@redocly/config';
2
- import type { PluginDefaultOptions, PageRouteDetails, LifecycleContext, AfterRoutesCreatedActions } from '../../types';
2
+ import type { PluginDefaultOptions, PageRouteDetails, LifecycleContext, AfterRoutesCreatedActions, MarkdownParseInput } from '../../types';
3
3
  import type { LINK_ORIGINAL_ATTR_NAME } from '../../constants/common';
4
4
  export type RoutesInfoActions = {
5
5
  outdir: string;
@@ -34,4 +34,10 @@ export type MdPageStaticData = {
34
34
  export type WithOriginalAttr<T, P = string> = T & {
35
35
  [K in `${typeof LINK_ORIGINAL_ATTR_NAME}:${string}`]?: P | null;
36
36
  };
37
+ export type ParseMarkdocOpts = {
38
+ input: MarkdownParseInput;
39
+ context: LifecycleContext;
40
+ deps?: MarkdocDeps;
41
+ resource?: string;
42
+ };
37
43
  //# sourceMappingURL=markdown.d.ts.map
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Builds the markdown asset path used for `llms.txt` / AI agent flows from a route slug.
3
+ *
4
+ * The site root slug (`/`) maps to `index.html.md` so the home page resolves like other HTML routes;
5
+ * every other slug gets a `.md` suffix on the same path.
6
+ *
7
+ * @param routeSlug - URL path segment for the page (e.g. `/`, `/docs`, `/reference/petstore`)
8
+ * @returns Path to the corresponding markdown file (e.g. `/index.html.md`, `/docs.md`)
9
+ *
10
+ * @example
11
+ * getLlmsTxtMdPathBySlug('/');
12
+ * // returns '/index.html.md'
13
+ *
14
+ * @example
15
+ * getLlmsTxtMdPathBySlug('/guides/getting-started');
16
+ * // returns '/guides/getting-started.md'
17
+ */
18
+ export declare function getLlmsTxtMdPathBySlug(routeSlug: string): string;
19
+ //# sourceMappingURL=get-llms-txt-md-path-by-slug.d.ts.map
@@ -0,0 +1 @@
1
+ function d(t){return`${t}${t==="/"?"index.html.md":".md"}`}export{d as getLlmsTxtMdPathBySlug};
@@ -0,0 +1,3 @@
1
+ import type { RbacScopeItems } from '@redocly/config';
2
+ export declare function isRbacScopeItems(value: unknown): value is RbacScopeItems;
3
+ //# sourceMappingURL=is-rbac-scope-items.d.ts.map
@@ -0,0 +1 @@
1
+ function e(t){return!t||typeof t!="object"?!1:!("content"in t||"features"in t||"teamNamePatterns"in t||"teamFolders"in t)}export{e as isRbacScopeItems};
@@ -1 +1 @@
1
- import R from"path";import x from"picomatch";import"../node-crypto-polyfill.js";import{REDOCLY_TEAMS_RBAC as _,REDOCLY_ROUTE_RBAC as A}from"@redocly/config";import{DEFAULT_ANONYMOUS_VISITOR_TEAM as O,ServerRoutes as w,PUBLIC_RBAC_SCOPE_ITEM as y,RBAC_ALL_OTHER_TEAMS as u,DEFAULT_RBAC_SCOPE as S}from"../../constants/common.js";import{DEPRECATED_PUBLIC_API_DEFINITIONS_FOLDER as I,PUBLIC_API_DEFINITIONS_FOLDER as C,PUBLIC_ASSETS_FOLDER as N}from"../constants/common.js";import{removeTrailingSlash as B}from"../../utils/url/remove-trailing-slash.js";import{removeLeadingSlash as k}from"../../utils/url/remove-leading-slash.js";import{parsePathVersions as M}from"../../utils/path/parse-path-versions.js";import{reporter as W}from"../tools/notifiers/reporter.js";import{bold as U}from"../tools/notifiers/helpers/colors.js";import{shaDirPathShort as $}from"../utils/crypto/sha-dir-path-short.js";import{isTruthy as b}from"../../utils/guards/is-truthy.js";import{canExpandConfig as v,expandRbacConfig as Y,getTeamFolderDefaults as z,parseTeamFoldersTemplate as H,parseTeamNameTemplate as K}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 j=["NONE","READ","TRIAGE","WRITE","MAINTAIN","ADMIN"],Q=new Set(["x-parsed-md-description","x-parsed-md-summary"]);function yt(t,e){const n=j.indexOf(t.toUpperCase()),r=j.indexOf(e.toUpperCase());return n>r?t:e}const E={};function P(t,e){if(!t?.content)return y;const n=t.content,{slug:r,fsPath:s}=e;if(!r&&!s)return y;const o=f=>{const h=`slug:${f}`,m=E[h]??x(f);E[h]=m;const g=`fsPath:${f}`,L=E[g]??x(k(f));return E[g]=L,!!(r&&m(r))||!!(s&&L(s))};if(X(r||s||"")&&Object.keys(n).filter(m=>o(m)).length===0)return n[S]||y;const c=Object.keys(n).filter(f=>o(f));if(c.length==0)return y;const l=c.map(f=>x.scan(f,{tokens:!0,parts:!0}));let p=l[0];for(let f=1;f<l.length;f++)p=V(p,l[f]);return n[p.input]}function Et(t,e,n={},r=!1){if(r&&Object.keys(n).length===0)return e.isAuthenticated;const s=n.features?.[t];return s?e.teams.some(o=>s[o]&&s[o].toLowerCase()!=="none"):!0}function Pt(t,e){return T(t,{isAuthenticated:!1,teams:[O]},e.rbac||{},e.requiresLogin||!1)}function T(t,e={},n={},r=!1){if(t.slug&&typeof t.slug=="string"&&Object.values(w).some(c=>{const l=c.split(":")[0].replace(/\/$/,"");return t.slug===l||t.slug?.startsWith(c)})||typeof t.slug=="string"&&t.slug?.endsWith("/mcp")&&J.instance().canAccessFeature("mcp"))return!0;if(r&&Object.keys(n).length===0)return!!e.isAuthenticated;const s=Y(n,e.teams||[]),o=t[_]||P(s,t[A]||{});if(Object.keys(o||{}).length===0)return!1;if(Object.keys(o).length===1&&o[u]&&o[u].toLowerCase()!=="none")return!0;const a=(e?.email?[...e?.teams||[],e?.email]:e?.teams)||[],i=[];for(const c of a??[])o[c]?i.push(o[c]):o[u]&&c!==e?.email&&i.push(o[u]);return i.length?i.some(c=>c.toLowerCase()!=="none"):!1}function Tt(t,e,n,r){if(!t.startsWith(C)&&!t.startsWith(I))return!0;const s=t.replace(new RegExp(`^${C}/`),"").replace(new RegExp(`^${I}/`),""),a=s==="."?"":s,i={[A]:{slug:t,fsPath:a},slug:t};return T(i,r,e,n)}function xt(t,e,n,r,s){if(!t.startsWith(N))return!0;const o=t.match(/.*\..{64}\.([A-Fa-f0-9]{8})\.[^\.]+$/)?.[1];if(!o)return!0;const a=r[o];if(!a)return!0;const{base:i,ext:c}=R.parse(t),l=i.split(".")[0],p=c.split(".").join(""),h=a==="."?"":a,m={[A]:{slug:t,fsPath:R.posix.join(h,`${l}.${p}`)},slug:t};return T(m,s,e,n)}async function Ot(t,e){const{isAuthenticated:n=!1,idpAccessToken:r,federatedAccessToken:s,federatedIdToken:o,...a}=await G(t,e),{teams:i=[]}=a;let c;return n?c=i.filter(l=>l!==O):c=[O],{isAuthenticated:n,idpAccessToken:r,teams:c,claims:a}}function F(t,e,n={},r=!1){if(!t)return t;if(Array.isArray(t)){const s=[];for(const o of t){const a=F(o,e,n,r);a!==void 0&&s.push(a)}return s}if(typeof t=="object"){if(!T(t,e,n,r))return;let s=!1;const o={};for(const a in t){if(a===_||a===A)continue;if(Q.has(a)){o[a]=t[a];continue}const i=F(t[a],e,n,r);if(a==="items"&&Array.isArray(i)&&i.length===0&&t[a].length!==0){s=!0;continue}i!==void 0&&(o[a]=i)}return s?void 0:o}return t}function Dt(t){return typeof t=="string"?t.split(" ").filter(Boolean):Array.isArray(t)?t.map(e=>e.toString()):[]}function gt(t,e){if(!e)return;const n=e.content;if(!n)return e;const r=Object.entries(n).flatMap(([o,a])=>o===S?[[o,a]]:[[o,a],...t.localeFolders.map(i=>[o.startsWith("/")?`/${i.toLocaleLowerCase()}${o}`:R.posix.join(t.localizationFolder,i,o),a])]),s=Object.fromEntries(r);return{...e,content:s}}async function Lt(t,e){if(!e)return{};const n={},r=new Set((await t.scan()).flatMap(({relativePath:s})=>{const{versionFolderPath:o}=M(s)||{},a=R.dirname(s);return o?[o,a]:a}));for(const s of r)n[$(s)]=s;return n}const d=t=>typeof t=="object"&&t!==null&&!Array.isArray(t);function X(t){return t?t.split("/").filter(Boolean).some(n=>n.startsWith(".")):!1}const Z=t=>{if(t&&d(t)&&("content"in t&&d(t.content)||"reunite"in t&&d(t.reunite)||"features"in t&&d(t.features)||t.teamFolders&&t.teamNamePatterns)){const e=Object.values(t.content||{});if(e.length===0)return!0;if(e.every(d))return e.every(n=>Object.values(n).every(r=>typeof r=="string"))}return!1},_t=async t=>{if(t){if(Object.keys(t).length===0)return{};if(Z(t))return q(t);await W.panicOnContentError(`You are using an incorrect format of ${U("rbac:")} configuration. See: https://redocly.com/docs/realm/access`)}},q=t=>{const e={...t};if(e.content){const n={};for(const r in e.content)if(e.content[r]!==void 0){const s=B(r);n[s]=e.content[r]}e.content=n}return e};function St(t,e){const n=t.fsPath,r=t.slug,s=[];if(v(e)&&(n||r)){const o=[n,r].filter(b),a=H(e,o);if(a){const i=e?.teamNamePatterns?.map(l=>l.replace("{teamPathSegment}",a.teamPathSegment).replace("{projectRole}","read"))??[];s.push(...i);const c=P({content:{...z(e),...e.content}},t);s.push(...D(c))}else{const i=P(e,t);s.push(...D(i))}}else{const o=P(e,t);s.push(...D(o))}return tt(e,s)}function D(t){if(!t)return[];const e=[],n=u in t?{authenticated:t[u],anonymous:t[u]}:{};for(const[r,s]of Object.entries({...n,...t}))s.toLowerCase()!=="none"&&r!==u&&e.push(r);return e}function tt(t,e){return e.map(r=>K(t,r)??{teamName:r}).map(r=>r.projectRole&&r.projectRole!=="READ"?r.teamName?.toLowerCase().replace(r.projectRole?.toLowerCase?.()??"","read")??"":r.teamName?.toLowerCase()??"")}export{j as PROJECT_ROLES_ORDERED_BY_ACCESS_LEVEL,gt as applyL10nToRbacConfig,xt as canAccessAsset,Et as canAccessFeature,T as canAccessResource,Tt as canDownloadApiDefinition,tt as expandTeamsForRead,D as extractTeamsFromScopeItems,F as filterDataByAccessDeep,Ot as getAuthDetailsFromCookies,yt as getHigherRole,St as getRbacTeamsListForResource,P as getScopeItemsForResource,Z as isRbacConfigValid,Pt as isResourcePubliclyAccessible,q as normalizeRbacConfig,_t as parseRbacConfig,Dt as parseTeamClaimToArray,Lt as resolveDirectoryHashes};
1
+ import R from"path";import x from"picomatch";import"../node-crypto-polyfill.js";import{REDOCLY_TEAMS_RBAC as _,REDOCLY_ROUTE_RBAC as A}from"@redocly/config";import{DEFAULT_ANONYMOUS_VISITOR_TEAM as O,ServerRoutes as w,PUBLIC_RBAC_SCOPE_ITEM as y,RBAC_ALL_OTHER_TEAMS as u,DEFAULT_RBAC_SCOPE as S}from"../../constants/common.js";import{DEPRECATED_PUBLIC_API_DEFINITIONS_FOLDER as I,PUBLIC_API_DEFINITIONS_FOLDER as C,PUBLIC_ASSETS_FOLDER as N}from"../constants/common.js";import{removeTrailingSlash as B}from"../../utils/url/remove-trailing-slash.js";import{removeLeadingSlash as k}from"../../utils/url/remove-leading-slash.js";import{parsePathVersions as M}from"../../utils/path/parse-path-versions.js";import{reporter as W}from"../tools/notifiers/reporter.js";import{bold as U}from"../tools/notifiers/helpers/colors.js";import{shaDirPathShort as $}from"../utils/crypto/sha-dir-path-short.js";import{isTruthy as b}from"../../utils/guards/is-truthy.js";import{canExpandConfig as v,expandRbacConfig as Y,getTeamFolderDefaults as z,parseTeamFoldersTemplate as H,parseTeamNameTemplate as K}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 j=["NONE","READ","TRIAGE","WRITE","MAINTAIN","ADMIN"],Q=new Set(["x-parsed-md-description","x-parsed-md-summary"]);function yt(t,e){const n=j.indexOf(t.toUpperCase()),r=j.indexOf(e.toUpperCase());return n>r?t:e}const E={};function P(t,e){if(!t?.content)return y;const n=t.content,{slug:r,fsPath:s}=e;if(!r&&!s)return y;const o=f=>{const h=`slug:${f}`,m=E[h]??x(f);E[h]=m;const g=`fsPath:${f}`,L=E[g]??x(k(f));return E[g]=L,!!(r&&m(r))||!!(s&&L(s))};if(X(r||s||"")&&Object.keys(n).filter(m=>o(m)).length===0)return n[S]||y;const c=Object.keys(n).filter(f=>o(f));if(c.length==0)return y;const l=c.map(f=>x.scan(f,{tokens:!0,parts:!0}));let p=l[0];for(let f=1;f<l.length;f++)p=V(p,l[f]);return n[p.input]}function Et(t,e,n={},r=!1){if(r&&Object.keys(n).length===0)return e.isAuthenticated;const s=n.features?.[t];return s?e.teams.some(o=>s[o]&&s[o].toLowerCase()!=="none"):!0}function Pt(t,e){return T(t,{isAuthenticated:!1,teams:[O]},e.access?.rbac||{},e.access?.requiresLogin||!1)}function T(t,e={},n={},r=!1){if(t.slug&&typeof t.slug=="string"&&Object.values(w).some(c=>{const l=c.split(":")[0].replace(/\/$/,"");return t.slug===l||t.slug?.startsWith(c)})||typeof t.slug=="string"&&t.slug?.endsWith("/mcp")&&J.instance().canAccessFeature("mcp"))return!0;if(r&&Object.keys(n).length===0)return!!e.isAuthenticated;const s=Y(n,e.teams||[]),o=t[_]||P(s,t[A]||{});if(Object.keys(o||{}).length===0)return!1;if(Object.keys(o).length===1&&o[u]&&o[u].toLowerCase()!=="none")return!0;const a=(e?.email?[...e?.teams||[],e?.email]:e?.teams)||[],i=[];for(const c of a??[])o[c]?i.push(o[c]):o[u]&&c!==e?.email&&i.push(o[u]);return i.length?i.some(c=>c.toLowerCase()!=="none"):!1}function Tt(t,e,n,r){if(!t.startsWith(C)&&!t.startsWith(I))return!0;const s=t.replace(new RegExp(`^${C}/`),"").replace(new RegExp(`^${I}/`),""),a=s==="."?"":s,i={[A]:{slug:t,fsPath:a},slug:t};return T(i,r,e,n)}function xt(t,e,n,r,s){if(!t.startsWith(N))return!0;const o=t.match(/.*\..{64}\.([A-Fa-f0-9]{8})\.[^\.]+$/)?.[1];if(!o)return!0;const a=r[o];if(!a)return!0;const{base:i,ext:c}=R.parse(t),l=i.split(".")[0],p=c.split(".").join(""),h=a==="."?"":a,m={[A]:{slug:t,fsPath:R.posix.join(h,`${l}.${p}`)},slug:t};return T(m,s,e,n)}async function Ot(t,e){const{isAuthenticated:n=!1,idpAccessToken:r,federatedAccessToken:s,federatedIdToken:o,...a}=await G(t,e),{teams:i=[]}=a;let c;return n?c=i.filter(l=>l!==O):c=[O],{isAuthenticated:n,idpAccessToken:r,teams:c,claims:a}}function F(t,e,n={},r=!1){if(!t)return t;if(Array.isArray(t)){const s=[];for(const o of t){const a=F(o,e,n,r);a!==void 0&&s.push(a)}return s}if(typeof t=="object"){if(!T(t,e,n,r))return;let s=!1;const o={};for(const a in t){if(a===_||a===A)continue;if(Q.has(a)){o[a]=t[a];continue}const i=F(t[a],e,n,r);if(a==="items"&&Array.isArray(i)&&i.length===0&&t[a].length!==0){s=!0;continue}i!==void 0&&(o[a]=i)}return s?void 0:o}return t}function Dt(t){return typeof t=="string"?t.split(" ").filter(Boolean):Array.isArray(t)?t.map(e=>e.toString()):[]}function gt(t,e){if(!e)return;const n=e.content;if(!n)return e;const r=Object.entries(n).flatMap(([o,a])=>o===S?[[o,a]]:[[o,a],...t.localeFolders.map(i=>[o.startsWith("/")?`/${i.toLocaleLowerCase()}${o}`:R.posix.join(t.localizationFolder,i,o),a])]),s=Object.fromEntries(r);return{...e,content:s}}async function Lt(t,e){if(!e)return{};const n={},r=new Set((await t.scan()).flatMap(({relativePath:s})=>{const{versionFolderPath:o}=M(s)||{},a=R.dirname(s);return o?[o,a]:a}));for(const s of r)n[$(s)]=s;return n}const d=t=>typeof t=="object"&&t!==null&&!Array.isArray(t);function X(t){return t?t.split("/").filter(Boolean).some(n=>n.startsWith(".")):!1}const Z=t=>{if(t&&d(t)&&("content"in t&&d(t.content)||"reunite"in t&&d(t.reunite)||"features"in t&&d(t.features)||t.teamFolders&&t.teamNamePatterns)){const e=Object.values(t.content||{});if(e.length===0)return!0;if(e.every(d))return e.every(n=>Object.values(n).every(r=>typeof r=="string"))}return!1},_t=async t=>{if(t){if(Object.keys(t).length===0)return{};if(Z(t))return q(t);await W.panicOnContentError(`You are using an incorrect format of ${U("rbac:")} configuration. See: https://redocly.com/docs/realm/access`)}},q=t=>{const e={...t};if(e.content){const n={};for(const r in e.content)if(e.content[r]!==void 0){const s=B(r);n[s]=e.content[r]}e.content=n}return e};function St(t,e){const n=t.fsPath,r=t.slug,s=[];if(v(e)&&(n||r)){const o=[n,r].filter(b),a=H(e,o);if(a){const i=e?.teamNamePatterns?.map(l=>l.replace("{teamPathSegment}",a.teamPathSegment).replace("{projectRole}","read"))??[];s.push(...i);const c=P({content:{...z(e),...e.content}},t);s.push(...D(c))}else{const i=P(e,t);s.push(...D(i))}}else{const o=P(e,t);s.push(...D(o))}return tt(e,s)}function D(t){if(!t)return[];const e=[],n=u in t?{authenticated:t[u],anonymous:t[u]}:{};for(const[r,s]of Object.entries({...n,...t}))s.toLowerCase()!=="none"&&r!==u&&e.push(r);return e}function tt(t,e){return e.map(r=>K(t,r)??{teamName:r}).map(r=>r.projectRole&&r.projectRole!=="READ"?r.teamName?.toLowerCase().replace(r.projectRole?.toLowerCase?.()??"","read")??"":r.teamName?.toLowerCase()??"")}export{j as PROJECT_ROLES_ORDERED_BY_ACCESS_LEVEL,gt as applyL10nToRbacConfig,xt as canAccessAsset,Et as canAccessFeature,T as canAccessResource,Tt as canDownloadApiDefinition,tt as expandTeamsForRead,D as extractTeamsFromScopeItems,F as filterDataByAccessDeep,Ot as getAuthDetailsFromCookies,yt as getHigherRole,St as getRbacTeamsListForResource,P as getScopeItemsForResource,Z as isRbacConfigValid,Pt as isResourcePubliclyAccessible,q as normalizeRbacConfig,_t as parseRbacConfig,Dt as parseTeamClaimToArray,Lt as resolveDirectoryHashes};
@@ -0,0 +1,2 @@
1
+ export declare function highlightTextForSearch(query: string, text: string): string;
2
+ //# sourceMappingURL=highlight-text-for-search.d.ts.map
@@ -0,0 +1 @@
1
+ import{HIGHLIGHTED_TEXT_MAX_LENGTH as a}from"../../constants/plugins/search.js";function L(n,g){const p=n.split(/\s+/g),d=t=>t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),e=p.reduce((t,h)=>{if(!h||!t?.replace)return t;const u=new RegExp(`(^|\\s)${d(h)}`,"gi");return t.replace(u,(l,H,x,k)=>{const m=k.substring(0,x),T=(m.match(/<mark>/g)??[]).length,$=(m.match(/<\/mark>/g)??[]).length;return T>$?l:`<mark>${l}</mark>`})},g);if(!e)return g||"";if(e.replace(/<mark>/g,"").replace(/<\/mark>/g,"").length<a)return e;const s=e.indexOf("<mark>"),i=e.indexOf("</mark>")+7,r=a/2+n.length/2,o=s<r,c=i+r<e.length,f=e.substring(o?0:s-r,c?i+r:e.length);return`${o?"":"..."}${f}${c?"...":""}`}export{L as highlightTextForSearch};
@@ -1 +1 @@
1
- import{TrieRouter as q}from"hono/router/trie-router";import{REDOCLY_ROUTE_RBAC as c}from"@redocly/config";import{withPathPrefix as C}from"@redocly/theme/core/utils";import{canAccessResource as L}from"../../../utils/rbac.js";import{handleUnauthorizedApiRequest as U}from"../../utils.js";import{handleApiRouteRequest as P}from"../../handle-api-route-request.js";import{sortApiFunctionRoutes as w}from"../../utils/sort-api-function-routes.js";function B(u,t){u.all("*",async(o,a)=>{const{method:m,path:e}=o.req,p=t.getAllApiRoutes(),h=w(p),i=new q;for(const n of h){const A=n.httpMethod?.toUpperCase()||"ALL",g=C(n.slug);i.add(A,g,n)}const s=i.match(m.toUpperCase(),e);if(!s||s[0].length===0)return a();const l=s[0],[r]=l[0],{isAuthenticated:R,claims:{email:f},teams:d}=o.get("auth");return L({...r,slug:e,[c]:{...r[c],slug:e}},{isAuthenticated:R,email:f,teams:d},t.config.rbac,t.config.requiresLogin)?P(r,o,t):U(o)})}export{B as installApiRoutes};
1
+ import{TrieRouter as q}from"hono/router/trie-router";import{REDOCLY_ROUTE_RBAC as i}from"@redocly/config";import{withPathPrefix as C}from"@redocly/theme/core/utils";import{canAccessResource as L}from"../../../utils/rbac.js";import{handleUnauthorizedApiRequest as U}from"../../utils.js";import{handleApiRouteRequest as P}from"../../handle-api-route-request.js";import{sortApiFunctionRoutes as w}from"../../utils/sort-api-function-routes.js";function B(a,t){a.all("*",async(e,u)=>{const{method:m,path:o}=e.req,p=t.getAllApiRoutes(),h=w(p),c=new q;for(const n of h){const A=n.httpMethod?.toUpperCase()||"ALL",g=C(n.slug);c.add(A,g,n)}const s=c.match(m.toUpperCase(),o);if(!s||s[0].length===0)return u();const l=s[0],[r]=l[0],{isAuthenticated:R,claims:{email:f},teams:d}=e.get("auth");return L({...r,slug:o,[i]:{...r[i],slug:o}},{isAuthenticated:R,email:f,teams:d},t.config.access?.rbac,t.config.access?.requiresLogin)?P(r,e,t):U(e)})}export{B as installApiRoutes};
@@ -1 +1 @@
1
- import{CACHE_CONTROL_NO_CACHE_HEADER_VALUE as o}from"../../constants/common.js";import{filterDataByAccessDeep as c}from"../../utils/rbac.js";function f(a){return async t=>{const{isAuthenticated:e,teams:n,claims:{email:r}}=t.get("auth"),i=c(a.getGlobalData(),{isAuthenticated:e,email:r,teams:n},a.config.rbac,a.config.requiresLogin);return t.json({...i},200,{"Cache-Control":o})}}export{f as appDataHandler};
1
+ import{CACHE_CONTROL_NO_CACHE_HEADER_VALUE as i}from"../../constants/common.js";import{filterDataByAccessDeep as o}from"../../utils/rbac.js";function f(a){return async e=>{const{isAuthenticated:t,teams:c,claims:{email:n}}=e.get("auth"),r=o(a.getGlobalData(),{isAuthenticated:t,email:n,teams:c},a.config.access?.rbac,a.config.access?.requiresLogin);return e.json({...r},200,{"Cache-Control":i})}}export{f as appDataHandler};
@@ -1 +1 @@
1
- import{RbacFeatures as p}from"../../../constants/common.js";import{ASK_AI_API_URL as r}from"../../constants/common.js";import{canAccessFeature as u}from"../../utils/rbac.js";import{handleUnauthorizedApiRequest as f}from"../utils.js";import{isAiSearchEnabled as h}from"../../plugins/search/utils.js";function C(a){return async e=>{if(!r)return e.newResponse(null,404);const t=a.getConfig();if(!h(t))return e.newResponse(null,403,{});const o=e.get("auth");if(!u(p.AI_SEARCH,o,t.rbac,t.requiresLogin))return f(e);const i={"Content-Type":"application/json"},n=[];o.claims?.authCookie&&n.push(`authorization=${o.claims.authCookie}`),o.idpAccessToken&&n.push(`accessToken=${o.idpAccessToken}`),n.length>0&&(i.Cookie=n.join("; "));const c=await e.req.json(),s=await fetch(r,{method:"POST",body:JSON.stringify(c),headers:i});return s.ok?e.newResponse(s.body,200,{"Content-Type":"text/event-stream"}):e.newResponse(s.body,s.status,{"Content-Type":"application/json"})}}export{C as askAiHandler};
1
+ import{RbacFeatures as p}from"../../../constants/common.js";import{ASK_AI_API_URL as r}from"../../constants/common.js";import{canAccessFeature as u}from"../../utils/rbac.js";import{handleUnauthorizedApiRequest as f}from"../utils.js";import{isAiSearchEnabled as h}from"../../plugins/search/utils.js";function C(a){return async e=>{if(!r)return e.newResponse(null,404);const t=a.getConfig();if(!h(t))return e.newResponse(null,403,{});const o=e.get("auth");if(!u(p.AI_SEARCH,o,t.access?.rbac,t.access?.requiresLogin))return f(e);const i={"Content-Type":"application/json"},n=[];o.claims?.authCookie&&n.push(`authorization=${o.claims.authCookie}`),o.idpAccessToken&&n.push(`accessToken=${o.idpAccessToken}`),n.length>0&&(i.Cookie=n.join("; "));const c=await e.req.json(),s=await fetch(r,{method:"POST",body:JSON.stringify(c),headers:i});return s.ok?e.newResponse(s.body,200,{"Content-Type":"text/event-stream"}):e.newResponse(s.body,s.status,{"Content-Type":"application/json"})}}export{C as askAiHandler};
@@ -1,11 +1,12 @@
1
1
  import type { Context, Handler } from 'hono';
2
2
  import type { Store } from '../../store.js';
3
+ import { ServerRoutes } from '../../../constants/common.js';
3
4
  export declare function authorizeHandler(ctx: Context): Promise<Response>;
4
5
  export declare function redoclyLoginCallbackHandler(): Handler;
5
6
  export declare function oidcCallbackHandler(store: Store): Handler;
6
7
  export declare function logoutHandler(store: Store): (ctx: Context) => Promise<Response>;
7
8
  export declare function postLogoutHandler(store: Store): (ctx: Context) => Promise<Response>;
8
- export declare function inviteHandler(store: Store): (ctx: Context) => Promise<Response>;
9
+ export declare function inviteHandler(store: Store): (ctx: Context<Record<string, unknown>, typeof ServerRoutes.INVITE>) => Promise<Response>;
9
10
  export declare function idpLoginHandler(store: Store): (ctx: Context) => Promise<Response>;
10
11
  export declare function samlCallbackHandler(store: Store): Handler;
11
12
  export declare function redoclyTokenLoginHandler(store: Store): Handler;
@@ -1 +1 @@
1
- import{setCookie as _,deleteCookie as q}from"hono/cookie";import{AuthProviderType as W}from"@redocly/config";import{withPathPrefix as I,getPathPrefix as R}from"@redocly/theme/core/utils";import{compareURIs as Y}from"../../../utils/url/compare-uris.js";import{ensureArray as b}from"../../../utils/array/ensure-array.js";import{ALTERNATIVE_AUD_CLAIM_NAME as F,JWT_SECRET_KEY as v,ORG_SLUG as Q,ORG_ID as Z}from"../../constants/common.js";import{DEFAULT_COOKIE_EXPIRATION as B,ServerRoutes as S}from"../../../constants/common.js";import{sanitizeRedirectPathname as z}from"../../../utils/url/sanitize-redirect-pathname.js";import{telemetry as M}from"../../telemetry/index.js";import{envConfig as H}from"../../config/env-config.js";import{getAuthProviderLoginParams as x,isOidcProviderConfig as $,isSaml2ProviderConfig as ee,oidcExchangeCodeForToken as re,buildLoginUrl as oe,decodeSamlResponse as ne,extractUserClaims as te,parseSamlResponse as ie,parseOidcState as se,verifySAMLResponse as ae,getUsernameFromPayload as de,buildOidcLogoutUrl as ce,getOidcMetadata as j,getRedoclyTokenPayload as le,isRedoclySso as ue,rewritePreviewAuthRedirectUri as pe,parsePreviewBranch as N,buildOidcLoginUrl as ge,createMcpSessionResource as k}from"../auth.js";import*as O from"../jwt/jwt.js";import{AlgorithmTypes as P}from"../jwt/types.js";import{handleErrorPageRender as fe}from"../utils.js";import{encodeBase64URL as me}from"../jwt/encode.js";async function ve(i){if(H.isProductionEnv)return i.newResponse(null,404,{});const{password:e,...r}=await i.req.json(),a=await O.sign({...r,name:r.username||r.email||"Unknown"},v,P.HS256);return _(i,"authorization",a,{path:R()||"/",httpOnly:!0,secure:!0,sameSite:"none"}),i.newResponse(null,200,{})}function $e(){return async i=>{const e=i.get("logger"),r=encodeURIComponent(i.req.query("message")||"");e.error(`Login error: ${r}`);const a=`${S.LOGIN}/?error=${encodeURIComponent(r)}`;return i.newResponse(null,301,{Location:a})}}function K(i){if(!i||!i.includes(S.MCP_CALLBACK))return null;try{const e=i.split("/"),r=e[e.length-1];if(r){const a=Buffer.from(r,"base64url").toString("utf-8");return JSON.parse(a).mcpSessionId||null}}catch{}return null}function Ue(i){return async e=>{const r=e.get("logger"),a=i.getConfig().ssoDirect,n=se(e.req.query("state")),f=n.idpId,t=n.source==="mcp"||n.redirectTo&&typeof n.redirectTo=="string"&&n.redirectTo.includes(S.MCP_CALLBACK),c=t?K(typeof n.redirectTo=="string"?n.redirectTo:void 0):null,s=a?.[f];if(!$(s))return r.error("OIDC login error: missing OIDC provider config"),e.text("Forbidden",403);const d=await j(f,s);if(a&&!d.token_endpoint){const p="Invalid OIDC configuration: token_endpoint is required";return r.error(`OIDC login error: ${p}`),e.text(p,500)}try{const p=d.token_endpoint,l=e.req.query("code"),m=e.req.query("error");if(m)return t&&M.sendMcpAuthorizationFailedMessage([{...k(c),error:`OIDC error: ${m}`,error_details:e.req.query("error_description")||null}]),fe(e,i,{slug:"/"},403,"403OIDC");if(!l){const w="Code is expected but not present";return r.error(`OIDC login error: ${w}`),t&&M.sendMcpAuthorizationFailedMessage([{...k(c),error:w,error_details:null}]),new Response(`Forbidden: ${w}`,{status:403})}const h=e.req.header("x-forwarded-host"),g=e.req.header("x-forwarded-proto")||"https",A=t&&typeof n.redirectUri=="string"?n.redirectUri:new URL(I(S.OIDC_CALLBACK),h?`${g}://${h}`:e.req.url).toString(),C=e.get("cookies")?.code_verifier,u=await re(p,l,A,s,{...s.tokenRequestCustomParams,...C?{code_verifier:C}:{}});if(u.error)return r.error(`Error from OIDC provider: "${u.error}"`),t&&M.sendMcpAuthorizationFailedMessage([{...k(c),error:`Token exchange error: ${u.error}`,error_details:u.error_description||null}]),e.text(`Forbidden: ${u.error_description||u.error}`,403);if(!u?.id_token){const w="No id_token, please, add openid to scopes";return r.error(`OIDC login error: ${w}`),t&&M.sendMcpAuthorizationFailedMessage([{...k(c),error:w,error_details:null}]),new Response(`Forbidden: ${w}`,{status:403})}const{payload:o,header:U}=O.decode(u.id_token),J=U.alg===P.RS256;if(s.audience?.length&&![...b(o.aud||[]),...b(o[F]||[])].some(L=>s.audience?.includes(L))){const L="No valid audience found in id_token";return r.error(`OIDC login error: ${L}`),t&&M.sendMcpAuthorizationFailedMessage([{...k(c),error:L,error_details:null}]),new Response(`Forbidden: ${L}`)}const E=J?u.id_token:await O.sign({...o,idpId:f},v,P.HS256);de(o)||r.warn("To display your username, the required 'email' or 'full_profile' scope must be added to the identity provider configuration");const D=s?.tokenExpirationTime?Date.now()+s.tokenExpirationTime*1e3:o.exp*1e3||Date.now()+B*1e3;if(s.introspectEndpoint){const w=await fetch(s.introspectEndpoint,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({access_token:u.access_token})});if(w.ok){const T=(await w.json()).ext?.federatedIdentity;T&&(_(e,"federated_access_token",T.access_token||"",{path:R()||"/",httpOnly:!1,expires:new Date(D)}),_(e,"federated_id_token",T.id_token||"",{path:R()||"/",httpOnly:!1,expires:new Date(D)}))}else r.warn(`OIDC introspect error: ${w.statusText}`)}if(_(e,"authorization",E,{path:R()||"/",httpOnly:!0,expires:new Date(D)}),E!==u.id_token&&_(e,"idp_id_token",u.id_token||"",{path:R()||"/",httpOnly:!0,expires:new Date(D)}),_(e,"idp_access_token",u.access_token||"",{path:R()||"/",httpOnly:!0,expires:new Date(D)}),q(e,"code_verifier",{path:R()||"/"}),t&&n.redirectTo&&typeof n.redirectTo=="string"&&n.redirectTo.includes(S.MCP_CALLBACK)){const L=`${e.req.url.split("?")[0].replace(S.OIDC_CALLBACK,"")}${n.redirectTo}`;return e.newResponse(null,302,{Location:L})}const G=typeof n.redirectTo=="string"?n.redirectTo:void 0;let V=z(new URL(G||"/",e.req.url).pathname);const X=e.newResponse(null,302,{Location:V});return r.updateContext({email:o.email,subject:o.sub}),r.info("OIDC login successful"),X}catch(p){const l=p instanceof Error?p.message:String(p),m=p instanceof Error?p.stack:String(p);if(r.error(`OIDC login error: ${l}`),t&&M.sendMcpAuthorizationFailedMessage([{...k(c),error:l,error_details:m}]),p.error==="access_denied")return r.info("Access denied"),e.text("Forbidden",403)}const y="Something went wrong";return r.error(`OIDC login error: ${y}`),t&&M.sendMcpAuthorizationFailedMessage([{...k(c),error:y,error_details:null}]),e.text(y,500)}}function Te(i){return async e=>{const r=e.get("logger"),n=e.get("auth").claims?.idpId,t=i.getConfig().ssoDirect?.[n];if(e.req.method==="POST")return $(t)||q(e,"authorization",{path:R()||"/"}),r.info("Logout successful"),e.newResponse(null,200,{});let c;if($(t)){const s=(await j(n,t)).end_session_endpoint;if(s){const d=new URL(e.req.url),y=e.req.header("x-forwarded-proto")||d.protocol.slice(0,-1)||"https",p=e.req.header("x-forwarded-host")||d.host,l=`${y}://${p}`,m=N(l),h=m?me(JSON.stringify({branch:N(l)})):void 0,g=m?`${pe(l)}/_auth/logout`:`${l}/post-logout`;c=ce(s,g,e.get("cookies")?.idp_id_token||e.get("cookies")?.authorization||"",h)}}return r.info("Logout successful"),q(e,"authorization",{path:R()||"/"}),e.newResponse(null,302,{Location:c||I("/")})}}function qe(i){return async e=>{const r=i.getConfig().logoutReturnUrl,a=r||I("/");return e.newResponse(null,302,{Location:a})}}function be(i){return async e=>{const r=e.get("logger"),a=e.req.param("code"),n=H.BH_API_URL,f=(t,c,s)=>t&&c?`${t} ${c.charAt(0)}`:s;try{if(!n)throw new Error("BH_API_URL is not set");const t=i.getConfig().ssoDirect;if(!t||!Object.keys(t).length)return r.warn("Invite no sso configured to handle"),e.redirect(I("/"));const c=await fetch(`${n}/user-invites/public/${a}`);if(!c.ok)return c.status===404?(r.warn(`Invite ${a} not found redirect to homepage`),e.redirect(I("/"))):(r.error("Invite error",await c.text()),e.redirect(I("/")));const s=await c.json(),d=new URL(I("/invite"),e.req.url);return d.searchParams.set("code",a),d.searchParams.set("org",s.organization.name),d.searchParams.set("invitedBy",f(s.invitedBy.firstName,s.invitedBy.lastName,s.invitedBy.name)),e.newResponse(null,302,{Location:d.toString()})}catch(t){return r.error("Error processing invite",{error:t,inviteCode:a}),e.text(t.message||"Failed to process invite",400)}}}function Ee(i){return async e=>{const r=e.get("logger"),a=i.getConfig().ssoDirect,n=new URL(e.req.url),f=e.req.query("inviteCode"),t=e.req.header("x-forwarded-proto")||n.protocol.slice(0,-1)||"https",c=e.req.header("x-forwarded-host")||n.host,s=`${t}://${c}`;let d=n.searchParams.get("idpId");const y=n.searchParams.get("redirectTo"),p=Object.keys(a||{})[0];d=d||p;const l=n.searchParams.get("mcp_redirect_uri"),m=!!l;if(!a?.[d]){const o="Invalid idpId";if(r.error(`IdP login error: ${o}`),m){const U=K(y||void 0);M.sendMcpAuthorizationFailedMessage([{...k(U),error:o,error_details:null}])}return e.text(`Forbidden: ${o}`,403)}const g=d&&a?await x(d,a[d]):void 0,A={};for(const o of Object.keys(g?.extraParams||{}))A[o]=n.searchParams.get(o)||g?.extraParams?.[o]||void 0;let C,u={};if(m&&l&&g&&g.type===W.OIDC){r.info(`Building MCP OAuth login URL with redirect_uri: ${l}`);const o=ge("",{...g,extraParams:A},y,f,{redirectUriOverride:l,sourceOverride:"mcp",branchOverride:void 0});C=o.loginUrl,u=o.cookies||{}}else if(g){const o=oe({...g,extraParams:A},s,y,f);C=o.loginUrl,u=o.cookies||{}}return Object.keys(u).forEach(o=>{_(e,o,u[o].value,u[o].options)}),r.info(`IdP login initiated for ID '${d}'`),e.newResponse(null,302,{Location:C||new URL(e.req.url).pathname})}}function Fe(i){return async e=>{const r=e.get("logger"),a=await e.req.formData(),n=a.get("SAMLResponse"),f=a.get("RelayState");if(typeof n!="string"||typeof f!="string"){const o="SAMLResponse is required";return r.error(`SAML2 login error: ${o}`),e.text(`Bad request: ${o}`,400)}const t=ne(n),{success:c,uid:s,nameFormat:d,attrs:y,issuerId:p,expiresAt:l}=ie(t),{idpId:m,redirectTo:h}=JSON.parse(f);if(!c){const o="SAML2 assertion is not successful";return r.error(`SAML2 login error: ${o}`),e.text(`Permission denied: ${o}`,401)}if(!l||Math.ceil(Date.now()/1e3)>=l){const o="SAML2 Token Expired";return r.error(`SAML2 login error: ${o}`),e.text(o,401)}const g=i.getConfig().ssoDirect?.[m];if(!g||!ee(g)){const o="Cannot find valid IdP";return r.error(`SAML2 login error: ${o}`),e.text(`Permission denied: ${o}`,401)}if(!(g.issuerId&&p&&Y(g.issuerId,p))){const o="IssuerID is misconfigured or untrusted assertions issuer received";return r.error(`SAML2 login error: ${o}`),e.text(`Permission denied: ${o}`,401)}if(!await ae(t,g.x509PublicCert)){const o="SAMLResponse signature invalid";return r.error(`SAML2 login error: ${o}`),e.text(o,401)}const C=te(s,d,y,g.teamsAttributeName);if(!C.sub){const o="The provider did not return a valid user identity.";return r.error(`SAML2 login error: ${o}`),e.text(o,400)}if(!C.email){const o="The provider did not return a valid user email.";return r.error(`SAML2 login error: ${o}`),e.text(o,400)}const u=await O.sign({...C,idpId:m},v,P.HS256);return _(e,"authorization",u,{path:R()||"/",httpOnly:!0,expires:new Date(l*1e3)}),r.updateContext({email:C.email,subject:C.sub}),r.info("SAML2 login successful"),e.newResponse(null,302,{Location:h||"/"})}}function Be(i){return async e=>{const r=e.get("logger"),a=new URL(e.req.query("redirectTo")||"/",e.req.url),n=I(z(a.pathname)),f=i.getConfig().ssoDirect,t=Object.entries(f||{}).find(([,h])=>$(h)&&ue(h));if(!(f&&t))return e.newResponse(null,302,{Location:n});const s=e.req.query("token"),d=s&&await le(s);if(!d)return e.newResponse(null,302,{Location:n});if(!b(d[F]||[]).some(h=>h===Q||h===Z))return e.newResponse(null,302,{Location:n});const l=await O.sign({...d,idpId:t?.at(0)},v,P.HS256),m=Date.now()+B*1e3;return _(e,"authorization",l,{path:R()||"/",httpOnly:!0,expires:new Date(m),sameSite:"None",secure:!0}),r.info("Token login successful"),e.newResponse(null,302,{Location:n})}}export{ve as authorizeHandler,Ee as idpLoginHandler,be as inviteHandler,Te as logoutHandler,Ue as oidcCallbackHandler,qe as postLogoutHandler,$e as redoclyLoginCallbackHandler,Be as redoclyTokenLoginHandler,Fe as samlCallbackHandler};
1
+ import{setCookie as _,deleteCookie as q}from"hono/cookie";import{AuthProviderType as W}from"@redocly/config";import{withPathPrefix as I,getPathPrefix as R}from"@redocly/theme/core/utils";import{compareURIs as Y}from"../../../utils/url/compare-uris.js";import{ensureArray as b}from"../../../utils/array/ensure-array.js";import{ALTERNATIVE_AUD_CLAIM_NAME as F,JWT_SECRET_KEY as v,ORG_SLUG as Q,ORG_ID as Z}from"../../constants/common.js";import{DEFAULT_COOKIE_EXPIRATION as B,ServerRoutes as S}from"../../../constants/common.js";import{sanitizeRedirectPathname as z}from"../../../utils/url/sanitize-redirect-pathname.js";import{telemetry as M}from"../../telemetry/index.js";import{envConfig as H}from"../../config/env-config.js";import{getAuthProviderLoginParams as x,isOidcProviderConfig as $,isSaml2ProviderConfig as ee,oidcExchangeCodeForToken as re,buildLoginUrl as oe,decodeSamlResponse as ne,extractUserClaims as te,parseSamlResponse as ie,parseOidcState as se,verifySAMLResponse as ae,getUsernameFromPayload as de,buildOidcLogoutUrl as ce,getOidcMetadata as j,getRedoclyTokenPayload as le,isRedoclySso as ue,rewritePreviewAuthRedirectUri as pe,parsePreviewBranch as N,buildOidcLoginUrl as ge,createMcpSessionResource as k}from"../auth.js";import*as O from"../jwt/jwt.js";import{AlgorithmTypes as P}from"../jwt/types.js";import{handleErrorPageRender as fe}from"../utils.js";import{encodeBase64URL as me}from"../jwt/encode.js";async function ve(i){if(H.isProductionEnv)return i.newResponse(null,404,{});const{password:e,...r}=await i.req.json(),a=await O.sign({...r,name:r.username||r.email||"Unknown"},v,P.HS256);return _(i,"authorization",a,{path:R()||"/",httpOnly:!0,secure:!0,sameSite:"none"}),i.newResponse(null,200,{})}function $e(){return async i=>{const e=i.get("logger"),r=encodeURIComponent(i.req.query("message")||"");e.error(`Login error: ${r}`);const a=`${S.LOGIN}/?error=${encodeURIComponent(r)}`;return i.newResponse(null,301,{Location:a})}}function K(i){if(!i||!i.includes(S.MCP_CALLBACK))return null;try{const e=i.split("/"),r=e[e.length-1];if(r){const a=Buffer.from(r,"base64url").toString("utf-8");return JSON.parse(a).mcpSessionId||null}}catch{}return null}function Ue(i){return async e=>{const r=e.get("logger"),a=i.getConfig().ssoDirect,n=se(e.req.query("state")),f=n.idpId,t=n.source==="mcp"||n.redirectTo&&typeof n.redirectTo=="string"&&n.redirectTo.includes(S.MCP_CALLBACK),c=t?K(typeof n.redirectTo=="string"?n.redirectTo:void 0):null,s=a?.[f];if(!$(s))return r.error("OIDC login error: missing OIDC provider config"),e.text("Forbidden",403);const d=await j(f,s);if(a&&!d.token_endpoint){const p="Invalid OIDC configuration: token_endpoint is required";return r.error(`OIDC login error: ${p}`),e.text(p,500)}try{const p=d.token_endpoint,l=e.req.query("code"),m=e.req.query("error");if(m)return t&&M.sendMcpAuthorizationFailedMessage([{...k(c),error:`OIDC error: ${m}`,error_details:e.req.query("error_description")||null}]),fe(e,i,{slug:"/"},403,"403OIDC");if(!l){const w="Code is expected but not present";return r.error(`OIDC login error: ${w}`),t&&M.sendMcpAuthorizationFailedMessage([{...k(c),error:w,error_details:null}]),new Response(`Forbidden: ${w}`,{status:403})}const h=e.req.header("x-forwarded-host"),g=e.req.header("x-forwarded-proto")||"https",A=t&&typeof n.redirectUri=="string"?n.redirectUri:new URL(I(S.OIDC_CALLBACK),h?`${g}://${h}`:e.req.url).toString(),C=e.get("cookies")?.code_verifier,u=await re(p,l,A,s,{...s.tokenRequestCustomParams,...C?{code_verifier:C}:{}});if(u.error)return r.error(`Error from OIDC provider: "${u.error}"`),t&&M.sendMcpAuthorizationFailedMessage([{...k(c),error:`Token exchange error: ${u.error}`,error_details:u.error_description||null}]),e.text(`Forbidden: ${u.error_description||u.error}`,403);if(!u?.id_token){const w="No id_token, please, add openid to scopes";return r.error(`OIDC login error: ${w}`),t&&M.sendMcpAuthorizationFailedMessage([{...k(c),error:w,error_details:null}]),new Response(`Forbidden: ${w}`,{status:403})}const{payload:o,header:U}=O.decode(u.id_token),J=U.alg===P.RS256;if(s.audience?.length&&![...b(o.aud||[]),...b(o[F]||[])].some(L=>s.audience?.includes(L))){const L="No valid audience found in id_token";return r.error(`OIDC login error: ${L}`),t&&M.sendMcpAuthorizationFailedMessage([{...k(c),error:L,error_details:null}]),new Response(`Forbidden: ${L}`)}const E=J?u.id_token:await O.sign({...o,idpId:f},v,P.HS256);de(o)||r.warn("To display your username, the required 'email' or 'full_profile' scope must be added to the identity provider configuration");const D=s?.tokenExpirationTime?Date.now()+s.tokenExpirationTime*1e3:o.exp*1e3||Date.now()+B*1e3;if(s.introspectEndpoint){const w=await fetch(s.introspectEndpoint,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({access_token:u.access_token})});if(w.ok){const T=(await w.json()).ext?.federatedIdentity;T&&(_(e,"federated_access_token",T.access_token||"",{path:R()||"/",httpOnly:!1,expires:new Date(D)}),_(e,"federated_id_token",T.id_token||"",{path:R()||"/",httpOnly:!1,expires:new Date(D)}))}else r.warn(`OIDC introspect error: ${w.statusText}`)}if(_(e,"authorization",E,{path:R()||"/",httpOnly:!0,expires:new Date(D)}),E!==u.id_token&&_(e,"idp_id_token",u.id_token||"",{path:R()||"/",httpOnly:!0,expires:new Date(D)}),_(e,"idp_access_token",u.access_token||"",{path:R()||"/",httpOnly:!0,expires:new Date(D)}),q(e,"code_verifier",{path:R()||"/"}),t&&n.redirectTo&&typeof n.redirectTo=="string"&&n.redirectTo.includes(S.MCP_CALLBACK)){const L=`${e.req.url.split("?")[0].replace(S.OIDC_CALLBACK,"")}${n.redirectTo}`;return e.newResponse(null,302,{Location:L})}const G=typeof n.redirectTo=="string"?n.redirectTo:void 0;let V=z(new URL(G||"/",e.req.url).pathname);const X=e.newResponse(null,302,{Location:V});return r.updateContext({email:o.email,subject:o.sub}),r.info("OIDC login successful"),X}catch(p){const l=p instanceof Error?p.message:String(p),m=p instanceof Error?p.stack:String(p);if(r.error(`OIDC login error: ${l}`),t&&M.sendMcpAuthorizationFailedMessage([{...k(c),error:l,error_details:m}]),p.error==="access_denied")return r.info("Access denied"),e.text("Forbidden",403)}const y="Something went wrong";return r.error(`OIDC login error: ${y}`),t&&M.sendMcpAuthorizationFailedMessage([{...k(c),error:y,error_details:null}]),e.text(y,500)}}function Te(i){return async e=>{const r=e.get("logger"),n=e.get("auth").claims?.idpId,t=i.getConfig().ssoDirect?.[n];if(e.req.method==="POST")return $(t)||q(e,"authorization",{path:R()||"/"}),r.info("Logout successful"),e.newResponse(null,200,{});let c;if($(t)){const s=(await j(n,t)).end_session_endpoint;if(s){const d=new URL(e.req.url),y=e.req.header("x-forwarded-proto")||d.protocol.slice(0,-1)||"https",p=e.req.header("x-forwarded-host")||d.host,l=`${y}://${p}`,m=N(l),h=m?me(JSON.stringify({branch:N(l)})):void 0,g=m?`${pe(l)}/_auth/logout`:`${l}/post-logout`;c=ce(s,g,e.get("cookies")?.idp_id_token||e.get("cookies")?.authorization||"",h)}}return r.info("Logout successful"),q(e,"authorization",{path:R()||"/"}),e.newResponse(null,302,{Location:c||I("/")})}}function qe(i){return async e=>{const r=i.getConfig().access?.logoutReturnUrl,a=r||I("/");return e.newResponse(null,302,{Location:a})}}function be(i){return async e=>{const r=e.get("logger"),a=e.req.param("code"),n=H.BH_API_URL,f=(t,c,s)=>t&&c?`${t} ${c.charAt(0)}`:s;try{if(!n)throw new Error("BH_API_URL is not set");const t=i.getConfig().ssoDirect;if(!t||!Object.keys(t).length)return r.warn("Invite no sso configured to handle"),e.redirect(I("/"));const c=await fetch(`${n}/user-invites/public/${a}`);if(!c.ok)return c.status===404?(r.warn(`Invite ${a} not found redirect to homepage`),e.redirect(I("/"))):(r.error("Invite error",await c.text()),e.redirect(I("/")));const s=await c.json(),d=new URL(I("/invite"),e.req.url);return d.searchParams.set("code",a),d.searchParams.set("org",s.organization.name),d.searchParams.set("invitedBy",f(s.invitedBy.firstName,s.invitedBy.lastName,s.invitedBy.name)),e.newResponse(null,302,{Location:d.toString()})}catch(t){return r.error("Error processing invite",{error:t,inviteCode:a}),e.text(t.message||"Failed to process invite",400)}}}function Ee(i){return async e=>{const r=e.get("logger"),a=i.getConfig().ssoDirect,n=new URL(e.req.url),f=e.req.query("inviteCode"),t=e.req.header("x-forwarded-proto")||n.protocol.slice(0,-1)||"https",c=e.req.header("x-forwarded-host")||n.host,s=`${t}://${c}`;let d=n.searchParams.get("idpId");const y=n.searchParams.get("redirectTo"),p=Object.keys(a||{})[0];d=d||p;const l=n.searchParams.get("mcp_redirect_uri"),m=!!l;if(!a?.[d]){const o="Invalid idpId";if(r.error(`IdP login error: ${o}`),m){const U=K(y||void 0);M.sendMcpAuthorizationFailedMessage([{...k(U),error:o,error_details:null}])}return e.text(`Forbidden: ${o}`,403)}const g=d&&a?await x(d,a[d]):void 0,A={};for(const o of Object.keys(g?.extraParams||{}))A[o]=n.searchParams.get(o)||g?.extraParams?.[o]||void 0;let C,u={};if(m&&l&&g&&g.type===W.OIDC){r.info(`Building MCP OAuth login URL with redirect_uri: ${l}`);const o=ge("",{...g,extraParams:A},y,f,{redirectUriOverride:l,sourceOverride:"mcp",branchOverride:void 0});C=o.loginUrl,u=o.cookies||{}}else if(g){const o=oe({...g,extraParams:A},s,y,f);C=o.loginUrl,u=o.cookies||{}}return Object.keys(u).forEach(o=>{_(e,o,u[o].value,u[o].options)}),r.info(`IdP login initiated for ID '${d}'`),e.newResponse(null,302,{Location:C||new URL(e.req.url).pathname})}}function Fe(i){return async e=>{const r=e.get("logger"),a=await e.req.formData(),n=a.get("SAMLResponse"),f=a.get("RelayState");if(typeof n!="string"||typeof f!="string"){const o="SAMLResponse is required";return r.error(`SAML2 login error: ${o}`),e.text(`Bad request: ${o}`,400)}const t=ne(n),{success:c,uid:s,nameFormat:d,attrs:y,issuerId:p,expiresAt:l}=ie(t),{idpId:m,redirectTo:h}=JSON.parse(f);if(!c){const o="SAML2 assertion is not successful";return r.error(`SAML2 login error: ${o}`),e.text(`Permission denied: ${o}`,401)}if(!l||Math.ceil(Date.now()/1e3)>=l){const o="SAML2 Token Expired";return r.error(`SAML2 login error: ${o}`),e.text(o,401)}const g=i.getConfig().ssoDirect?.[m];if(!g||!ee(g)){const o="Cannot find valid IdP";return r.error(`SAML2 login error: ${o}`),e.text(`Permission denied: ${o}`,401)}if(!(g.issuerId&&p&&Y(g.issuerId,p))){const o="IssuerID is misconfigured or untrusted assertions issuer received";return r.error(`SAML2 login error: ${o}`),e.text(`Permission denied: ${o}`,401)}if(!await ae(t,g.x509PublicCert)){const o="SAMLResponse signature invalid";return r.error(`SAML2 login error: ${o}`),e.text(o,401)}const C=te(s,d,y,g.teamsAttributeName);if(!C.sub){const o="The provider did not return a valid user identity.";return r.error(`SAML2 login error: ${o}`),e.text(o,400)}if(!C.email){const o="The provider did not return a valid user email.";return r.error(`SAML2 login error: ${o}`),e.text(o,400)}const u=await O.sign({...C,idpId:m},v,P.HS256);return _(e,"authorization",u,{path:R()||"/",httpOnly:!0,expires:new Date(l*1e3)}),r.updateContext({email:C.email,subject:C.sub}),r.info("SAML2 login successful"),e.newResponse(null,302,{Location:h||"/"})}}function Be(i){return async e=>{const r=e.get("logger"),a=new URL(e.req.query("redirectTo")||"/",e.req.url),n=I(z(a.pathname)),f=i.getConfig().ssoDirect,t=Object.entries(f||{}).find(([,h])=>$(h)&&ue(h));if(!(f&&t))return e.newResponse(null,302,{Location:n});const s=e.req.query("token"),d=s&&await le(s);if(!d)return e.newResponse(null,302,{Location:n});if(!b(d[F]||[]).some(h=>h===Q||h===Z))return e.newResponse(null,302,{Location:n});const l=await O.sign({...d,idpId:t?.at(0)},v,P.HS256),m=Date.now()+B*1e3;return _(e,"authorization",l,{path:R()||"/",httpOnly:!0,expires:new Date(m),sameSite:"None",secure:!0}),r.info("Token login successful"),e.newResponse(null,302,{Location:n})}}export{ve as authorizeHandler,Ee as idpLoginHandler,be as inviteHandler,Te as logoutHandler,Ue as oidcCallbackHandler,qe as postLogoutHandler,$e as redoclyLoginCallbackHandler,Be as redoclyTokenLoginHandler,Fe as samlCallbackHandler};
@@ -1 +1 @@
1
- import{telemetryTraceStep as o}from"../../../telemetry/helpers/trace-step.js";import{CATALOG_ENTITY_KEY as d}from"../../../../constants/common.js";import{ALLOWED_CATALOG_QUERY_PARAMS as y}from"../../../constants/plugins/catalog-entities.js";import{allowlistObject as g}from"../../../../utils/object/allowlist-object.js";import{CatalogEntitiesService as f}from"../../../plugins/catalog-entities/database/catalog-entities-service.js";import{createPaginationParamsValidator as E}from"../../../providers/database/pagination/schemas.js";import{ENTITY_RELATION_FROM_DATABASE as A}from"../../../plugins/catalog-entities/database/mappers/field-transformations.js";import{getRbacRestrictionsDataForCatalog as b}from"../helpers/get-rbac-restrictions-data-for-catalog.js";const _=["id","key","title","type","summary","source","sourceFile","createdAt","updatedAt","version","revision"],p=async({catalogEntitiesService:i,store:a,ctx:e})=>o("catalog_entities.bff.related_entities.get_related_entities",async t=>{try{const r=e.req.param(d);if(!r)return t?.error(new Error("Entity key is required")),e.json({message:"Entity key is required"},400);t?.setAttribute("pathParams",JSON.stringify({entityKey:r}));const s=e.req.query();t?.setAttribute("queryParams",JSON.stringify(g(s,y)));const m=E(_,A).parse(s),{currentRbacTeamsForRead:l,excludedTypes:c,excludedEntities:u}=b({store:a,ctx:e}),n=await i.getRelatedEntities({entityKey:r,paginationParams:m,rbacTeams:l,excludedTypes:c,excludedEntities:u});return t?.setAttribute("relatedEntitiesCount",n.items.length),e.json(n)}catch(r){return console.error(r),t?.error(r),e.json({message:r.message},500)}});function v(i){return async a=>o("catalog_entities.bff.related_entities",async e=>{e?.setAttribute("method",a.req.method);const t=await f.getInstance({baseDbDir:i.serverOutDir});return p({catalogEntitiesService:t,ctx:a,store:i})})}export{v as bffCatalogRelatedEntitiesHandler};
1
+ import{telemetryTraceStep as o}from"../../../telemetry/helpers/trace-step.js";import{CATALOG_ENTITY_KEY as d}from"../../../../constants/common.js";import{ALLOWED_CATALOG_QUERY_PARAMS as y}from"../../../constants/plugins/catalog-entities.js";import{allowlistObject as f}from"../../../../utils/object/allowlist-object.js";import{CatalogEntitiesService as g}from"../../../plugins/catalog-entities/database/catalog-entities-service.js";import{createPaginationParamsValidator as E}from"../../../providers/database/pagination/schemas.js";import{ENTITY_RELATION_TO_DATABASE as _}from"../../../plugins/catalog-entities/database/mappers/field-transformations.js";import{getRbacRestrictionsDataForCatalog as A}from"../helpers/get-rbac-restrictions-data-for-catalog.js";const b=["id","key","title","type","summary","source","source_file","created_at","updated_at","relation_type","version","revision"],p=async({catalogEntitiesService:i,store:a,ctx:e})=>o("catalog_entities.bff.related_entities.get_related_entities",async t=>{try{const r=e.req.param(d);if(!r)return t?.error(new Error("Entity key is required")),e.json({message:"Entity key is required"},400);t?.setAttribute("pathParams",JSON.stringify({entityKey:r}));const s=e.req.query();t?.setAttribute("queryParams",JSON.stringify(f(s,y)));const m=E(b,_).parse(s),{currentRbacTeamsForRead:l,excludedTypes:c,excludedEntities:u}=A({store:a,ctx:e}),n=await i.getRelatedEntities({entityKey:r,paginationParams:m,rbacTeams:l,excludedTypes:c,excludedEntities:u});return t?.setAttribute("relatedEntitiesCount",n.items.length),e.json(n)}catch(r){return console.error(r),t?.error(r),e.json({message:r.message},500)}});function v(i){return async a=>o("catalog_entities.bff.related_entities",async e=>{e?.setAttribute("method",a.req.method);const t=await g.getInstance({baseDbDir:i.serverOutDir});return p({catalogEntitiesService:t,ctx:a,store:i})})}export{v as bffCatalogRelatedEntitiesHandler};